snowe
12/19/2023, 11:52 PM.asResult
in your lens? i.e.
val ssmResponse = Body.auto<SSMObject>().toLens().asResult()
return ssmResponse(client(request))
.map {
println("SSM call was successful, returning the client token decrypted hopefully")
it.parameter.value
}
.mapFailure {
throw IllegalStateException(
"unable to find the client secret $clientSecretParameterUrl: $it" // i need access to the bodyString() here
)
}.get()
snowe
12/20/2023, 1:25 AMAndrew O'Hara
12/20/2023, 3:24 PMsnowe
12/21/2023, 9:25 PMAWS Parameters and Secrets Lambda Extension
, rather than SSM directly, for faster response and caching. I do have to call ssm to put some data, but I’m using quarkiverse’s SSM service, which autowires all the credentials automatically so I don’t have to actually configure anything. It would be nice to keep the binary size low, but not sure the tradeoffs are worth it.Andrew O'Hara
12/22/2023, 2:08 AMsnowe
12/22/2023, 9:15 PMsnowe
12/22/2023, 9:16 PMdave
12/22/2023, 10:26 PMdave
12/22/2023, 10:26 PMsnowe
12/22/2023, 10:26 PMdave
12/22/2023, 10:26 PMsnowe
12/22/2023, 10:27 PMdave
12/22/2023, 10:27 PMdave
12/22/2023, 10:27 PMsnowe
12/22/2023, 10:27 PMdave
12/22/2023, 10:28 PMsnowe
12/22/2023, 10:28 PMdave
12/22/2023, 10:29 PMdave
12/22/2023, 10:29 PMsnowe
12/22/2023, 10:30 PMdave
12/22/2023, 10:32 PMsnowe
12/22/2023, 10:34 PMsnowe
12/22/2023, 11:29 PMAndrew O'Hara
12/23/2023, 1:17 AMdave
12/23/2023, 5:34 AMsnowe
12/27/2023, 5:00 PMHow are you running your lambdas? If they are all in memory in a single process then this should be trivial to get them to use the same in memory version. It’s all about having everything in a single test env.so running in aws is fine, all the http4k stuff works great, saves to ssm, works perfectly. It’s when I’m trying to test with quarkus tests that it’s a problem. So I autowire a fake using something like this:
@Dependent
class HttpConfig {
@Produces
@IfBuildProfile(anyOf = ["test", "dev"])
fun ssmClient(): SystemsManager {
val http = FakeSystemsManager()
return SystemsManager.Http(Region.of("us-east-1"), { AwsCredentials("test", "test") }, http.debug())
}
@Produces
@DefaultBean
fun prodSsmClient(): SystemsManager {
val http = JavaHttpClient()
return SystemsManager.Http(Region.of("us-east-1"), { AwsCredentials("test", "test") }, http.debug())
}
}
(haven’t actually tested that the prod bean works yet)
then my test is a quarkustest so it starts the quarkus application (i’m pretty sure in a separate thread… not quite sure how all the underlying quarkus stuff runs), and hits the running application from a restassured call.
@QuarkusTest
@TestProfile(UpdateTokenHandlerProfile::class)
open class UpdateServiceAuthTokenLambdaTest {
@Inject
lateinit var ssmClient: SystemsManager
@Test
@Throws(Exception::class)
fun `test auth token saved to SSM`() {
RestAssured.given()
.contentType("application/json")
.accept("application/json")
.`when`()
.post()
.then()
.statusCode(200)
.body(CoreMatchers.containsString("""success":true"""))
val authToken = ssmClient.getParameter(SSMParameterName.of(authTokenPath),true).valueOrNull()
expectThat(authToken)
.isNotNull()
.get(ParameterValue::Parameter)
.get(Parameter::Value)
.isA<String>()
.isNotBlank()
.isNotEmpty()
}
}
dave
12/27/2023, 5:06 PMFakeSystemsManager().start()
in your test and it will start on the default port. Then you'd use the JavaHttpClient as usual.
If you're missing data between the tests then I suspect that your magic wiring (this is why we hate magic!) is maybe creating multiple copies of the FakeSystemsManager and so you're getting a different one for each test? The storage could help here, but it's all the same thing - you need to get a single instance of either if you want to keep it in memory, or to just use a networked version. - there are storage implementations for. Redis, S3, File etc... see: https://github.com/http4k/http4k-connect?tab=readme-ov-file#supported-storage-backends-named-http4k-connect-storage-technology)dave
12/27/2023, 5:07 PMdave
12/27/2023, 5:07 PMsnowe
12/27/2023, 5:08 PMdave
12/27/2023, 5:08 PMsnowe
12/27/2023, 5:08 PMsnowe
12/27/2023, 5:08 PMsnowe
12/27/2023, 5:09 PMdave
12/27/2023, 5:09 PMsnowe
12/27/2023, 5:09 PMdave
12/27/2023, 5:09 PMsnowe
12/27/2023, 5:10 PMdave
12/27/2023, 5:10 PMdave
12/27/2023, 5:10 PMdave
12/27/2023, 5:11 PMdave
12/27/2023, 5:12 PMSetBaseUriFrom(apiUrl).then(FakeSystemsManager())
dave
12/27/2023, 5:13 PMsnowe
12/27/2023, 5:14 PMdave
12/27/2023, 5:14 PMdave
12/27/2023, 5:15 PMsnowe
12/27/2023, 5:15 PMdave
12/27/2023, 5:15 PMfun main() {
SetBaseUriFrom(Uri.of("<http://github.com>")).then(JavaHttpClient()).asServer(SunHttp(8080)).start()
}
dave
12/27/2023, 5:15 PMsnowe
12/27/2023, 5:15 PMdave
12/27/2023, 5:16 PMsnowe
12/27/2023, 5:16 PMsnowe
12/27/2023, 6:15 PM@Singleton
and everything just works 🤦🏽♂️dave
12/27/2023, 6:30 PMdave
12/27/2023, 6:31 PMdave
12/27/2023, 6:31 PMdave
12/27/2023, 6:31 PMsnowe
12/27/2023, 6:39 PMdave
12/27/2023, 7:18 PMsnowe
12/28/2023, 12:44 AM@Test
fun `test 1`() {
ssmManager.putParameter(
SSMParameterName.of("abc"), "123", ParameterType.SecureString,
Overwrite = true,
KeyId = KMSKeyId.parse("alias/aws/ssm")
)
}
@Test
fun `test 2`() {
ssmManager.putParameter(
SSMParameterName.of("abc"), "123", ParameterType.SecureString,
Overwrite = true,
KeyId = KMSKeyId.parse("alias/aws/ssm")
)
}
note it’s the exact same test copied and pasted, but the first test succeeds at saving the parameter, the second fails:
***** REQUEST: POST: <https://ssm.us-east-1.amazonaws.com/> *****
POST <https://ssm.us-east-1.amazonaws.com/> HTTP/1.1
X-Amz-Target: AmazonSSM.PutParameter
Content-Type: application/x-amz-json-1.1
X-Forwarded-Host: <http://ssm.us-east-1.amazonaws.com|ssm.us-east-1.amazonaws.com>
host: <http://ssm.us-east-1.amazonaws.com|ssm.us-east-1.amazonaws.com>
x-amz-content-sha256: dd07741b6cfd5f48da0c8fdb657445b84d80765e1216449f2bc5250c3e09b45e
x-amz-date: 20231228T004328Z
content-length: 91
Authorization: AWS4-HMAC-SHA256 Credential=test/20231228/us-east-1/ssm/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target;x-forwarded-host, Signature=a3d3818e6a439dd402c46a31382092351324e6257e63955a8e36d4be08026a77
{"Name":"abc","Value":"123","Type":"SecureString","KeyId":"alias/aws/ssm","Overwrite":true}
***** RESPONSE 200 to POST: <https://ssm.us-east-1.amazonaws.com/> *****
HTTP/1.1 200 OK
{"Tier":"Standard","Version":1}
***** REQUEST: POST: <https://ssm.us-east-1.amazonaws.com/> *****
POST <https://ssm.us-east-1.amazonaws.com/> HTTP/1.1
X-Amz-Target: AmazonSSM.PutParameter
Content-Type: application/x-amz-json-1.1
X-Forwarded-Host: <http://ssm.us-east-1.amazonaws.com|ssm.us-east-1.amazonaws.com>
host: <http://ssm.us-east-1.amazonaws.com|ssm.us-east-1.amazonaws.com>
x-amz-content-sha256: dd07741b6cfd5f48da0c8fdb657445b84d80765e1216449f2bc5250c3e09b45e
x-amz-date: 20231228T004328Z
content-length: 91
Authorization: AWS4-HMAC-SHA256 Credential=test/20231228/us-east-1/ssm/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target;x-forwarded-host, Signature=a3d3818e6a439dd402c46a31382092351324e6257e63955a8e36d4be08026a77
{"Name":"abc","Value":"123","Type":"SecureString","KeyId":"alias/aws/ssm","Overwrite":true}
***** RESPONSE 400 to POST: <https://ssm.us-east-1.amazonaws.com/> *****
HTTP/1.1 400 Bad Request
{"__type":"ResourceNotFoundException","Message":"AmazonSSM can't find the specified item."}
dave
12/28/2023, 6:37 AMdave
12/28/2023, 7:01 AMsnowe
12/28/2023, 5:31 PMdave
12/28/2023, 5:32 PM