Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Kurt Miller 2018-03-23 20:18:27 -04:00
commit cc00ce5050
33 changed files with 414 additions and 284 deletions

2
.gitignore vendored
View File

@ -55,4 +55,4 @@ jest
# DotNet
[Bb]in/
[Oo]bj/
[Oo]bj/

View File

@ -56,7 +56,7 @@ services:
volumes:
- ./tmp/serverless-integration-test-aws-scala-sbt:/app
aws-csharp:
image: microsoft/dotnet:1.0.4-sdk
image: microsoft/dotnet:2.0-sdk
volumes:
- ./tmp/serverless-integration-test-aws-csharp:/app
aws-fsharp:
@ -99,7 +99,7 @@ services:
- ./tmp/serverless-integration-test-spotinst-ruby:/app
spotinst-java8:
image: maven:3-jdk-8
volumes:
volumes:
- ./tmp/serverless-integration-test-spotinst-java8:/app
webtasks-nodejs:
image: node:6.10.3

View File

@ -12,6 +12,32 @@ layout: Doc
# API Gateway
- [Lambda Proxy Integration](#lambda-proxy-integration)
- [Simple HTTP Endpoint](#simple-http-endpoint)
- [Example "LAMBDA-PROXY" event (default)](#example-lambda-proxy-event-default)
- [HTTP Endpoint with Extended Options](#http-endpoint-with-extended-options)
- [Enabling CORS](#enabling-cors)
- [HTTP Endpoints with `AWS_IAM` Authorizers](#http-endpoints-with-awsiam-authorizers)
- [HTTP Endpoints with Custom Authorizers](#http-endpoints-with-custom-authorizers)
- [Catching Exceptions In Your Lambda Function](#catching-exceptions-in-your-lambda-function)
- [Setting API keys for your Rest API](#setting-api-keys-for-your-rest-api)
- [Request Parameters](#request-parameters)
- [Lambda Integration](#lambda-integration)
- [Example "LAMBDA" event (before customization)](#example-lambda-event-before-customization)
- [Request templates](#request-templates)
- [Default Request Templates](#default-request-templates)
- [Custom Request Templates](#custom-request-templates)
- [Pass Through Behavior](#pass-through-behavior)
- [Responses](#responses)
- [Custom Response Headers](#custom-response-headers)
- [Custom Response Templates](#custom-response-templates)
- [Status codes](#status-codes)
- [Available Status Codes](#available-status-codes)
- [Using Status Codes](#using-status-codes)
- [Custom Status Codes](#custom-status-codes)
- [Setting an HTTP Proxy on API Gateway](#setting-an-http-proxy-on-api-gateway)
- [Share API Gateway and API Resources](#share-api-gateway-and-api-resources)
_Are you looking for tutorials on using API Gateway? Check out the following resources:_
> - [Add a custom domain for your API Gateway](https://serverless.com/blog/serverless-api-gateway-domain/)
@ -634,33 +660,7 @@ See the [api gateway documentation](https://docs.aws.amazon.com/apigateway/lates
**Notes:**
- A missing/empty request Content-Type is considered to be the API Gateway default (`application/json`)
- [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/aws/events/apigateway)
- [API Gateway](#api-gateway)
- [Lambda Proxy Integration](#lambda-proxy-integration)
- [Simple HTTP Endpoint](#simple-http-endpoint)
- [Example "LAMBDA-PROXY" event (default)](#example-lambda-proxy-event-default)
- [HTTP Endpoint with Extended Options](#http-endpoint-with-extended-options)
- [Enabling CORS](#enabling-cors)
- [HTTP Endpoints with `AWS_IAM` Authorizers](#http-endpoints-with-awsiam-authorizers)
- [HTTP Endpoints with Custom Authorizers](#http-endpoints-with-custom-authorizers)
- [Catching Exceptions In Your Lambda Function](#catching-exceptions-in-your-lambda-function)
- [Setting API keys for your Rest API](#setting-api-keys-for-your-rest-api)
- [Request Parameters](#request-parameters)
- [Lambda Integration](#lambda-integration)
- [Example "LAMBDA" event (before customization)](#example-lambda-event-before-customization)
- [Request templates](#request-templates)
- [Default Request Templates](#default-request-templates)
- [Custom Request Templates](#custom-request-templates)
- [Pass Through Behavior](#pass-through-behavior)
- [Responses](#responses)
- [Custom Response Headers](#custom-response-headers)
- [Custom Response Templates](#custom-response-templates)
- [Status codes](#status-codes)
- [Available Status Codes](#available-status-codes)
- [Using Status Codes](#using-status-codes)
- [Custom Status Codes](#custom-status-codes)
- [Setting an HTTP Proxy on API Gateway](#setting-an-http-proxy-on-api-gateway)
- [Share API Gateway and API Resources](#share-api-gateway-and-api-resources)
- API Gateway docs refer to "WHEN_NO_TEMPLATE" (singular), but this will fail during creation as the actual value should be "WHEN_NO_TEMPLATES" (plural)
### Responses
@ -862,7 +862,7 @@ As your application grows, you will likely need to break it out into multiple, s
```yml
service: service-name
provider:
provider:
name: aws
apiGateway:
restApiId: xxxxxxxxxx # REST API resource ID. Default is generated by the framework
@ -873,13 +873,14 @@ functions:
```
If your application has many nested paths, you might also want to break them out into smaller services.
```yml
service: service-a
provider:
provider:
apiGateway:
restApiId: xxxxxxxxxx
restApiId: xxxxxxxxxx
restApiRootResourceId: xxxxxxxxxx
functions:
@ -893,10 +894,10 @@ functions:
```yml
service: service-b
provider:
provider:
apiGateway:
restApiId: xxxxxxxxxx
restApiRootResourceId: xxxxxxxxxx
restApiId: xxxxxxxxxx
restApiRootResourceId: xxxxxxxxxx
functions:
create:
@ -911,13 +912,13 @@ The above example services both reference the same parent path `/posts`. However
```yml
service: service-a
provider:
provider:
apiGateway:
restApiId: xxxxxxxxxx
restApiId: xxxxxxxxxx
restApiRootResourceId: xxxxxxxxxx
restApiResources:
/posts: xxxxxxxxxx
functions:
...
@ -925,10 +926,10 @@ functions:
```yml
service: service-b
provider:
provider:
apiGateway:
restApiId: xxxxxxxxxx
restApiRootResourceId: xxxxxxxxxx
restApiId: xxxxxxxxxx
restApiRootResourceId: xxxxxxxxxx
restApiResources:
/posts: xxxxxxxxxx
@ -942,14 +943,14 @@ You can define more than one path resource, but by default, Serverless will gene
```yml
service: service-a
provider:
provider:
apiGateway:
restApiId: xxxxxxxxxx
restApiId: xxxxxxxxxx
# restApiRootResourceId: xxxxxxxxxx # Optional
restApiResources:
/posts: xxxxxxxxxx
/categories: xxxxxxxxx
functions:
listPosts:

View File

@ -1,39 +0,0 @@
using Amazon.Lambda.Core;
using System;
[assembly:LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace AwsDotnetCsharp
{
public class Handler
{
public Response Hello(Request request)
{
return new Response("Go Serverless v1.0! Your function executed successfully!", request);
}
}
public class Response
{
public string Message {get; set;}
public Request Request {get; set;}
public Response(string message, Request request){
Message = message;
Request = request;
}
}
public class Request
{
public string Key1 {get; set;}
public string Key2 {get; set;}
public string Key3 {get; set;}
public Request(string key1, string key2, string key3){
Key1 = key1;
Key2 = key2;
Key3 = key3;
}
}
}

View File

@ -35,7 +35,7 @@ Using the `create` command we can specify one of the available [templates](https
The `--path` or shorthand `-p` is the location to be created with the template service files. Change directories into this new folder.
## 2. Build using .NET CLI tools and create zip package
## 2. Build using .NET Core 2.X CLI tools and create zip package
```
# Linux or Mac OS

View File

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<AssemblyName>CsharpHandlers</AssemblyName>
<PackageId>csharp</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
<PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="1.6.0" />
</ItemGroup>
</Project>

View File

@ -1,85 +0,0 @@
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
# docs.serverless.com
#
# Happy Coding!
service: aws-csharp # NOTE: update this with your service name
# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"
provider:
name: aws
runtime: dotnetcore1.0
# you can overwrite defaults here
# stage: dev
# region: us-east-1
# you can add statements to the Lambda function's IAM Role here
# iamRoleStatements:
# - Effect: "Allow"
# Action:
# - "s3:ListBucket"
# Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] }
# - Effect: "Allow"
# Action:
# - "s3:PutObject"
# Resource:
# Fn::Join:
# - ""
# - - "arn:aws:s3:::"
# - "Ref" : "ServerlessDeploymentBucket"
# - "/*"
# you can define service wide environment variables here
# environment:
# variable1: value1
# you can add packaging information here
package:
artifact: bin/release/netcoreapp1.0/deploy-package.zip
# exclude:
# - exclude-me.js
# - exclude-me-dir/**
functions:
hello:
handler: CsharpHandlers::AwsDotnetCsharp.Handler::Hello
# The following are a few example events you can configure
# NOTE: Please make sure to change your handler code to work with those events
# Check the event documentation for details
# events:
# - http:
# path: users/create
# method: get
# - s3: ${env:BUCKET}
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# Define function environment variables here
# environment:
# variable2: value2
# you can add CloudFormation resource templates here
#resources:
# Resources:
# NewResource:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: my-new-bucket
# Outputs:
# NewOutput:
# Description: "Description for the output"
# Value: "Some output value"

View File

@ -5,6 +5,10 @@ description: Create a F# Hello World Lambda function
layout: Doc
-->
<!-- DOCS-SITE-LINK:START automatically generated -->
### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/aws/examples/hello-world/fsharp/)
<!-- DOCS-SITE-LINK:END -->
# Hello World F# Example
Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md).

View File

@ -30,7 +30,6 @@ You should also have [go](https://golang.org/doc/install) and [make](https://www
It is always good practice to organize your `go` projects within [GOPATH](https://golang.org/doc/code.html#GOPATH), to maximize the benefits of go tooling.
## 1. Create a service
There are two templates for `go`:
The Serverless Framework includes starter templates for various languages and providers. There are two templates for `go`.
@ -50,7 +49,7 @@ sls create --template aws-go --path myService
sls create --template aws-go-dep --path myService
```
Using the `create` command we can specify one of the available [templates](https://serverless.com/framework/docs/providers/aws/cli-reference/create#available-templates). For this example use aws-nodejs with the `--template` or shorthand `-t` flag.
Using the `create` command we can specify one of the available [templates](https://serverless.com/framework/docs/providers/aws/cli-reference/create#available-templates). For this example use aws-go-dep with the `--template` or shorthand `-t` flag.
The `--path` or shorthand `-p` is the location to be created with the template service files.

View File

@ -45,7 +45,17 @@ provider:
- "/*"
```
Alongside `provider.iamRoleStatements` managed policies can also be added to this service-wide Role, define managed policies in `provider.iamManagedPolicies`. These will also be merged into the generated IAM Role so you can use `Join`, `Ref` or any other CloudFormation method or feature here too.
```yml
service: new-service
provider:
name: aws
iamManagedPolicies:
- 'some:aws:arn:xxx:*:*'
- 'someOther:aws:arn:xxx:*:*'
- { 'Fn::Join': [':', ['arn:aws:iam:', { Ref: 'AWSAccountId' }, 'some/path']] }
```
## Custom IAM Roles
**WARNING:** You need to take care of the overall role setup as soon as you define custom roles.

View File

@ -62,6 +62,8 @@ provider:
rateLimit: 100
stackTags: # Optional CF stack tags
key: value
iamManagedPolicies: # Optional IAM Managed Policies, which allows to include the policies into IAM Role
- arn:aws:iam:*****:policy/some-managed-policy
iamRoleStatements: # IAM role statements so that services can be accessed in the AWS account
- Effect: 'Allow'
Action:
@ -103,6 +105,8 @@ package: # Optional deployment packaging configuration
- .git/**
- .travis.yml
excludeDevDependencies: false # Config if Serverless should automatically exclude dev dependencies in the deployment package. Defaults to true
artifact: path/to/my-artifact.zip # Own package that should be used. You must provide this file.
individually: true # Enables individual packaging for each function. If true you must provide package for each function. Defaults to false
functions:
@ -127,6 +131,15 @@ functions:
subnetIds:
- subnetId1
- subnetId2
package:
include: # Specify the directories and files which should be included in the deployment package for this specific function.
- src/**
- handler.js
exclude: # Specify the directories and files which should be excluded in the deployment package for this specific function.
- .git/**
- .travis.yml
artifact: path/to/my-artifact.zip # Own package that should be use for this specific function. You must provide this file.
individually: true # Enables individual packaging for specific function. If true you must provide package for each function. Defaults to false
events: # The Events that trigger this Function
- http: # This creates an API Gateway HTTP endpoint which can be used to trigger this function. Learn more in "events/apigateway"
path: users/create # Path for this endpoint

View File

@ -116,6 +116,7 @@ provider:
Action:
- Update:Replace
- Update:Delete
Resource: "*"
Condition:
StringEquals:
ResourceType:

View File

@ -78,7 +78,7 @@ functions: # Your "Functions"
x-azure-settings:
name: req
methods:
- POST
- post
route: /users/create
usersDelete:
events:
@ -86,7 +86,7 @@ functions: # Your "Functions"
x-azure-settings:
name: req
methods:
- DELETE
- delete
route: /users/delete
```

View File

@ -49,4 +49,4 @@ serverless logs -f hello
hello world!
```
You can install the Kubeless CLI tool following the [../guide/installation](installation guide).
You can install the Kubeless CLI tool following the [installation guide](../guide/installation.md).

View File

@ -2,6 +2,7 @@
/* eslint-disable no-use-before-define */
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
@ -9,6 +10,8 @@ const BbPromise = require('bluebird');
const filesize = require('filesize');
const normalizeFiles = require('../../lib/normalizeFiles');
const NUM_CONCURRENT_UPLOADS = 3;
module.exports = {
uploadArtifacts() {
return BbPromise.bind(this)
@ -76,36 +79,36 @@ module.exports = {
},
uploadFunctions() {
let shouldUploadService = false;
this.serverless.cli.log('Uploading artifacts...');
const functionNames = this.serverless.service.getAllFunctions();
return BbPromise.map(functionNames, (name) => {
const functionArtifactFileName = this.provider.naming.getFunctionArtifactName(name);
const functionObject = this.serverless.service.getFunction(name);
functionObject.package = functionObject.package || {};
let artifactFilePath = functionObject.package.artifact ||
this.serverless.service.package.artifact;
if (!artifactFilePath ||
(this.serverless.service.artifact && !functionObject.package.artifact)) {
if (this.serverless.service.package.individually || functionObject.package.individually) {
const artifactFileName = functionArtifactFileName;
artifactFilePath = path.join(this.packagePath, artifactFileName);
return this.uploadZipFile(artifactFilePath);
const artifactFilePaths = _.uniq(
_.map(functionNames, (name) => {
const functionArtifactFileName = this.provider.naming.getFunctionArtifactName(name);
const functionObject = this.serverless.service.getFunction(name);
functionObject.package = functionObject.package || {};
const artifactFilePath = functionObject.package.artifact ||
this.serverless.service.package.artifact;
if (!artifactFilePath ||
(this.serverless.service.artifact && !functionObject.package.artifact)) {
if (this.serverless.service.package.individually || functionObject.package.individually) {
const artifactFileName = functionArtifactFileName;
return path.join(this.packagePath, artifactFileName);
}
return this.provider.naming.getServiceArtifactName();
}
shouldUploadService = true;
return BbPromise.resolve();
}
return artifactFilePath;
})
);
return BbPromise.map(artifactFilePaths, (artifactFilePath) => {
const stats = fs.statSync(artifactFilePath);
this.serverless.cli.log(`Uploading service .zip file to S3 (${filesize(stats.size)})...`);
return this.uploadZipFile(artifactFilePath);
}, { concurrency: 3 }).then(() => {
if (shouldUploadService) {
const artifactFileName = this.provider.naming.getServiceArtifactName();
const artifactFilePath = path.join(this.packagePath, artifactFileName);
const stats = fs.statSync(artifactFilePath);
this.serverless.cli.log(`Uploading service .zip file to S3 (${filesize(stats.size)})...`);
return this.uploadZipFile(artifactFilePath);
}
return BbPromise.resolve();
});
}, { concurrency: NUM_CONCURRENT_UPLOADS }
);
},
};

View File

@ -225,19 +225,45 @@ describe('uploadArtifacts', () => {
});
describe('#uploadFunctions()', () => {
let uploadZipFileStub;
beforeEach(() => {
sinon.stub(fs, 'statSync').returns({ size: 1024 });
uploadZipFileStub = sinon.stub(awsDeploy, 'uploadZipFile').resolves();
});
afterEach(() => {
fs.statSync.restore();
uploadZipFileStub.restore();
});
it('should upload the service artifact file to the S3 bucket', () => {
awsDeploy.serverless.config.servicePath = 'some/path';
awsDeploy.serverless.service.service = 'new-service';
sinon.stub(fs, 'statSync').returns({ size: 0 });
return awsDeploy.uploadFunctions().then(() => {
expect(uploadZipFileStub.calledOnce).to.be.equal(true);
expect(uploadZipFileStub.args[0][0]).to.be.equal('new-service.zip');
});
});
const uploadZipFileStub = sinon
.stub(awsDeploy, 'uploadZipFile').resolves();
it('should upload a single .zip file to the S3 bucket when not packaging individually', () => {
awsDeploy.serverless.service.functions = {
first: {
package: {
artifact: 'artifact.zip',
},
},
second: {
package: {
artifact: 'artifact.zip',
},
},
};
return awsDeploy.uploadFunctions().then(() => {
expect(uploadZipFileStub.calledOnce).to.be.equal(true);
fs.statSync.restore();
awsDeploy.uploadZipFile.restore();
expect(uploadZipFileStub.args[0][0]).to.be.equal('artifact.zip');
});
});
@ -256,16 +282,12 @@ describe('uploadArtifacts', () => {
},
};
const uploadZipFileStub = sinon
.stub(awsDeploy, 'uploadZipFile').resolves();
return awsDeploy.uploadFunctions().then(() => {
expect(uploadZipFileStub.calledTwice).to.be.equal(true);
expect(uploadZipFileStub.args[0][0])
.to.be.equal(awsDeploy.serverless.service.functions.first.package.artifact);
expect(uploadZipFileStub.args[1][0])
.to.be.equal(awsDeploy.serverless.service.functions.second.package.artifact);
uploadZipFileStub.restore();
});
});
@ -284,19 +306,12 @@ describe('uploadArtifacts', () => {
},
};
const uploadZipFileStub = sinon
.stub(awsDeploy, 'uploadZipFile').resolves();
const statSyncStub = sinon.stub(fs, 'statSync').returns({ size: 1024 });
return awsDeploy.uploadFunctions().then(() => {
expect(uploadZipFileStub.calledTwice).to.be.equal(true);
expect(uploadZipFileStub.args[0][0])
.to.be.equal(awsDeploy.serverless.service.functions.first.package.artifact);
expect(uploadZipFileStub.args[1][0])
.to.be.equal(awsDeploy.serverless.service.package.artifact);
}).finally(() => {
uploadZipFileStub.restore();
statSyncStub.restore();
});
});
@ -304,16 +319,11 @@ describe('uploadArtifacts', () => {
awsDeploy.serverless.config.servicePath = 'some/path';
awsDeploy.serverless.service.service = 'new-service';
const statSyncStub = sinon.stub(fs, 'statSync').returns({ size: 1024 });
const uploadZipFileStub = sinon.stub(awsDeploy, 'uploadZipFile').resolves();
sinon.spy(awsDeploy.serverless.cli, 'log');
return awsDeploy.uploadFunctions().then(() => {
const expected = 'Uploading service .zip file to S3 (1 KB)...';
expect(awsDeploy.serverless.cli.log.calledWithExactly(expected)).to.be.equal(true);
}).finally(() => {
statSyncStub.restore();
uploadZipFileStub.restore();
});
});
});

View File

@ -7,6 +7,7 @@ const path = require('path');
module.exports = {
mergeIamTemplates() {
this.validateStatements(this.serverless.service.provider.iamRoleStatements);
this.validateManagedPolicies(this.serverless.service.provider.iamManagedPolicies);
return this.merge();
},
@ -120,6 +121,20 @@ module.exports = {
.Statement.concat(this.serverless.service.provider.iamRoleStatements);
}
if (this.serverless.service.provider.iamManagedPolicies) {
// add iam managed policies
const iamManagedPolicies = this.serverless.service.provider.iamManagedPolicies;
const resource = this.serverless.service.provider.compiledCloudFormationTemplate
.Resources[this.provider.naming.getRoleLogicalId()].Properties;
if (iamManagedPolicies.length > 0) {
if (!_.has(resource, 'ManagedPolicyArns') || _.isEmpty(resource.ManagedPolicyArns)) {
resource.ManagedPolicyArns = [];
}
resource.ManagedPolicyArns = resource.ManagedPolicyArns
.concat(iamManagedPolicies);
}
}
// check if one of the functions contains vpc configuration
const vpcConfigProvided = [];
this.serverless.service.getAllFunctions().forEach((functionName) => {
@ -173,4 +188,14 @@ module.exports = {
throw new this.serverless.classes.Error(errorMessage);
}
},
validateManagedPolicies(iamManagedPolicies) {
// Verify that iamManagedPolicies (if present) is an array
if (!iamManagedPolicies) {
return;
}
if (!_.isArray(iamManagedPolicies)) {
throw new this.serverless.classes.Error('iamManagedPolicies should be an array of arns');
}
},
};

View File

@ -155,6 +155,22 @@ describe('#mergeIamTemplates()', () => {
});
});
it('should add managed policy arns', () => {
awsPackage.serverless.service.provider.iamManagedPolicies = [
'some:aws:arn:xxx:*:*',
'someOther:aws:arn:xxx:*:*',
{ 'Fn::Join': [':', ['arn:aws:iam:', { Ref: 'AWSAccountId' }, 'some/path']] },
];
return awsPackage.mergeIamTemplates()
.then(() => {
expect(awsPackage.serverless.service.provider.compiledCloudFormationTemplate
.Resources[awsPackage.provider.naming.getRoleLogicalId()]
.Properties
.ManagedPolicyArns
).to.deep.equal(awsPackage.serverless.service.provider.iamManagedPolicies);
});
});
it('should throw error if custom IAM policy statements is not an array', () => {
awsPackage.serverless.service.provider.iamRoleStatements = {
policy: 'some_value',
@ -222,6 +238,12 @@ describe('#mergeIamTemplates()', () => {
.to.throw(/statement 0 is missing.*Resource; statement 2 is missing.*Effect, Action/);
});
it('should throw error if managed policies is not an array', () => {
awsPackage.serverless.service.provider.iamManagedPolicies = 'a string';
expect(() => awsPackage.mergeIamTemplates())
.to.throw('iamManagedPolicies should be an array of arns');
});
it('should add a CloudWatch LogGroup resource', () => {
const normalizedName = awsPackage.provider.naming.getLogGroupLogicalId(functionName);
return awsPackage.mergeIamTemplates().then(() => {

View File

@ -34,6 +34,7 @@ const validTemplates = [
'google-nodejs',
'kubeless-python',
'kubeless-nodejs',
'openwhisk-java-maven',
'openwhisk-nodejs',
'openwhisk-php',
'openwhisk-python',

View File

@ -143,7 +143,6 @@ describe('Create', () => {
expect(dirContent).to.include('aws-csharp.csproj');
expect(dirContent).to.include('build.cmd');
expect(dirContent).to.include('build.sh');
expect(dirContent).to.include('global.json');
});
});
@ -264,9 +263,9 @@ describe('Create', () => {
expect(dirContent).to.include('gradlew.bat');
expect(dirContent).to.include('package.json');
expect(dirContent).to.include(path.join('gradle', 'wrapper',
'gradle-wrapper.jar'));
'gradle-wrapper.jar'));
expect(dirContent).to.include(path.join('gradle', 'wrapper',
'gradle-wrapper.properties'));
'gradle-wrapper.properties'));
expect(dirContent).to.include(path.join('src', 'main', 'kotlin', 'com', 'serverless',
'Handler.kt'));
expect(dirContent).to.include(path.join('src', 'main', 'kotlin', 'com', 'serverless',
@ -291,17 +290,17 @@ describe('Create', () => {
expect(dirContent).to.include('gradlew');
expect(dirContent).to.include('gradlew.bat');
expect(dirContent).to.include(path.join('gradle', 'wrapper',
'gradle-wrapper.jar'));
'gradle-wrapper.jar'));
expect(dirContent).to.include(path.join('gradle', 'wrapper',
'gradle-wrapper.properties'));
'gradle-wrapper.properties'));
expect(dirContent).to.include(path.join('src', 'main', 'resources',
'log4j.properties'));
'log4j.properties'));
expect(dirContent).to.include(path.join('src', 'main', 'java',
'com', 'serverless', 'Handler.java'));
'com', 'serverless', 'Handler.java'));
expect(dirContent).to.include(path.join('src', 'main', 'java',
'com', 'serverless', 'ApiGatewayResponse.java'));
'com', 'serverless', 'ApiGatewayResponse.java'));
expect(dirContent).to.include(path.join('src', 'main', 'java',
'com', 'serverless', 'Response.java'));
'com', 'serverless', 'Response.java'));
expect(dirContent).to.include(path.join('.gitignore'));
});
});
@ -319,17 +318,17 @@ describe('Create', () => {
expect(dirContent).to.include('gradlew');
expect(dirContent).to.include('gradlew.bat');
expect(dirContent).to.include(path.join('gradle', 'wrapper',
'gradle-wrapper.jar'));
'gradle-wrapper.jar'));
expect(dirContent).to.include(path.join('gradle', 'wrapper',
'gradle-wrapper.properties'));
'gradle-wrapper.properties'));
expect(dirContent).to.include(path.join('src', 'main', 'resources',
'log4j.properties'));
'log4j.properties'));
expect(dirContent).to.include(path.join('src', 'main', 'groovy',
'com', 'serverless', 'Handler.groovy'));
'com', 'serverless', 'Handler.groovy'));
expect(dirContent).to.include(path.join('src', 'main', 'groovy',
'com', 'serverless', 'ApiGatewayResponse.groovy'));
'com', 'serverless', 'ApiGatewayResponse.groovy'));
expect(dirContent).to.include(path.join('src', 'main', 'groovy',
'com', 'serverless', 'Response.groovy'));
'com', 'serverless', 'Response.groovy'));
expect(dirContent).to.include('.gitignore');
});
});
@ -354,6 +353,23 @@ describe('Create', () => {
});
});
it('should generate scaffolding for "openwhisk-java-maven" template', () => {
process.chdir(tmpDir);
create.options.template = 'openwhisk-java-maven';
return create.create().then(() => {
const dirContent = walkDirSync(tmpDir)
.map(elem => elem.replace(path.join(tmpDir, path.sep), ''));
expect(dirContent).to.include('pom.xml');
expect(dirContent).to.include(path.join('src', 'main', 'java',
'com', 'example', 'FunctionApp.java'));
expect(dirContent).to.include(path.join('src', 'test', 'java',
'com', 'example', 'FunctionAppTest.java'));
expect(dirContent).to.include('.gitignore');
expect(dirContent).to.include('serverless.yml');
});
});
it('should generate scaffolding for "openwhisk-nodejs" template', () => {
process.chdir(tmpDir);
create.options.template = 'openwhisk-nodejs';
@ -509,7 +525,7 @@ describe('Create', () => {
expect(dirContent).to.include('serverless.yml');
expect(dirContent).to.include('pom.xml');
expect(dirContent).to.include(path.join('src', 'main', 'java',
'com', 'serverless', 'Handler.java'));
'com', 'serverless', 'Handler.java'));
expect(dirContent).to.include('.gitignore');
});
});
@ -608,7 +624,7 @@ describe('Create', () => {
});
it('should create a custom renamed service in the directory if using ' +
'the "path" and "name" option', () => {
'the "path" and "name" option', () => {
process.chdir(tmpDir);
create.options.path = 'my-new-service';
@ -640,7 +656,7 @@ describe('Create', () => {
create.options.template = 'aws-nodejs';
create.options.path = '';
create.serverless.utils.copyDirContentsSync(path.join(create.serverless.config.serverlessPath,
'plugins', 'create', 'templates', create.options.template), tmpDir);
'plugins', 'create', 'templates', create.options.template), tmpDir);
const dirContent = fs.readdirSync(tmpDir);
@ -749,7 +765,7 @@ describe('Create', () => {
return create.create().then(() => {
const dirContent = walkDirSync(tmpDir)
.map(elem => elem.replace(path.join(tmpDir, path.sep), ''));
.map(elem => elem.replace(path.join(tmpDir, path.sep), ''));
expect(dirContent).to.include('serverless.yml');
expect(dirContent).to.include(path.join('hello', 'main.go'));

View File

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<TargetFramework>netcoreapp2.0</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<AssemblyName>CsharpHandlers</AssemblyName>
<PackageId>aws-csharp</PackageId>
</PropertyGroup>
@ -12,7 +13,7 @@
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="1.6.0" />
<DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="2.0.1" />
</ItemGroup>
</Project>

View File

@ -1,2 +1,2 @@
dotnet restore
dotnet lambda package --configuration release --framework netcoreapp1.0 --output-package bin/release/netcoreapp1.0/deploy-package.zip
dotnet lambda package --configuration release --framework netcoreapp2.0 --output-package bin/release/netcoreapp2.0/deploy-package.zip

View File

@ -1,10 +1,11 @@
#!/bin/bash
#install zip
apt-get -qq update
apt-get -qq -y install zip
#install zip on debian OS, since microsoft/dotnet container doesn't have zip by default
if [ -f /etc/debian_version ]
then
apt -qq update
apt -qq -y install zip
fi
dotnet restore
#create deployment package
dotnet lambda package --configuration release --framework netcoreapp1.0 --output-package bin/release/netcoreapp1.0/deploy-package.zip
dotnet lambda package --configuration release --framework netcoreapp2.0 --output-package bin/release/netcoreapp2.0/deploy-package.zip

View File

@ -1,5 +0,0 @@
{
"sdk": {
"version": "1.0.4"
}
}

View File

@ -19,7 +19,7 @@ service: aws-csharp # NOTE: update this with your service name
provider:
name: aws
runtime: dotnetcore1.0
runtime: dotnetcore2.0
# you can overwrite defaults here
# stage: dev
@ -47,7 +47,7 @@ provider:
# you can add packaging information here
package:
artifact: bin/release/netcoreapp1.0/deploy-package.zip
artifact: bin/release/netcoreapp2.0/deploy-package.zip
# exclude:
# - exclude-me.js
# - exclude-me-dir/**

View File

@ -1,15 +1,11 @@
#!/bin/bash
isMacOs=`uname -a | grep Darwin`
#install zip
if [ -z "$isMacOs" ]
#install zip on debian OS, since microsoft/dotnet container doesn't have zip by default
if [ -f /etc/debian_version ]
then
apt-get -qq update
apt-get -qq -y install zip
apt -qq update
apt -qq -y install zip
fi
dotnet restore
#create deployment package
dotnet lambda package --configuration release --framework netcoreapp2.0 --output-package bin/release/netcoreapp2.0/deploy-package.zip

View File

@ -0,0 +1,8 @@
target
.vscode
.sts4-cache
.project
.classpath
.settings
*.iml
.idea

View File

@ -0,0 +1,47 @@
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo-function</artifactId>
<version>1.0-SNAPSHOT</version>
<url>https://openwhisk.apache.org/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<gson.version>2.8.2</gson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>demo-function</finalName>
<plugins>
<!-- This helps in packaging the function depeendencies as uber jar-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,49 @@
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
# docs.serverless.com
#
# Happy Coding!
service: openwhisk-java-maven # NOTE: update this with your service name
# Please ensure the serverless-openwhisk provider plugin is installed globally.
# $ npm install -g serverless-openwhisk
# ...before installing project dependencies to register this provider.
# $ npm install
provider:
name: openwhisk
runtime: java
# you can add packaging information here
package:
artifact: target/demo-function.jar
functions:
demo:
handler: com.example.FunctionApp
# extend the framework using plugins listed here:
# https://github.com/serverless/plugins
plugins:
- "serverless-openwhisk"
# you can define custom triggers and trigger feeds using the resources section.
#
#resources:
# triggers:
# my_trigger:
# parameters:
# hello: world
# alarm_trigger:
# parameters:
# hello: world
# feed: /whisk.system/alarms/alarm
# feed_parameters:
# cron: '*/8 * * * * *'

View File

@ -0,0 +1,31 @@
package com.example;
/*
* 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.
*/
import com.google.gson.JsonObject;
/**
* Hello FunctionApp
*/
public class FunctionApp {
public static JsonObject main(JsonObject args) {
JsonObject response = new JsonObject();
response.addProperty("greetings", "Hello! Welcome to OpenWhisk");
return response;
}
}

View File

@ -0,0 +1,39 @@
package com.example;
/*
* 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.
*/
import static org.junit.Assert.*;
import com.google.gson.JsonObject;
import org.junit.Test;
/**
* Unit test for simple function.
*/
public class FunctionAppTest {
@Test
public void testFunction() {
JsonObject args = new JsonObject();
JsonObject response = FunctionApp.main(args);
assertNotNull(response);
String greetings = response.getAsJsonPrimitive("greetings").getAsString();
assertNotNull(greetings);
assertEquals("Hello! Welcome to OpenWhisk", greetings);
}
}

View File

@ -8,7 +8,7 @@ function integration-test {
$DIR/integration-test-template $@
}
integration-test aws-csharp 'apt-get -qq update && apt-get -qq -y install zip && dotnet restore && dotnet lambda package --configuration release --framework netcoreapp1.0 --output-package bin/release/netcoreapp1.0/deploy-package.zip'
integration-test aws-csharp './build.sh'
integration-test aws-fsharp './build.sh'
integration-test aws-go 'cd /go/src/app && make build'
integration-test aws-go-dep 'cd /go/src/app && make build'