/** * Forces the lambda to run and sync the IPs for CloudFront to be white listed on the origin elb */ private void forceLambdaToUpdateSgs(String arn) { String json; try { json = IOUtils.toString(this.getClass().getClassLoader().getResourceAsStream("aws-ip-space-change-sns-sample-event.json")); } catch (IOException e) { String msg = "Failed to load mock sns message, to force Lambda first run"; logger.error(msg, e); throw new RuntimeException(msg, e); } // this will fail InvokeResult result = awsLambda.invoke(new InvokeRequest().withFunctionName(arn).withPayload(String.format(json, BAD_HASH)).withLogType(LogType.Tail)); // collect the error so we can parse it for the latest hash String log = new String(Base64.getDecoder().decode(result.getLogResult()), Charset.forName("UTF-8")); Pattern pattern = Pattern.compile("MD5 Mismatch: got\\s(.*?)\\sexp.*?"); Matcher matcher = pattern.matcher(log); boolean matched = matcher.find(); if (! matched) { throw new RuntimeException("failed to extract hash from: " + log); } String realHash = matcher.group(1); result = awsLambda.invoke(new InvokeRequest().withFunctionName(arn).withPayload(String.format(json, realHash)).withLogType(LogType.Tail)); logger.info("Forcing the Lambda to run and update Security Groups"); logger.info(new String(result.getPayload().array(), Charset.forName("UTF-8"))); }
/** * Synchronously or asynchronously invokes an AWS Lambda function. * If synchronously invoked, the AWS Lambda log is collected and the response payload is returned * @param invokeConfig AWS Lambda invocation configuration * @return response payload */ public String invokeLambdaFunction(InvokeConfig invokeConfig) throws LambdaInvokeException { InvokeRequest invokeRequest = new InvokeRequest() .withFunctionName(invokeConfig.getFunctionName()) .withPayload(invokeConfig.getPayload()); if(invokeConfig.isSynchronous()){ invokeRequest .withInvocationType(InvocationType.RequestResponse) .withLogType(LogType.Tail); } else { invokeRequest .withInvocationType(InvocationType.Event); } logger.log("Lambda invoke request:%n%s%nPayload:%n%s%n", invokeRequest.toString(), invokeConfig.getPayload()); InvokeResult invokeResult = client.invoke(invokeRequest); String payload = ""; if(invokeResult.getPayload() != null){ payload = new String(invokeResult.getPayload().array(), Charset.forName("UTF-8")); } logger.log("Lambda invoke response:%n%s%nPayload:%n%s%n", invokeResult.toString(), payload); if(invokeResult.getLogResult() != null){ logger.log("Log:%n%s%n", new String(Base64.decode(invokeResult.getLogResult()), Charset.forName("UTF-8"))); } if(StringUtils.isNotEmpty(invokeResult.getFunctionError())){ throw new LambdaInvokeException("Function returned error of type: " + invokeResult.getFunctionError()); } return payload; }
@Test public void testInvokeLambdaFunctionSynchronous() throws Exception { final String logBase64 = "bGFtYmRh"; final String log = "lambda"; final String requestPayload = "{\"key1\": \"value1\"}"; final String responsePayload = "{\"key2\": \"value2\"}"; InvokeConfig invokeConfig = new InvokeConfig("function", requestPayload, true, null); InvokeResult invokeResult = new InvokeResult() .withLogResult(logBase64) .withPayload(ByteBuffer.wrap(responsePayload.getBytes())); when(awsLambdaClient.invoke(any(InvokeRequest.class))) .thenReturn(invokeResult); String result = lambdaInvokeService.invokeLambdaFunction(invokeConfig); verify(awsLambdaClient, times(1)).invoke(invokeRequestArg.capture()); InvokeRequest invokeRequest = invokeRequestArg.getValue(); assertEquals("function", invokeRequest.getFunctionName()); assertEquals(LogType.Tail.toString(), invokeRequest.getLogType()); assertEquals(requestPayload, new String(invokeRequest.getPayload().array(), Charset.forName("UTF-8"))); assertEquals(InvocationType.RequestResponse.toString(), invokeRequest.getInvocationType()); ArgumentCaptor<String> stringArgs = ArgumentCaptor.forClass(String.class); verify(jenkinsLogger).log(eq("Lambda invoke request:%n%s%nPayload:%n%s%n"), stringArgs.capture()); List<String> stringArgValues = stringArgs.getAllValues(); assertEquals(Arrays.asList(invokeRequest.toString(), requestPayload), stringArgValues); verify(jenkinsLogger).log(eq("Log:%n%s%n"), eq(log)); stringArgs = ArgumentCaptor.forClass(String.class); verify(jenkinsLogger).log(eq("Lambda invoke response:%n%s%nPayload:%n%s%n"), stringArgs.capture()); stringArgValues = stringArgs.getAllValues(); assertEquals(Arrays.asList(invokeResult.toString(), responsePayload), stringArgValues); assertEquals(responsePayload, result); }
/** * Executes a lambda function and returns the result of the execution. */ @Override public cfData execute( cfSession _session, cfArgStructData argStruct ) throws cfmRunTimeException { AmazonKey amazonKey = getAmazonKey( _session, argStruct ); // Arguments to extract String payload = getNamedStringParam( argStruct, "payload", null ); String functionName = getNamedStringParam( argStruct, "function", null ); String qualifier = getNamedStringParam( argStruct, "qualifier", null ); try { // Construct the Lambda Client InvokeRequest invokeRequest = new InvokeRequest(); invokeRequest.setInvocationType( InvocationType.Event ); invokeRequest.setLogType( LogType.Tail ); invokeRequest.setFunctionName( functionName ); invokeRequest.setPayload( payload ); if ( qualifier != null ) { invokeRequest.setQualifier( qualifier ); } // Lambda client must be created with credentials BasicAWSCredentials awsCreds = new BasicAWSCredentials( amazonKey.getKey(), amazonKey.getSecret() ); AWSLambda awsLambda = AWSLambdaClientBuilder.standard() .withRegion( amazonKey.getAmazonRegion().toAWSRegion().getName() ) .withCredentials( new AWSStaticCredentialsProvider( awsCreds ) ).build(); // Execute awsLambda.invoke( invokeRequest ); } catch ( Exception e ) { throwException( _session, "AmazonLambdaAsyncExecute: " + e.getMessage() ); return cfBooleanData.FALSE; } return cfBooleanData.TRUE; }
@LambdaFunction(functionName="account-activated", logType = LogType.Tail) Account accountActivated(AccountEvent event);
@LambdaFunction(functionName="account-suspended", logType = LogType.Tail) Account accountSuspended(AccountEvent event);
@LambdaFunction(functionName="commit-metrics", logType = LogType.Tail) Map<String, Object> tightCouplingQuery(Map event);
@Test public void testInvokeLambdaFunctionSynchronousError() throws Exception { final String logBase64 = "bGFtYmRh"; final String log = "lambda"; final String requestPayload = "{\"key1\": \"value1\"}"; final String responsePayload = "{\"errorMessage\":\"event_fail\"}"; InvokeConfig invokeConfig = new InvokeConfig("function", requestPayload, true, null); InvokeResult invokeResult = new InvokeResult() .withLogResult(logBase64) .withPayload(ByteBuffer.wrap(responsePayload.getBytes())) .withFunctionError("Unhandled"); when(awsLambdaClient.invoke(any(InvokeRequest.class))) .thenReturn(invokeResult); try { lambdaInvokeService.invokeLambdaFunction(invokeConfig); fail("Should fail with LambdaInvokeException"); } catch (LambdaInvokeException lie){ assertEquals("Function returned error of type: Unhandled", lie.getMessage()); } verify(awsLambdaClient, times(1)).invoke(invokeRequestArg.capture()); InvokeRequest invokeRequest = invokeRequestArg.getValue(); assertEquals("function", invokeRequest.getFunctionName()); assertEquals(LogType.Tail.toString(), invokeRequest.getLogType()); assertEquals(requestPayload, new String(invokeRequest.getPayload().array(), Charset.forName("UTF-8"))); assertEquals(InvocationType.RequestResponse.toString(), invokeRequest.getInvocationType()); ArgumentCaptor<String> stringArgs = ArgumentCaptor.forClass(String.class); verify(jenkinsLogger).log(eq("Lambda invoke request:%n%s%nPayload:%n%s%n"), stringArgs.capture()); List<String> stringArgValues = stringArgs.getAllValues(); assertEquals(Arrays.asList(invokeRequest.toString(), requestPayload), stringArgValues); verify(jenkinsLogger).log(eq("Log:%n%s%n"), eq(log)); stringArgs = ArgumentCaptor.forClass(String.class); verify(jenkinsLogger).log(eq("Lambda invoke response:%n%s%nPayload:%n%s%n"), stringArgs.capture()); stringArgValues = stringArgs.getAllValues(); assertEquals(Arrays.asList(invokeResult.toString(), responsePayload), stringArgValues); }
@LambdaFunction(functionName="TableSegmentScannerFunction", logType=LogType.Tail) boolean scanSegment(SegmentScannerInput input);
/** * Executes a lambda function and returns the result of the execution. */ @Override public cfData execute( cfSession _session, cfArgStructData argStruct ) throws cfmRunTimeException { AmazonKey amazonKey = getAmazonKey( _session, argStruct ); // Arguments to extract String payload = getNamedStringParam( argStruct, "payload", null ); String functionName = getNamedStringParam( argStruct, "function", null ); String qualifier = getNamedStringParam( argStruct, "qualifier", null ); try { // Construct the Lambda Client InvokeRequest invokeRequest = new InvokeRequest(); invokeRequest.setInvocationType( InvocationType.RequestResponse ); invokeRequest.setLogType( LogType.Tail ); invokeRequest.setFunctionName( functionName ); invokeRequest.setPayload( payload ); if ( qualifier != null ) { invokeRequest.setQualifier( qualifier ); } // Lambda client must be created with credentials BasicAWSCredentials awsCreds = new BasicAWSCredentials( amazonKey.getKey(), amazonKey.getSecret() ); AWSLambda awsLambda = AWSLambdaClientBuilder.standard() .withRegion( amazonKey.getAmazonRegion().toAWSRegion().getName() ) .withCredentials( new AWSStaticCredentialsProvider( awsCreds ) ).build(); // Execute and process the results InvokeResult result = awsLambda.invoke( invokeRequest ); // Convert the returned result ByteBuffer resultPayload = result.getPayload(); String resultJson = new String( resultPayload.array(), "UTF-8" ); Map<String, Object> resultMap = Jackson.fromJsonString( resultJson, Map.class ); return tagUtils.convertToCfData( resultMap ); } catch ( Exception e ) { throwException( _session, "AmazonLambdaExecute: " + e.getMessage() ); return cfBooleanData.FALSE; } }