CAMEL-11832: Add support for Lambda
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/fdc75e57 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/fdc75e57 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/fdc75e57 Branch: refs/heads/master Commit: fdc75e57918034ec58db87e0e268ebc0db7fa062 Parents: 12e2c2c Author: Thomas Lehoux <tleh...@gmail.com> Authored: Tue Oct 3 12:16:16 2017 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Tue Oct 3 17:04:16 2017 +0200 ---------------------------------------------------------------------- components/camel-aws/pom.xml | 1 + .../src/main/docs/aws-lambda-component.adoc | 165 ++++++++++ .../component/aws/lambda/LambdaComponent.java | 49 +++ .../aws/lambda/LambdaConfiguration.java | 138 ++++++++ .../component/aws/lambda/LambdaConstants.java | 47 +++ .../component/aws/lambda/LambdaEndpoint.java | 97 ++++++ .../component/aws/lambda/LambdaOperations.java | 26 ++ .../component/aws/lambda/LambdaProducer.java | 298 +++++++++++++++++ .../org/apache/camel/component/aws-lambda | 18 + .../aws/lambda/AmazonLambdaClientMock.java | 325 +++++++++++++++++++ .../LambdaComponentConfigurationTest.java | 76 +++++ .../aws/lambda/LambdaComponentSpringTest.java | 133 ++++++++ .../aws/lambda/LambdaOperationsTest.java | 49 +++ .../aws/lambda/LambdaProducerTest.java | 170 ++++++++++ .../LambdaComponentIntegrationTest.java | 143 ++++++++ .../LambdaComponentSpringTest-context.xml | 57 ++++ .../lambda/function/node/GetHelloWithName.js | 5 + .../lambda/function/node/GetHelloWithName.zip | Bin 0 -> 320 bytes 18 files changed, 1797 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-aws/pom.xml b/components/camel-aws/pom.xml index 7b7a714..d569214 100644 --- a/components/camel-aws/pom.xml +++ b/components/camel-aws/pom.xml @@ -40,6 +40,7 @@ org.apache.camel.spi.ComponentResolver;component=aws-ec2, org.apache.camel.spi.ComponentResolver;component=aws-kinesis, org.apache.camel.spi.ComponentResolver;component=aws-kinesis-firehose, + org.apache.camel.spi.ComponentResolver;component=aws-lambda, org.apache.camel.spi.ComponentResolver;component=aws-s3, org.apache.camel.spi.ComponentResolver;component=aws-sdb, org.apache.camel.spi.ComponentResolver;component=aws-ses, http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/docs/aws-lambda-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/docs/aws-lambda-component.adoc b/components/camel-aws/src/main/docs/aws-lambda-component.adoc new file mode 100644 index 0000000..6020349 --- /dev/null +++ b/components/camel-aws/src/main/docs/aws-lambda-component.adoc @@ -0,0 +1,165 @@ +## AWS Lambda Component + +*Available as of Camel version 2.21* + +The Lambda component supports create, get, list, delete and invoke +https://aws.amazon.com/lambda/[AWS Lambda] functions. + +*Prerequisites* + +You must have a valid Amazon Web Services developer account, and be +signed up to use Amazon Lambda. More information are available at +https://aws.amazon.com/lambda/[Amazon Lambda]. + +When creating a Lambda function, you need to specify a IAM role which has at least the AWSLambdaBasicExecuteRole policy attached. + +*Warning* + +Lambda is regional service. Unlike S3 bucket, Lambda function created in a given region is not available on other regions. + +### URI Format + +[source,java] +------------------------- +aws-lambda://functionName[?options] +------------------------- + +You can append query options to the URI in the following format, +?options=value&option2=value&... + +### URI Options + + +// component options: START +The AWS Lambda component has no options. +// component options: END + + + + +// endpoint options: START +The AWS Lambda endpoint is configured using URI syntax: + + aws-lambda:functionName + +with the following path and query parameters: + +#### Path Parameters (1 parameters): + +[width="100%",cols="2,5,^1,2",options="header"] +|======================================================================= +| Name | Description | Default | Type +| **function** | *Required* Name of the Lambda function. | | String +|======================================================================= + +#### Query Parameters (8 parameters): + +[width="100%",cols="2,5,^1,2",options="header"] +|======================================================================= +| Name | Description | Default | Type +| **accessKey** (producer) | Amazon AWS Access Key | | String +| **awsLambdaClient** (producer) | To use a existing configured AwsLambdaClient as client | | AWSLambda +| **awsLambdaEndpoint** (producer) | The region with which the AWS-Lambda client wants to work with. | | String +| **operation** (producer) | *Required* The operation to perform. It can be listFunctions getFunction createFunction deleteFunction or invokeFunction | | LambdaOperations +| **proxyHost** (producer) | To define a proxy host when instantiating the Lambda client | | String +| **proxyPort** (producer) | To define a proxy port when instantiating the Lambda client | | Integer +| **secretKey** (producer) | Amazon AWS Secret Key | | String +| **synchronous** (advanced) | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported). | false | boolean +|======================================================================= +// endpoint options: END + + + +Required Lambda component options + +You have to provide the awsLambdaClient in the +link:registry.html[Registry] or your accessKey and secretKey to access +the https://aws.amazon.com/lambda/[Amazon Lambda] service. + +### Usage + +#### Message headers evaluated by the Lambda producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Operation |Header |Type |Description |Required + +|All |`CamelAwsLambdaOperation` |`String` |The operation we want to perform. Override operation passed as query parameter| Yes + +|createFunction |`CamelAwsLambdaS3Bucket` |`String` |Amazon S3 bucket name where the .zip file containing +your deployment package is stored. This bucket must reside in the same AWS region where you are creating the Lambda function.| No + +|createFunction |`CamelAwsLambdaS3Key` |`String` |The Amazon S3 object (the deployment package) key name +you want to upload.| No + +|createFunction |`CamelAwsLambdaS3ObjectVersion` |String |The Amazon S3 object (the deployment package) version +you want to upload.| No + +|createFunction |`CamelAwsLambdaZipFile` |`String` |The local path of the zip file (the deployment package). + Content of zip file can also be put in Message body.| No + +|createFunction |`CamelAwsLambdaRole` |`String` |The Amazon Resource Name (ARN) of the IAM role that Lambda assumes + when it executes your function to access any other Amazon Web Services (AWS) resources. |Yes + +|createFunction |`CamelAwsLambdaRuntime` |String |The runtime environment for the Lambda function you are uploading. + (nodejs, nodejs4.3, nodejs6.10, java8, python2.7, python3.6, dotnetcore1.0, odejs4.3-edge) |Yes + +|createFunction |`CamelAwsLambdaHandler` |`String` |The function within your code that Lambda calls to begin execution. + For Node.js, it is the module-name.export value in your function. + For Java, it can be package.class-name::handler or package.class-name.|Yes + +|createFunction |`CamelAwsLambdaDescription` |`String` |The user-provided description.|No + +|createFunction |`CamelAwsLambdaTargetArn` |`String` |The parent object that contains the target ARN (Amazon Resource Name) +of an Amazon SQS queue or Amazon SNS topic.|No + +|createFunction |`CamelAwsLambdaMemorySize` |`Integer` |The memory size, in MB, you configured for the function. +Must be a multiple of 64 MB.|No + +|createFunction |`CamelAwsLambdaKMSKeyArn` |`String` |The Amazon Resource Name (ARN) of the KMS key used to encrypt your function's environment variables. +If not provided, AWS Lambda will use a default service key.|No + +|createFunction |`CamelAwsLambdaPublish` |`Boolean` |This boolean parameter can be used to request AWS Lambda +to create the Lambda function and publish a version as an atomic operation.|No + +|createFunction |`CamelAwsLambdaTimeout` |`Integer` |The function execution time at which Lambda should terminate the function. +The default is 3 seconds.|No + +|createFunction |`CamelAwsLambdaTracingConfig` |`String` |Your function's tracing settings (Active or PassThrough).|No + +|createFunction |`CamelAwsLambdaEnvironmentVariables` |`Map<String, String>` |The key-value pairs that represent your environment's configuration settings.|No + +|createFunction |`CamelAwsLambdaEnvironmentTags` |`Map<String, String>` |The list of tags (key-value pairs) assigned to the new function.|No + +|createFunction |`CamelAwsLambdaSecurityGroupIds` |`List<String>` |If your Lambda function accesses resources in a VPC, a list of one or more security groups IDs in your VPC.|No + +|createFunction |`CamelAwsLambdaSubnetIds` |`List<String>` |If your Lambda function accesses resources in a VPC, a list of one or more subnet IDs in your VPC.|No + +|======================================================================= + +Dependencies + +Maven users will need to add the following dependency to their pom.xml. + +*pom.xml* + +[source,xml] +--------------------------------------- +<dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-aws</artifactId> + <version>${camel-version}</version> +</dependency> +--------------------------------------- + +where `${camel-version`} must be replaced by the actual version of Camel +(2.16 or higher). + +### See Also + +* link:configuring-camel.html[Configuring Camel] +* link:component.html[Component] +* link:endpoint.html[Endpoint] +* link:getting-started.html[Getting Started] + +* link:aws.html[AWS Component] http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaComponent.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaComponent.java new file mode 100644 index 0000000..371cc38 --- /dev/null +++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaComponent.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import java.util.*; +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.impl.UriEndpointComponent; +import org.apache.camel.util.ObjectHelper; + +public class LambdaComponent extends UriEndpointComponent { + + public LambdaComponent() { + super(LambdaEndpoint.class); + } + + public LambdaComponent(CamelContext context) { + super(context, LambdaEndpoint.class); + } + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { + LambdaConfiguration configuration = new LambdaConfiguration(); + setProperties(configuration, parameters); + configuration.setFunction(remaining); + + if (ObjectHelper.isEmpty(configuration.getAwsLambdaClient()) && (ObjectHelper.isEmpty(configuration.getAccessKey()) || ObjectHelper.isEmpty(configuration.getSecretKey()))) { + throw new IllegalArgumentException("accessKey/secretKey or awsLambdaClient must be specified"); + } + + LambdaEndpoint endpoint = new LambdaEndpoint(uri, this, configuration); + return endpoint; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConfiguration.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConfiguration.java new file mode 100644 index 0000000..4286c1d --- /dev/null +++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConfiguration.java @@ -0,0 +1,138 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import com.amazonaws.services.lambda.AWSLambda; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; +import org.apache.camel.spi.UriPath; + +@UriParams +public class LambdaConfiguration implements Cloneable { + + @UriPath + @Metadata(required = "true") + private String function; + @UriParam(label = "producer") + private AWSLambda awsLambdaClient; + @UriParam(label = "producer", secret = true) + private String accessKey; + @UriParam(label = "producer", secret = true) + private String secretKey; + @UriParam(label = "producer") + private String awsLambdaEndpoint; + @UriParam(label = "producer") + @Metadata(required = "true") + private LambdaOperations operation; + @UriParam(label = "producer") + private String proxyHost; + @UriParam(label = "producer") + private Integer proxyPort; + + + public String getFunction() { + return function; + } + + /** + * Name of the Lambda function. + */ + public void setFunction(String function) { + this.function = function; + } + + + public AWSLambda getAwsLambdaClient() { + return awsLambdaClient; + } + + /** + * To use a existing configured AwsLambdaClient as client + */ + public void setAwsLambdaClient(AWSLambda awsLambdaClient) { + this.awsLambdaClient = awsLambdaClient; + } + + public String getAccessKey() { + return accessKey; + } + + /** + * Amazon AWS Access Key + */ + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + /** + * Amazon AWS Secret Key + */ + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getAwsLambdaEndpoint() { + return awsLambdaEndpoint; + } + + /** + * The region with which the AWS-Lambda client wants to work with. + */ + public void setAwsLambdaEndpoint(String awsLambdaEndpoint) { + this.awsLambdaEndpoint = awsLambdaEndpoint; + } + + public LambdaOperations getOperation() { + return operation; + } + + /** + * The operation to perform. It can be listFunctions, getFunction, createFunction, deleteFunction or invokeFunction + */ + public void setOperation(LambdaOperations operation) { + this.operation = operation; + } + + /** + * To define a proxy host when instantiating the Lambda client + */ + public String getProxyHost() { + return proxyHost; + } + + public void setProxyHost(String proxyHost) { + this.proxyHost = proxyHost; + } + + /** + * To define a proxy port when instantiating the Lambda client + */ + public Integer getProxyPort() { + return proxyPort; + } + + public void setProxyPort(Integer proxyPort) { + this.proxyPort = proxyPort; + } + + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConstants.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConstants.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConstants.java new file mode 100644 index 0000000..95ced62 --- /dev/null +++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaConstants.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +/** + * Constants used in Camel AWS Lambda module + */ +public interface LambdaConstants { + + String OPERATION = "CamelAwsLambdaOperation"; + + String S3_BUCKET = "CamelAwsLambdaS3Bucket"; + String S3_KEY = "CamelAwsLambdaS3Key"; + String S3_OBJECT_VERSION = "CamelAwsLambdaS3ObjectVersion"; + String ZIP_FILE = "CamelAwsLambdaZipFile"; + String DESCRIPTION = "CamelAwsLambdaDescription"; + String ROLE = "CamelAwsLambdaRole"; + String RUNTIME = "CamelAwsLambdaRuntime"; + String HANDLER = "CamelAwsLambdaHandler"; + String TARGET_ARN = "CamelAwsLambdaTargetArn"; + String MEMORY_SIZE = "CamelAwsLambdaMemorySize"; + String KMS_KEY_ARN = "CamelAwsLambdaKMSKeyArn"; + String ENVIRONMENT_VARIABLES = "CamelAwsLambdaEnvironmentVariables"; + String PUBLISH = "CamelAwsLambdaPublish"; + String TIMEOUT = "CamelAwsLambdaTimeout"; + String TAGS = "CamelAwsLambdaTags"; + String TRACING_CONFIG = "CamelAwsLambdaTracingConfig"; + String SDK_CLIENT_EXECUTION_TIMEOUT = "CamelAwsLambdaSdkClientExecutionTimeout"; + String SDK_REQUEST_TIMEOUT = "CamelAwsLambdaSdkRequestTimeout"; + String SECURITY_GROUP_IDS = "CamelAwsLambdaSecurityGroupIds"; + String SUBNET_IDS = "CamelAwsLambdaSubnetIds"; + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaEndpoint.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaEndpoint.java new file mode 100644 index 0000000..086a2fe --- /dev/null +++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaEndpoint.java @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import com.amazonaws.ClientConfiguration; +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.lambda.AWSLambda; +import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import org.apache.camel.Component; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.impl.ScheduledPollEndpoint; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.util.ObjectHelper; + +/** + * The aws-lambda is used for managing and invoking functions from Amazon Lambda. + */ +@UriEndpoint(firstVersion = "2.21.0", scheme = "aws-lambda", title = "AWS Lambda", syntax = "aws-lambda:functionName", producerOnly = true, label = "cloud,computing,serverless") +public class LambdaEndpoint extends ScheduledPollEndpoint { + + private AWSLambda awsLambdaClient; + + @UriParam + private LambdaConfiguration configuration; + + public LambdaEndpoint(String uri, Component component, LambdaConfiguration configuration) { + super(uri, component); + this.configuration = configuration; + } + + public Consumer createConsumer(Processor processor) throws Exception { + throw new UnsupportedOperationException("You cannot receive messages from this endpoint"); + } + + public Producer createProducer() throws Exception { + return new LambdaProducer(this); + } + + public boolean isSingleton() { + return true; + } + + @Override + public void doStart() throws Exception { + super.doStart(); + awsLambdaClient = configuration.getAwsLambdaClient() != null ? configuration.getAwsLambdaClient() : createLambdaClient(); + } + + public LambdaConfiguration getConfiguration() { + return configuration; + } + + public AWSLambda getAwsLambdaClient() { + return awsLambdaClient; + } + + AWSLambda createLambdaClient() { + AWSLambdaClientBuilder builder = AWSLambdaClientBuilder.standard(); + + if (ObjectHelper.isNotEmpty(configuration.getProxyHost()) && ObjectHelper.isNotEmpty(configuration.getProxyPort())) { + ClientConfiguration clientConfiguration = new ClientConfiguration(); + clientConfiguration.setProxyHost(configuration.getProxyHost()); + clientConfiguration.setProxyPort(configuration.getProxyPort()); + builder = builder.withClientConfiguration(clientConfiguration); + } + + if (ObjectHelper.isNotEmpty(configuration.getAwsLambdaEndpoint())) { + builder = builder.withRegion(configuration.getAwsLambdaEndpoint()); + } + + if (configuration.getAccessKey() != null && configuration.getSecretKey() != null) { + AWSCredentials credentials = new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey()); + builder = builder.withCredentials(new AWSStaticCredentialsProvider(credentials)); + } + + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaOperations.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaOperations.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaOperations.java new file mode 100644 index 0000000..0feccb7 --- /dev/null +++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaOperations.java @@ -0,0 +1,26 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +public enum LambdaOperations { + + listFunctions, + getFunction, + createFunction, + deleteFunction, + invokeFunction +} http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaProducer.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaProducer.java new file mode 100644 index 0000000..cff6ac5 --- /dev/null +++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/lambda/LambdaProducer.java @@ -0,0 +1,298 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import java.io.*; +import java.nio.*; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import com.amazonaws.AmazonServiceException; +import com.amazonaws.services.lambda.AWSLambda; +import com.amazonaws.services.lambda.model.CreateFunctionRequest; +import com.amazonaws.services.lambda.model.CreateFunctionResult; +import com.amazonaws.services.lambda.model.DeadLetterConfig; +import com.amazonaws.services.lambda.model.DeleteFunctionRequest; +import com.amazonaws.services.lambda.model.DeleteFunctionResult; +import com.amazonaws.services.lambda.model.Environment; +import com.amazonaws.services.lambda.model.FunctionCode; +import com.amazonaws.services.lambda.model.GetFunctionRequest; +import com.amazonaws.services.lambda.model.GetFunctionResult; +import com.amazonaws.services.lambda.model.InvokeRequest; +import com.amazonaws.services.lambda.model.InvokeResult; +import com.amazonaws.services.lambda.model.ListFunctionsResult; +import com.amazonaws.services.lambda.model.TracingConfig; +import com.amazonaws.services.lambda.model.VpcConfig; +import com.amazonaws.util.IOUtils; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.impl.DefaultProducer; +import org.apache.camel.util.CastUtils; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.camel.component.aws.common.AwsExchangeUtil.getMessageForResponse; + + +/** + * A Producer which sends messages to the Amazon Web Service Lambda <a + * href="https://aws.amazon.com/lambda/">AWS Lambda</a> + */ +public class LambdaProducer extends DefaultProducer { + + private static final Logger LOG = LoggerFactory.getLogger(LambdaProducer.class); + + public LambdaProducer(final Endpoint endpoint) { + super(endpoint); + } + + + @Override + public void process(final Exchange exchange) throws Exception { + switch (determineOperation(exchange)) { + case getFunction: + getFunction(getEndpoint().getAwsLambdaClient(), exchange); + break; + case createFunction: + createFunction(getEndpoint().getAwsLambdaClient(), exchange); + break; + case deleteFunction: + deleteFunction(getEndpoint().getAwsLambdaClient(), exchange); + break; + case invokeFunction: + invokeFunction(getEndpoint().getAwsLambdaClient(), exchange); + break; + case listFunctions: + listFunctions(getEndpoint().getAwsLambdaClient(), exchange); + break; + default: + throw new IllegalArgumentException("Unsupported operation"); + } + } + + + private void getFunction(AWSLambda lambdaClient, Exchange exchange) { + GetFunctionResult result; + try { + result = lambdaClient.getFunction(new GetFunctionRequest().withFunctionName(getConfiguration().getFunction())); + } catch (AmazonServiceException ase) { + LOG.trace("getFunction command returned the error code {}", ase.getErrorCode()); + throw ase; + } + Message message = getMessageForResponse(exchange); + message.setBody(result); + } + + + private void deleteFunction(AWSLambda lambdaClient, Exchange exchange) { + DeleteFunctionResult result; + try { + result = lambdaClient.deleteFunction(new DeleteFunctionRequest().withFunctionName(getConfiguration().getFunction())); + } catch (AmazonServiceException ase) { + LOG.trace("deleteFunction command returned the error code {}", ase.getErrorCode()); + throw ase; + } + Message message = getMessageForResponse(exchange); + message.setBody(result); + } + + + private void listFunctions(AWSLambda lambdaClient, Exchange exchange) { + ListFunctionsResult result; + try { + result = lambdaClient.listFunctions(); + } catch (AmazonServiceException ase) { + LOG.trace("listFunctions command returned the error code {}", ase.getErrorCode()); + throw ase; + } + Message message = getMessageForResponse(exchange); + message.setBody(result); + } + + + private void invokeFunction(AWSLambda lambdaClient, Exchange exchange) { + InvokeResult result; + try { + InvokeRequest request = new InvokeRequest() + .withFunctionName(getConfiguration().getFunction()) + .withPayload(exchange.getIn().getBody(String.class)); + result = lambdaClient.invoke(request); + } catch (AmazonServiceException ase) { + LOG.trace("invokeFunction command returned the error code {}", ase.getErrorCode()); + throw ase; + } + Message message = getMessageForResponse(exchange); + message.setBody(StandardCharsets.UTF_8.decode(result.getPayload()).toString()); + } + + + private void createFunction(AWSLambda lambdaClient, Exchange exchange) throws Exception { + CreateFunctionResult result; + try { + + CreateFunctionRequest request = new CreateFunctionRequest() + .withFunctionName(getConfiguration().getFunction()); + + FunctionCode functionCode = new FunctionCode(); + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.S3_BUCKET))) { + String s3Bucket = exchange.getIn().getHeader(LambdaConstants.S3_BUCKET, String.class); + functionCode.withS3Bucket(s3Bucket); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.S3_KEY))) { + String s3Key = exchange.getIn().getHeader(LambdaConstants.S3_KEY, String.class); + functionCode.withS3Key(s3Key); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.S3_OBJECT_VERSION))) { + String s3ObjectVersion = exchange.getIn().getHeader(LambdaConstants.S3_OBJECT_VERSION, String.class); + functionCode.withS3ObjectVersion(s3ObjectVersion); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.ZIP_FILE))) { + String zipFile = exchange.getIn().getHeader(LambdaConstants.ZIP_FILE, String.class); + File fileLocalPath = new File(zipFile); + FileInputStream inputStream = new FileInputStream(fileLocalPath); + functionCode.withZipFile(ByteBuffer.wrap(IOUtils.toByteArray(inputStream))); + } + if (ObjectHelper.isNotEmpty(exchange.getIn().getBody())) { + functionCode.withZipFile(exchange.getIn().getBody(ByteBuffer.class)); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getBody()) + || (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.S3_BUCKET)) && ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.S3_KEY)))) { + request.withCode(functionCode); + } else { + throw new IllegalArgumentException("At least S3 bucket/S3 key or zip file must be specified"); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.ROLE))) { + request.withRole(exchange.getIn().getHeader(LambdaConstants.ROLE, String.class)); + } else { + throw new IllegalArgumentException("Role must be specified"); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.RUNTIME))) { + request.withRuntime(exchange.getIn().getHeader(LambdaConstants.RUNTIME, String.class)); + } else { + throw new IllegalArgumentException("Runtime must be specified"); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.HANDLER))) { + request.withHandler(exchange.getIn().getHeader(LambdaConstants.HANDLER, String.class)); + } else { + throw new IllegalArgumentException("Handler must be specified"); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.DESCRIPTION))) { + String description = exchange.getIn().getHeader(LambdaConstants.DESCRIPTION, String.class); + request.withDescription(description); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.TARGET_ARN))) { + String targetArn = exchange.getIn().getHeader(LambdaConstants.TARGET_ARN, String.class); + request.withDeadLetterConfig(new DeadLetterConfig().withTargetArn(targetArn)); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.MEMORY_SIZE))) { + Integer memorySize = exchange.getIn().getHeader(LambdaConstants.MEMORY_SIZE, Integer.class); + request.withMemorySize(memorySize); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.KMS_KEY_ARN))) { + String kmsKeyARN = exchange.getIn().getHeader(LambdaConstants.KMS_KEY_ARN, String.class); + request.withKMSKeyArn(kmsKeyARN); + } + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.PUBLISH))) { + Boolean publish = exchange.getIn().getHeader(LambdaConstants.PUBLISH, Boolean.class); + request.withPublish(publish); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.TIMEOUT))) { + Integer timeout = exchange.getIn().getHeader(LambdaConstants.TIMEOUT, Integer.class); + request.withTimeout(timeout); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.TRACING_CONFIG))) { + String tracingConfigMode = exchange.getIn().getHeader(LambdaConstants.TRACING_CONFIG, String.class); + request.withTracingConfig(new TracingConfig().withMode(tracingConfigMode)); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.SDK_CLIENT_EXECUTION_TIMEOUT))) { + Integer timeout = exchange.getIn().getHeader(LambdaConstants.SDK_CLIENT_EXECUTION_TIMEOUT, Integer.class); + request.withSdkClientExecutionTimeout(timeout); + } + + if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(LambdaConstants.SDK_REQUEST_TIMEOUT))) { + Integer timeout = exchange.getIn().getHeader(LambdaConstants.SDK_REQUEST_TIMEOUT, Integer.class); + request.withSdkRequestTimeout(timeout); + } + + Map<String, String> environmentVariables = CastUtils.cast(exchange.getIn().getHeader(LambdaConstants.ENVIRONMENT_VARIABLES, Map.class)); + if (environmentVariables != null) { + request.withEnvironment(new Environment().withVariables(environmentVariables)); + } + + Map<String, String> tags = CastUtils.cast(exchange.getIn().getHeader(LambdaConstants.TAGS, Map.class)); + if (tags != null) { + request.withTags(tags); + } + + List<String> securityGroupIds = CastUtils.cast(exchange.getIn().getHeader(LambdaConstants.SECURITY_GROUP_IDS, (Class<List<String>>) (Object) List.class)); + List<String> subnetIds = CastUtils.cast(exchange.getIn().getHeader(LambdaConstants.SUBNET_IDS, (Class<List<String>>) (Object) List.class)); + if (securityGroupIds != null || subnetIds != null) { + VpcConfig vpcConfig = new VpcConfig(); + if (securityGroupIds != null) { + vpcConfig.withSecurityGroupIds(securityGroupIds); + } + if (subnetIds != null) { + vpcConfig.withSubnetIds(subnetIds); + } + request.withVpcConfig(vpcConfig); + } + result = lambdaClient.createFunction(request); + + } catch (AmazonServiceException ase) { + System.out.println(ase.getErrorCode() + " - " + ase.getErrorMessage()); + LOG.trace("invokeFunction command returned the error code {}", ase.getErrorCode()); + throw ase; + } + Message message = getMessageForResponse(exchange); + message.setBody(result); + } + + + private LambdaOperations determineOperation(Exchange exchange) { + LambdaOperations operation = exchange.getIn().getHeader(LambdaConstants.OPERATION, LambdaOperations.class); + if (operation == null) { + operation = getConfiguration().getOperation(); + } + return operation; + } + + protected LambdaConfiguration getConfiguration() { + return getEndpoint().getConfiguration(); + } + + @Override + public LambdaEndpoint getEndpoint() { + return (LambdaEndpoint) super.getEndpoint(); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/main/resources/META-INF/services/org/apache/camel/component/aws-lambda ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/main/resources/META-INF/services/org/apache/camel/component/aws-lambda b/components/camel-aws/src/main/resources/META-INF/services/org/apache/camel/component/aws-lambda new file mode 100644 index 0000000..51364f7 --- /dev/null +++ b/components/camel-aws/src/main/resources/META-INF/services/org/apache/camel/component/aws-lambda @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +class=org.apache.camel.component.aws.lambda.LambdaComponent http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/AmazonLambdaClientMock.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/AmazonLambdaClientMock.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/AmazonLambdaClientMock.java new file mode 100644 index 0000000..6b07bda --- /dev/null +++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/AmazonLambdaClientMock.java @@ -0,0 +1,325 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import java.nio.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import com.amazonaws.AmazonServiceException; +import com.amazonaws.AmazonWebServiceRequest; +import com.amazonaws.ResponseMetadata; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.lambda.AWSLambdaClient; +import com.amazonaws.services.lambda.model.AddPermissionRequest; +import com.amazonaws.services.lambda.model.AddPermissionResult; +import com.amazonaws.services.lambda.model.CreateAliasRequest; +import com.amazonaws.services.lambda.model.CreateAliasResult; +import com.amazonaws.services.lambda.model.CreateEventSourceMappingRequest; +import com.amazonaws.services.lambda.model.CreateEventSourceMappingResult; +import com.amazonaws.services.lambda.model.CreateFunctionRequest; +import com.amazonaws.services.lambda.model.CreateFunctionResult; +import com.amazonaws.services.lambda.model.DeleteAliasRequest; +import com.amazonaws.services.lambda.model.DeleteAliasResult; +import com.amazonaws.services.lambda.model.DeleteEventSourceMappingRequest; +import com.amazonaws.services.lambda.model.DeleteEventSourceMappingResult; +import com.amazonaws.services.lambda.model.DeleteFunctionRequest; +import com.amazonaws.services.lambda.model.DeleteFunctionResult; +import com.amazonaws.services.lambda.model.FunctionConfiguration; +import com.amazonaws.services.lambda.model.GetAccountSettingsRequest; +import com.amazonaws.services.lambda.model.GetAccountSettingsResult; +import com.amazonaws.services.lambda.model.GetAliasRequest; +import com.amazonaws.services.lambda.model.GetAliasResult; +import com.amazonaws.services.lambda.model.GetEventSourceMappingRequest; +import com.amazonaws.services.lambda.model.GetEventSourceMappingResult; +import com.amazonaws.services.lambda.model.GetFunctionConfigurationRequest; +import com.amazonaws.services.lambda.model.GetFunctionConfigurationResult; +import com.amazonaws.services.lambda.model.GetFunctionRequest; +import com.amazonaws.services.lambda.model.GetFunctionResult; +import com.amazonaws.services.lambda.model.GetPolicyRequest; +import com.amazonaws.services.lambda.model.GetPolicyResult; +import com.amazonaws.services.lambda.model.InvokeAsyncRequest; +import com.amazonaws.services.lambda.model.InvokeAsyncResult; +import com.amazonaws.services.lambda.model.InvokeRequest; +import com.amazonaws.services.lambda.model.InvokeResult; +import com.amazonaws.services.lambda.model.ListAliasesRequest; +import com.amazonaws.services.lambda.model.ListAliasesResult; +import com.amazonaws.services.lambda.model.ListEventSourceMappingsRequest; +import com.amazonaws.services.lambda.model.ListEventSourceMappingsResult; +import com.amazonaws.services.lambda.model.ListFunctionsRequest; +import com.amazonaws.services.lambda.model.ListFunctionsResult; +import com.amazonaws.services.lambda.model.ListTagsRequest; +import com.amazonaws.services.lambda.model.ListTagsResult; +import com.amazonaws.services.lambda.model.ListVersionsByFunctionRequest; +import com.amazonaws.services.lambda.model.ListVersionsByFunctionResult; +import com.amazonaws.services.lambda.model.PublishVersionRequest; +import com.amazonaws.services.lambda.model.PublishVersionResult; +import com.amazonaws.services.lambda.model.RemovePermissionRequest; +import com.amazonaws.services.lambda.model.RemovePermissionResult; +import com.amazonaws.services.lambda.model.Runtime; +import com.amazonaws.services.lambda.model.TagResourceRequest; +import com.amazonaws.services.lambda.model.TagResourceResult; +import com.amazonaws.services.lambda.model.TracingConfigResponse; +import com.amazonaws.services.lambda.model.TracingMode; +import com.amazonaws.services.lambda.model.UntagResourceRequest; +import com.amazonaws.services.lambda.model.UntagResourceResult; +import com.amazonaws.services.lambda.model.UpdateAliasRequest; +import com.amazonaws.services.lambda.model.UpdateAliasResult; +import com.amazonaws.services.lambda.model.UpdateEventSourceMappingRequest; +import com.amazonaws.services.lambda.model.UpdateEventSourceMappingResult; +import com.amazonaws.services.lambda.model.UpdateFunctionCodeRequest; +import com.amazonaws.services.lambda.model.UpdateFunctionCodeResult; +import com.amazonaws.services.lambda.model.UpdateFunctionConfigurationRequest; +import com.amazonaws.services.lambda.model.UpdateFunctionConfigurationResult; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.joda.time.DateTime; + +public class AmazonLambdaClientMock extends AWSLambdaClient { + + public AmazonLambdaClientMock() { + super(new BasicAWSCredentials("user", "secret")); + } + + + @Override + public AddPermissionResult addPermission(AddPermissionRequest addPermissionRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public CreateAliasResult createAlias(CreateAliasRequest createAliasRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public CreateEventSourceMappingResult createEventSourceMapping(CreateEventSourceMappingRequest createEventSourceMappingRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public CreateFunctionResult createFunction(CreateFunctionRequest createFunctionRequest) { + + CreateFunctionResult result = new CreateFunctionResult(); + + result.setFunctionName(createFunctionRequest.getFunctionName()); + result.setDeadLetterConfig(createFunctionRequest.getDeadLetterConfig()); + result.setDescription(createFunctionRequest.getDescription()); + result.setHandler(createFunctionRequest.getHandler()); + result.setFunctionArn("arn:aws:lambda:eu-central-1:643534317684:function:" + createFunctionRequest.getFunctionName()); + + try { + Runtime runtime = Runtime.fromValue(createFunctionRequest.getRuntime()); + result.setRuntime(runtime); + } catch (Exception e) { + throw new AmazonServiceException("validation error detected: Value '" + + createFunctionRequest.getRuntime() + + "' at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [java8, nodejs, nodejs4.3, nodejs6.10, python2.7, python3.6, dotnetcore1.0]"); + } + + result.setRole("arn:aws:iam::643534317684:role/" + createFunctionRequest.getRole()); + result.setCodeSize(340L); + result.setCodeSha256("PKt5ygvZ6G8vWJASlWIypsBmKzAdmRrvTO"); + result.setMemorySize(128); + result.setTimeout(3); + result.setLastModified(DateTime.now().toString()); + result.setVersion("$LATEST"); + result.setTracingConfig(new TracingConfigResponse().withMode(TracingMode.PassThrough)); + return result; + } + + @Override + public DeleteAliasResult deleteAlias(DeleteAliasRequest deleteAliasRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public DeleteEventSourceMappingResult deleteEventSourceMapping(DeleteEventSourceMappingRequest deleteEventSourceMappingRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public DeleteFunctionResult deleteFunction(DeleteFunctionRequest deleteFunctionRequest) { + return new DeleteFunctionResult(); + } + + @Override + public GetAccountSettingsResult getAccountSettings(GetAccountSettingsRequest getAccountSettingsRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public GetAliasResult getAlias(GetAliasRequest getAliasRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public GetEventSourceMappingResult getEventSourceMapping(GetEventSourceMappingRequest getEventSourceMappingRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public GetFunctionResult getFunction(GetFunctionRequest getFunctionRequest) { + + GetFunctionResult result = new GetFunctionResult(); + FunctionConfiguration configuration = new FunctionConfiguration(); + configuration.setFunctionName(getFunctionRequest.getFunctionName()); + configuration.setFunctionArn("arn:aws:lambda:eu-central-1:643534317684:function:" + getFunctionRequest.getFunctionName()); + configuration.setRuntime("nodejs6.10"); + configuration.setRole("arn:aws:iam::643534317684:role/lambda-execution-role"); + configuration.setHandler(getFunctionRequest.getFunctionName() + ".handler"); + configuration.setCodeSize(640L); + configuration.setCodeSha256("PKt5ygvZ6G8vWJASlWIypsBmKzAdmRrvTO/eBH06mBA="); + configuration.setMemorySize(128); + configuration.setTimeout(3); + configuration.setLastModified(DateTime.now().toString()); + configuration.setVersion("$LATEST"); + configuration.setTracingConfig(new TracingConfigResponse().withMode(TracingMode.PassThrough)); + result.setConfiguration(configuration); + return result; + } + + @Override + public GetFunctionConfigurationResult getFunctionConfiguration(GetFunctionConfigurationRequest getFunctionConfigurationRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public GetPolicyResult getPolicy(GetPolicyRequest getPolicyRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public InvokeResult invoke(InvokeRequest invokeRequest) { + InvokeResult result = new InvokeResult(); + + Map<String, Object> payload = new HashMap<String, Object>(); + try { + ObjectMapper mapper = new ObjectMapper(); + payload = mapper.readValue(StandardCharsets.UTF_8.decode(invokeRequest.getPayload()).toString(), new TypeReference<Map<String, String>>() { + }); + } catch (Exception e) { + + } + String responsePayload = "{\"Hello\":\"" + payload.get("name") + "\"}"; + result.setPayload(ByteBuffer.wrap(responsePayload.getBytes())); + return result; + } + + @Override + public InvokeAsyncResult invokeAsync(InvokeAsyncRequest invokeAsyncRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public ListAliasesResult listAliases(ListAliasesRequest listAliasesRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public ListEventSourceMappingsResult listEventSourceMappings(ListEventSourceMappingsRequest listEventSourceMappingsRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public ListEventSourceMappingsResult listEventSourceMappings() { + throw new UnsupportedOperationException(); + } + + @Override + public ListFunctionsResult listFunctions(ListFunctionsRequest listFunctionsRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public ListFunctionsResult listFunctions() { + + ListFunctionsResult result = new ListFunctionsResult(); + Collection<FunctionConfiguration> listFunctions = new ArrayList<FunctionConfiguration>(); + FunctionConfiguration configuration = new FunctionConfiguration(); + configuration.setFunctionName("GetHelloWithName"); + configuration.setFunctionArn("arn:aws:lambda:eu-central-1:643534317684:function:GetHelloWithName"); + configuration.setRuntime("nodejs6.10"); + configuration.setRole("arn:aws:iam::643534317684:role/lambda-execution-role"); + configuration.setHandler("GetHelloWithName.handler"); + configuration.setCodeSize(640L); + configuration.setCodeSha256("PKt5ygvZ6G8vWJASlWIypsBmKzAdmRrvTO/eBH06mBA="); + configuration.setMemorySize(128); + configuration.setTimeout(3); + configuration.setLastModified(DateTime.now().toString()); + configuration.setVersion("$LATEST"); + configuration.setTracingConfig(new TracingConfigResponse().withMode(TracingMode.PassThrough)); + listFunctions.add(configuration); + result.setFunctions(listFunctions); + return result; + } + + @Override + public ListTagsResult listTags(ListTagsRequest listTagsRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public ListVersionsByFunctionResult listVersionsByFunction(ListVersionsByFunctionRequest listVersionsByFunctionRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public PublishVersionResult publishVersion(PublishVersionRequest publishVersionRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public RemovePermissionResult removePermission(RemovePermissionRequest removePermissionRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public TagResourceResult tagResource(TagResourceRequest tagResourceRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public UntagResourceResult untagResource(UntagResourceRequest untagResourceRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public UpdateAliasResult updateAlias(UpdateAliasRequest updateAliasRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public UpdateEventSourceMappingResult updateEventSourceMapping(UpdateEventSourceMappingRequest updateEventSourceMappingRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public UpdateFunctionCodeResult updateFunctionCode(UpdateFunctionCodeRequest updateFunctionCodeRequest) { + throw new UnsupportedOperationException(); + } + + @Override + public UpdateFunctionConfigurationResult updateFunctionConfiguration(UpdateFunctionConfigurationRequest updateFunctionConfigurationRequest) { + throw new UnsupportedOperationException(); + } + + + @Override + public ResponseMetadata getCachedResponseMetadata(AmazonWebServiceRequest amazonWebServiceRequest) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentConfigurationTest.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentConfigurationTest.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentConfigurationTest.java new file mode 100644 index 0000000..ba848af --- /dev/null +++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentConfigurationTest.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import com.amazonaws.services.lambda.AWSLambdaClient; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; +import static org.mockito.Mockito.mock; + + +public class LambdaComponentConfigurationTest extends CamelTestSupport { + AWSLambdaClient awsLambdaClient = mock(AWSLambdaClient.class); + + @Test + public void createEndpointWithMinimalConfiguration() throws Exception { + LambdaComponent component = new LambdaComponent(context); + LambdaEndpoint endpoint = (LambdaEndpoint) component.createEndpoint( + "aws-lambda://myFunction?operation=getFunction&awsLambdaClient=#awsLambdaClient&accessKey=xxx&secretKey=yyy"); + + assertEquals("xxx", endpoint.getConfiguration().getAccessKey()); + assertEquals("yyy", endpoint.getConfiguration().getSecretKey()); + assertNotNull(endpoint.getConfiguration().getAwsLambdaClient()); + } + + @Test(expected = IllegalArgumentException.class) + public void createEndpointWithoutOperation() throws Exception { + LambdaComponent component = new LambdaComponent(context); + component.createEndpoint("aws-lambda://myFunction"); + } + + @Test(expected = IllegalArgumentException.class) + public void createEndpointWithoutAmazonLambdaClientConfiguration() throws Exception { + LambdaComponent component = new LambdaComponent(context); + component.createEndpoint("aws-lambda://myFunction?operation=getFunction"); + } + + @Test(expected = IllegalArgumentException.class) + public void createEndpointWithoutAccessKeyConfiguration() throws Exception { + LambdaComponent component = new LambdaComponent(context); + component.createEndpoint("aws-lambda://myFunction?operation=getFunction&secretKey=yyy"); + } + + @Test(expected = IllegalArgumentException.class) + public void createEndpointWithoutSecretKeyConfiguration() throws Exception { + LambdaComponent component = new LambdaComponent(context); + component.createEndpoint("aws-lambda://myFunction?operation=getFunction&accessKey=xxx"); + } + + @Test + public void createEndpointWithoutSecretKeyAndAccessKeyConfiguration() throws Exception { + LambdaComponent component = new LambdaComponent(context); + component.createEndpoint("aws-lambda://myFunction?operation=getFunction&awsLambdaClient=#awsLambdaClient"); + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry registry = super.createRegistry(); + registry.bind("awsLambdaClient", awsLambdaClient); + return registry; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest.java new file mode 100644 index 0000000..84c8b56 --- /dev/null +++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest.java @@ -0,0 +1,133 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import java.io.*; +import com.amazonaws.services.lambda.AWSLambdaClient; +import com.amazonaws.services.lambda.model.CreateFunctionResult; +import com.amazonaws.services.lambda.model.DeleteFunctionResult; +import com.amazonaws.services.lambda.model.GetFunctionResult; +import com.amazonaws.services.lambda.model.ListFunctionsResult; +import com.amazonaws.util.IOUtils; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Processor; +import org.apache.camel.test.spring.CamelSpringTestSupport; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class LambdaComponentSpringTest extends CamelSpringTestSupport { + + private AWSLambdaClient awsLambdaClient; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + + awsLambdaClient = context.getRegistry().lookupByNameAndType("awsLambdaClient", AmazonLambdaClientMock.class); + } + + @Test + public void lambdaCreateFunctionTest() throws Exception { + + Exchange exchange = template.send("direct:createFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(LambdaConstants.RUNTIME, "nodejs6.10"); + exchange.getIn().setHeader(LambdaConstants.HANDLER, "GetHelloWithName.handler"); + exchange.getIn().setHeader(LambdaConstants.DESCRIPTION, "Hello with node.js on Lambda"); + exchange.getIn().setHeader(LambdaConstants.ROLE, "arn:aws:iam::643534317684:role/lambda-execution-role"); + + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource("org/apache/camel/component/aws/lambda/function/node/GetHelloWithName.zip").getFile()); + FileInputStream inputStream = new FileInputStream(file); + exchange.getIn().setBody(IOUtils.toByteArray(inputStream)); + } + }); + + CreateFunctionResult result = (CreateFunctionResult) exchange.getOut().getBody(); + assertEquals(result.getFunctionName(), "GetHelloWithName"); + assertEquals(result.getDescription(), "Hello with node.js on Lambda"); + assertNotNull(result.getFunctionArn()); + assertNotNull(result.getCodeSha256()); + } + + @Test + public void lambdaDeleteFunctionTest() throws Exception { + + Exchange exchange = template.send("direct:deleteFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + assertNotNull(exchange.getOut().getBody(DeleteFunctionResult.class)); + } + + + @Test + public void lambdaGetFunctionTest() throws Exception { + + Exchange exchange = template.send("direct:getFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + GetFunctionResult result = (GetFunctionResult) exchange.getOut().getBody(); + assertEquals(result.getConfiguration().getFunctionName(), "GetHelloWithName"); + } + + + @Test + public void lambdaListFunctionsTest() throws Exception { + Exchange exchange = template.send("direct:listFunctions", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + + ListFunctionsResult result = (ListFunctionsResult) exchange.getOut().getBody(); + assertEquals(result.getFunctions().size(), 1); + assertEquals(result.getFunctions().get(0).getFunctionName(), "GetHelloWithName"); + } + + + @Test + public void lambdaInvokeFunctionTest() throws Exception { + Exchange exchange = template.send("direct:invokeFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + exchange.getIn().setBody("{\"name\":\"Camel\"}"); + } + }); + + assertNotNull(exchange.getOut().getBody(String.class)); + assertEquals(exchange.getOut().getBody(String.class), "{\"Hello\":\"Camel\"}"); + } + + + @Override + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext( + "org/apache/camel/component/aws/lambda/LambdaComponentSpringTest-context.xml"); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaOperationsTest.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaOperationsTest.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaOperationsTest.java new file mode 100644 index 0000000..0d156e7 --- /dev/null +++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaOperationsTest.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + + + +public class LambdaOperationsTest { + + @Test + public void supportedOperationCount() { + assertEquals(5, LambdaOperations.values().length); + } + + @Test + public void valueOf() { + assertEquals(LambdaOperations.createFunction, LambdaOperations.valueOf("createFunction")); + assertEquals(LambdaOperations.getFunction, LambdaOperations.valueOf("getFunction")); + assertEquals(LambdaOperations.listFunctions, LambdaOperations.valueOf("listFunctions")); + assertEquals(LambdaOperations.invokeFunction, LambdaOperations.valueOf("invokeFunction")); + assertEquals(LambdaOperations.deleteFunction, LambdaOperations.valueOf("deleteFunction")); + } + + @Test + public void testToString() { + assertEquals(LambdaOperations.createFunction.toString(), "createFunction"); + assertEquals(LambdaOperations.getFunction.toString(), "getFunction"); + assertEquals(LambdaOperations.listFunctions.toString(), "listFunctions"); + assertEquals(LambdaOperations.invokeFunction.toString(), "invokeFunction"); + assertEquals(LambdaOperations.deleteFunction.toString(), "deleteFunction"); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaProducerTest.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaProducerTest.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaProducerTest.java new file mode 100644 index 0000000..f774ceb --- /dev/null +++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/LambdaProducerTest.java @@ -0,0 +1,170 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda; + +import java.io.*; +import com.amazonaws.services.lambda.AWSLambdaClient; +import com.amazonaws.services.lambda.model.CreateFunctionResult; +import com.amazonaws.services.lambda.model.DeleteFunctionResult; +import com.amazonaws.services.lambda.model.GetFunctionResult; +import com.amazonaws.services.lambda.model.ListFunctionsResult; +import com.amazonaws.util.IOUtils; +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +public class LambdaProducerTest extends CamelTestSupport { + + @EndpointInject(uri = "mock:result") + private MockEndpoint mock; + + @Test + public void lambdaCreateFunctionTest() throws Exception { + + Exchange exchange = template.send("direct:createFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(LambdaConstants.RUNTIME, "nodejs6.10"); + exchange.getIn().setHeader(LambdaConstants.HANDLER, "GetHelloWithName.handler"); + exchange.getIn().setHeader(LambdaConstants.DESCRIPTION, "Hello with node.js on Lambda"); + exchange.getIn().setHeader(LambdaConstants.ROLE, "arn:aws:iam::643534317684:role/lambda-execution-role"); + + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource("org/apache/camel/component/aws/lambda/function/node/GetHelloWithName.zip").getFile()); + FileInputStream inputStream = new FileInputStream(file); + exchange.getIn().setBody(IOUtils.toByteArray(inputStream)); + } + }); + + assertMockEndpointsSatisfied(); + + CreateFunctionResult result = (CreateFunctionResult) exchange.getIn().getBody(); + assertEquals(result.getFunctionName(), "GetHelloWithName"); + assertEquals(result.getDescription(), "Hello with node.js on Lambda"); + assertNotNull(result.getFunctionArn()); + assertNotNull(result.getCodeSha256()); + } + + @Test + public void lambdaDeleteFunctionTest() throws Exception { + + Exchange exchange = template.send("direct:deleteFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + + assertMockEndpointsSatisfied(); + assertNotNull(exchange.getOut().getBody(DeleteFunctionResult.class)); + } + + + @Test + public void lambdaGetFunctionTest() throws Exception { + + Exchange exchange = template.send("direct:getFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + assertMockEndpointsSatisfied(); + + GetFunctionResult result = (GetFunctionResult) exchange.getOut().getBody(); + assertEquals(result.getConfiguration().getFunctionName(), "GetHelloWithName"); + } + + + @Test + public void lambdaListFunctionsTest() throws Exception { + + Exchange exchange = template.send("direct:listFunctions", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + assertMockEndpointsSatisfied(); + + ListFunctionsResult result = (ListFunctionsResult) exchange.getOut().getBody(); + assertEquals(result.getFunctions().size(), 1); + assertEquals(result.getFunctions().get(0).getFunctionName(), "GetHelloWithName"); + } + + + @Test + public void lambdaInvokeFunctionTest() throws Exception { + Exchange exchange = template.send("direct:invokeFunction", ExchangePattern.InOut, new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + exchange.getIn().setBody("{\"name\":\"Camel\"}"); + } + }); + assertMockEndpointsSatisfied(); + + assertNotNull(exchange.getOut().getBody(String.class)); + assertEquals(exchange.getOut().getBody(String.class), "{\"Hello\":\"Camel\"}"); + } + + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry registry = super.createRegistry(); + + AWSLambdaClient clientMock = new AmazonLambdaClientMock(); + + registry.bind("awsLambdaClient", clientMock); + + return registry; + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:createFunction") + .to("aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=createFunction") + .to("mock:result"); + + from("direct:getFunction") + .to("aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=getFunction") + .to("mock:result"); + + from("direct:listFunctions") + .to("aws-lambda://myFunction?awsLambdaClient=#awsLambdaClient&operation=listFunctions") + .to("mock:result"); + + from("direct:invokeFunction") + .to("aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=invokeFunction") + .to("mock:result"); + + from("direct:deleteFunction") + .to("aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=deleteFunction") + .to("mock:result"); + + } + }; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/integration/LambdaComponentIntegrationTest.java ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/integration/LambdaComponentIntegrationTest.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/integration/LambdaComponentIntegrationTest.java new file mode 100644 index 0000000..f9b7b28 --- /dev/null +++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/lambda/integration/LambdaComponentIntegrationTest.java @@ -0,0 +1,143 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws.lambda.integration; + +import java.io.*; +import com.amazonaws.services.lambda.model.CreateFunctionResult; +import com.amazonaws.services.lambda.model.DeleteFunctionResult; +import com.amazonaws.services.lambda.model.GetFunctionResult; +import com.amazonaws.services.lambda.model.ListFunctionsResult; +import com.amazonaws.util.IOUtils; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.aws.lambda.LambdaConstants; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Ignore; +import org.junit.Test; + +@Ignore("Must be manually tested. Provide your own accessKey and secretKey!") +public class LambdaComponentIntegrationTest extends CamelTestSupport { + + + @Test + public void lambdaCreateFunctionTest() throws Exception { + Exchange exchange = template.send("direct:createFunction", ExchangePattern.InOut, new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(LambdaConstants.RUNTIME, "nodejs6.10"); + exchange.getIn().setHeader(LambdaConstants.HANDLER, "GetHelloWithName.handler"); + exchange.getIn().setHeader(LambdaConstants.DESCRIPTION, "Hello with node.js on Lambda"); + exchange.getIn().setHeader(LambdaConstants.ROLE, "arn:aws:iam::643534317684:role/lambda-execution-role"); + + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource("org/apache/camel/component/aws/lambda/function/node/GetHelloWithName.zip").getFile()); + FileInputStream inputStream = new FileInputStream(file); + exchange.getIn().setBody(IOUtils.toByteArray(inputStream)); + } + }); + assertNotNull(exchange.getOut().getBody(CreateFunctionResult.class)); + assertEquals(exchange.getOut().getBody(CreateFunctionResult.class).getFunctionName(), "GetHelloWithName"); + } + + @Test + public void lambdaListFunctionsTest() throws Exception { + Exchange exchange = template.send("direct:listFunctions", ExchangePattern.InOut, new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + assertNotNull(exchange.getOut().getBody(ListFunctionsResult.class)); + assertEquals(exchange.getOut().getBody(ListFunctionsResult.class).getFunctions().size(), 3); + } + + + @Test + public void lambdaGetFunctionTest() throws Exception { + Exchange exchange = template.send("direct:getFunction", ExchangePattern.InOut, new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + GetFunctionResult result = exchange.getOut().getBody(GetFunctionResult.class); + assertNotNull(result); + assertEquals(result.getConfiguration().getFunctionName(), "GetHelloWithName"); + assertEquals(result.getConfiguration().getRuntime(), "nodejs6.10"); + + } + + + @Test + public void lambdaInvokeFunctionTest() throws Exception { + Exchange exchange = template.send("direct:invokeFunction", ExchangePattern.InOut, new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + exchange.getIn().setBody("{\"name\":\"Camel\"}"); + } + }); + + assertNotNull(exchange.getOut().getBody(String.class)); + assertEquals(exchange.getOut().getBody(String.class), "{\"Hello\":\"Camel\"}"); + } + + + @Test + public void lambdaDeleteFunctionTest() throws Exception { + + Exchange exchange = template.send("direct:deleteFunction", ExchangePattern.InOut, new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + } + }); + assertNotNull(exchange.getOut().getBody(DeleteFunctionResult.class)); + } + + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + + + from("direct:createFunction") + .to("aws-lambda://GetHelloWithName?operation=createFunction&accessKey=xxxx&secretKey=xxxx&awsLambdaEndpoint=lambda.eu-central-1.amazonaws.com"); + + from("direct:listFunctions") + .to("aws-lambda://myFunction?operation=listFunctions&accessKey=xxxx&secretKey=xxxx&awsLambdaEndpoint=lambda.eu-central-1.amazonaws.com"); + + from("direct:getFunction") + .to("aws-lambda://GetHelloWithName?operation=getFunction&accessKey=xxxx&secretKey=xxxx&awsLambdaEndpoint=lambda.eu-central-1.amazonaws.com"); + + from("direct:invokeFunction") + .to("aws-lambda://GetHelloWithName?operation=invokeFunction&accessKey=xxxx&secretKey=xxxx&awsLambdaEndpoint=lambda.eu-central-1.amazonaws.com"); + + from("direct:deleteFunction") + .to("aws-lambda://GetHelloWithName?operation=deleteFunction&accessKey=xxxx&secretKey=xxxx&awsLambdaEndpoint=lambda.eu-central-1.amazonaws.com"); + + } + }; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/fdc75e57/components/camel-aws/src/test/resources/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest-context.xml ---------------------------------------------------------------------- diff --git a/components/camel-aws/src/test/resources/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest-context.xml b/components/camel-aws/src/test/resources/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest-context.xml new file mode 100644 index 0000000..413404a --- /dev/null +++ b/components/camel-aws/src/test/resources/org/apache/camel/component/aws/lambda/LambdaComponentSpringTest-context.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://www.springframework.org/schema/beans" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> + + <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> + + <route> + <from uri="direct:createFunction"/> + <to uri="aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=createFunction"/> + </route> + + <route> + <from uri="direct:getFunction"/> + <to uri="aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=getFunction"/> + </route> + + <route> + <from uri="direct:listFunctions"/> + <to uri="aws-lambda://myFunction?awsLambdaClient=#awsLambdaClient&operation=listFunctions"/> + </route> + + <route> + <from uri="direct:invokeFunction"/> + <to uri="aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=invokeFunction"/> + </route> + + <route> + <from uri="direct:deleteFunction"/> + <to uri="aws-lambda://GetHelloWithName?awsLambdaClient=#awsLambdaClient&operation=deleteFunction"/> + </route> + + + </camelContext> + + <bean id="awsLambdaClient" class="org.apache.camel.component.aws.lambda.AmazonLambdaClientMock"/> +</beans> \ No newline at end of file