Status

Build Status

Features

This plugins adds Jenkins pipeline steps to interact with the AWS API.

see the changelog for release information

Primary/Agent setups

This plugin is not optimized to setups with a primary and multiple agents. Only steps that touch the workspace are executed on the agents while the rest is executed on the master.

For the best experience make sure that primary and agents have the same IAM permission and networking capabilities.

Usage / Steps

withAWS

the withAWS step provides authorization for the nested steps. You can provide region and profile information or let Jenkins assume a role in another or the same AWS account. You can mix all parameters in one withAWS block.

Set region information (note that region and endpointUrl are mutually exclusive):

withAWS(region:'eu-west-1') {
    // do something
}

Use provided endpointUrl (endpointUrl is optional, however, region and endpointUrl are mutually exclusive):

withAWS(endpointUrl:'https://minio.mycompany.com',credentials:'nameOfSystemCredentials',federatedUserId:"${submitter}@${releaseVersion}") {
    // do something
}

Use Jenkins UsernamePassword credentials information (Username: AccessKeyId, Password: SecretAccessKey):

withAWS(credentials:'IDofSystemCredentials') {
    // do something
}

Use Jenkins AWS credentials information (AWS Access Key: AccessKeyId, AWS Secret Key: SecretAccessKey):

withAWS(credentials:'IDofAwsCredentials') {
    // do something
}

Use profile information from ~/.aws/config:

withAWS(profile:'myProfile') {
    // do something
}

Assume role information (account is optional - uses current account as default. externalId, roleSessionName and policy are optional. duration is optional - if specified it represents the maximum amount of time in seconds the session may persist for, defaults to 3600.):

withAWS(role:'admin', roleAccount:'123456789012', externalId: 'my-external-id', policy: '{"Version":"2012-10-17","Statement":[{"Sid":"Stmt1","Effect":"Deny","Action":"s3:DeleteObject","Resource":"*"}]}', duration: 3600, roleSessionName: 'my-custom-session-name') {
    // do something
}

Assume federated user id information (federatedUserId is optional - if specified it generates a set of temporary credentials and allows you to push a federated user id into cloud trail for auditing. duration is optional - if specified it represents the maximum amount of time in seconds the session may persist for, defaults to 3600.):

withAWS(region:'eu-central-1',credentials:'nameOfSystemCredentials',federatedUserId:"${submitter}@${releaseVersion}", duration: 3600) {
    // do something
}

Authentication with a SAML assertion (fetched from your company IdP) by assuming a role

withAWS(role: 'myRole', roleAccount: '123456789', principalArn: 'arn:aws:iam::123456789:saml-provider/test', samlAssertion: 'base64SAML', region:'eu-west-1') {
  // do something
}

When you use Jenkins Declarative Pipelines you can also use withAWS in an options block:

options {
    withAWS(profile:'myProfile')
}
stages {
    ...
}

awsIdentity

Print current AWS identity information to the log.

The step returns an objects with the following fields:

def identity = awsIdentity()

cfInvalidate

Invalidate given paths in CloudFront distribution.

cfInvalidate(distribution:'someDistributionId', paths:['/*'])
cfInvalidate(distribution:'someDistributionId', paths:['/*'], waitForCompletion: true)

S3 Steps

All s3* steps take an optional pathStyleAccessEnabled and payloadSigningEnabled boolean parameter.

s3Upload(pathStyleAccessEnabled: true, payloadSigningEnabled: true, file:'file.txt', bucket:'my-bucket', path:'path/to/target/file.txt')
s3Copy(pathStyleAccessEnabled: true, fromBucket:'my-bucket', fromPath:'path/to/source/file.txt', toBucket:'other-bucket', toPath:'path/to/destination/file.txt')
s3Delete(pathStyleAccessEnabled: true, bucket:'my-bucket', path:'path/to/source/file.txt')
s3Download(pathStyleAccessEnabled: true, file:'file.txt', bucket:'my-bucket', path:'path/to/source/file.txt', force:true)
exists = s3DoesObjectExist(pathStyleAccessEnabled: true, bucket:'my-bucket', path:'path/to/source/file.txt')
files = s3FindFiles(pathStyleAccessEnabled: true, bucket:'my-bucket')

s3Upload

Upload a file/folder from the workspace (or a String) to an S3 bucket. If the file parameter denotes a directory, the complete directory including all subfolders will be uploaded.

s3Upload(file:'file.txt', bucket:'my-bucket', path:'path/to/target/file.txt')
s3Upload(file:'someFolder', bucket:'my-bucket', path:'path/to/targetFolder/')

Another way to use it is with include/exclude patterns which are applied in the specified subdirectory (workingDir). The option accepts a comma-separated list of patterns.

s3Upload(bucket:"my-bucket", path:'path/to/targetFolder/', includePathPattern:'**/*', workingDir:'dist', excludePathPattern:'**/*.svg,**/*.jpg')

Specific user metadatas can be added to uploaded files

s3Upload(bucket:"my-bucket", path:'path/to/targetFolder/', includePathPattern:'**/*.svg', workingDir:'dist', metadatas:['Key:SomeValue','Another:Value'])

Specific cachecontrol can be added to uploaded files

s3Upload(bucket:"my-bucket", path:'path/to/targetFolder/', includePathPattern:'**/*.svg', workingDir:'dist', cacheControl:'public,max-age=31536000')

Specific content encoding can be added to uploaded files

s3Upload(file:'file.txt', bucket:'my-bucket', contentEncoding: 'gzip')

Specific content type can be added to uploaded files

s3Upload(bucket:"my-bucket", path:'path/to/targetFolder/', includePathPattern:'**/*.ttf', workingDir:'dist', contentType:'application/x-font-ttf')

Canned ACLs can be added to upload requests.

s3Upload(file:'file.txt', bucket:'my-bucket', path:'path/to/target/file.txt', acl:'PublicRead')
s3Upload(file:'someFolder', bucket:'my-bucket', path:'path/to/targetFolder/', acl:'BucketOwnerFullControl')

A Server Side Encryption Algorithm can be added to upload requests.

s3Upload(file:'file.txt', bucket:'my-bucket', path:'path/to/target/file.txt', sseAlgorithm:'AES256')

A KMS alias or KMS id can be used to encrypt the uploaded file or directory at rest.

s3Upload(file: 'foo.txt', bucket: 'my-bucket', path: 'path/to/target/file.txt', kmsId: 'alias/foo')
s3Upload(file: 'foo.txt', bucket: 'my-bucket', path: 'path/to/target/file.txt', kmsId: '8e1d420d-bf94-4a15-a07a-8ad965abb30f')
s3upload(file: 'bar-dir', bucket: 'my-bucket', path: 'path/to/target', kmsId: 'alias/bar')

A redirect location can be added to uploaded files.

s3Upload(file: 'file.txt', bucket: 'my-bucket', redirectLocation: '/redirect')

Creating an S3 object by creating the file whose contents is the provided text argument.

s3Upload(path: 'file.txt', bucket: 'my-bucket', text: 'Some Text Content')
s3Upload(path: 'path/to/targetFolder/file.txt', bucket: 'my-bucket', text: 'Some Text Content')

Tags can be added to uploaded files.

s3Upload(file: 'file.txt', bucket: 'my-bucket', tags: '[tag1:value1, tag2:value2]')

def tags=[:]
tags["tag1"]="value1"
tags["tag2"]="value2"

s3Upload(file: 'file.txt', bucket: 'my-bucket', tags: tags.toString())

Log messages can be less verbose. Disable it when you feel the logs are excessive but you will lose the visibility of what files having been uploaded to S3.

s3Upload(path: 'source/path/', bucket: 'my-bucket', verbose: false)

s3Download

Download a file/folder from S3 to the local workspace. Set optional parameter force to true to overwrite existing file in workspace. If the path ends with a / the complete virtual directory will be downloaded.

s3Download(file:'file.txt', bucket:'my-bucket', path:'path/to/source/file.txt', force:true)
s3Download(file:'targetFolder/', bucket:'my-bucket', path:'path/to/sourceFolder/', force:true)

s3Copy

Copy file between S3 buckets.

s3Copy(fromBucket:'my-bucket', fromPath:'path/to/source/file.txt', toBucket:'other-bucket', toPath:'path/to/destination/file.txt')

s3Delete

Delete a file/folder from S3. If the path ends in a "/", then the path will be interpreted to be a folder, and all of its contents will be removed.

s3Delete(bucket:'my-bucket', path:'path/to/source/file.txt')
s3Delete(bucket:'my-bucket', path:'path/to/sourceFolder/')

s3DoesObjectExist

Check if object exists in S3 bucket.

exists = s3DoesObjectExist(bucket:'my-bucket', path:'path/to/source/file.txt')

s3FindFiles

This provides a way to query the files/folders in the S3 bucket, analogous to the findFiles step provided by "pipeline-utility-steps-plugin". If specified, the path limits the scope of the operation to that folder only. The glob parameter tells s3FindFiles what to look for. This can be a file name, a full path to a file, or a standard glob ("*", "*.ext", "path/**/file.ext", etc.).

If you do not specify path, then it will default to the root of the bucket. The path is assumed to be a folder; you do not need to end it with a "/", but it is okay if you do. The path property of the results will be relative to this value.

This works by enumerating every file/folder in the S3 bucket under path and then performing glob matching. When possible, you should use path to limit the search space for efficiency purposes.

If you do not specify glob, then it will default to "*".

By default, this will return both files and folders. To only return files, set the onlyFiles parameter to true.

files = s3FindFiles(bucket:'my-bucket')
files = s3FindFiles(bucket:'my-bucket', glob:'path/to/targetFolder/file.ext')
files = s3FindFiles(bucket:'my-bucket', path:'path/to/targetFolder/', glob:'file.ext')
files = s3FindFiles(bucket:'my-bucket', path:'path/to/targetFolder/', glob:'*.ext')
files = s3FindFiles(bucket:'my-bucket', path:'path/', glob:'**/file.ext')

s3FindFiles returns an array of FileWrapper objects exactly identical to those returned by findFiles.

Each FileWrapper object has the following properties:

When used in a string context, a FileWrapper object returns the value of its path property.

s3PresignURL

Will presign the bucket/key and return a url. Defaults to 1 minute duration, using GET.

def url = s3PresignURL(bucket: 'mybucket', key: 'mykey')

The duration can be overridden:

def url = s3PresignURL(bucket: 'mybucket', key: 'mykey', durationInSeconds: 300) //5 minutes

The method can also be overridden:

def url = s3PresignURL(bucket: 'mybucket', key: 'mykey', httpMethod: 'POST')

cfnValidate

Validates the given CloudFormation template.

def response = cfnValidate(file:'template.yaml')
echo "template description: ${response.description}"

cfnUpdate

Create or update the given CloudFormation stack using the given template from the workspace. You can specify an optional list of parameters, either as a key/value pair or a map. You can also specify a list of keepParams of parameters which will use the previous value on stack updates.

Using timeoutInMinutes you can specify the amount of time that can pass before the stack status becomes CREATE_FAILED and the stack gets rolled back. Due to limitations in the AWS API, this only applies to stack creation.

If you have many parameters you can specify a paramsFile containing the parameters. The format is either a standard JSON file like with the cli or a YAML file for the cfn-params command line utility.

Additionally you can specify a list of tags that are set on the stack and all resources created by CloudFormation.

The step returns the outputs of the stack as a map. It also contains special values prefixed with jenkins:

When cfnUpdate creates a stack and the creation fails, the stack is deleted instead of being left in a broken state.

To prevent running into rate limiting on the AWS API you can change the default polling interval of 1000 ms using the parameter pollIntervall. Using the value 0 disables event printing.

def outputs = cfnUpdate(stack:'my-stack', file:'template.yaml', params:['InstanceType=t2.nano'], keepParams:['Version'], timeoutInMinutes:10, tags:['TagName=Value'], notificationARNs:['arn:aws:sns:us-east-1:993852309656:topic'], pollInterval:1000)

or the parameters can be specified as a map:

def outputs = cfnUpdate(stack:'my-stack', file:'template.yaml', params:['InstanceType': 't2.nano'], keepParams:['Version'], timeoutInMinutes:10, tags:['TagName=Value'], notificationARNs:['arn:aws:sns:us-east-1:993852309656:topic'], pollInterval:1000)

Alternatively, you can specify a URL to a template on S3 (you'll need this if you hit the 51200 byte limit on template):

def outputs = cfnUpdate(stack:'my-stack', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml')

By default the cfnUpdate step creates a new stack if the specified stack does not exist, this behaviour can be overridden by passing create: 'false' as parameter :

def outputs = cfnUpdate(stack:'my-stack', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', create: 'false')

In above example if my-stack already exists it would be updated and if it doesnt exist no actions would be performed.

In a case where CloudFormation needs to use a different IAM Role for creating the stack than the one currently in effect, you can pass the complete Role ARN to be used as roleArn parameter. i.e:

def outputs = cfnUpdate(stack:'my-stack', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', roleArn: 'arn:aws:iam::123456789012:role/S3Access')

It's possible to override the behaviour of a stack when the creation fails by using "onFailure". Allowed values are DO_NOTHING, ROLLBACK, or DELETE Because the normal default value of ROLLBACK behaves strangely in a CI/CD environment. cfnUpdate uses DELETE as default.

def outputs = cfnUpdate(stack:'my-stack', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', onFailure:'DELETE')

You can specify rollback triggers for the stack update:

def outputs = cfnUpdate(stack:'my-stack', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', rollbackTimeoutInMinutes: 10, rollbackTriggers: ['AWS::CloudWatch::Alarm=arn:of:cloudwatch:alarm'])

When creating a stack, you can activate termination protection by using the enableTerminationProtection field:

def outputs = cfnUpdate(stack:'my-stack', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', enableTerminationProtection: true)

Note: When creating a stack, either file or url are required. When updating it, omitting both parameters will keep the stack's current template.

cfnDelete

Remove the given stack from CloudFormation.

To prevent running into rate limiting on the AWS API you can change the default polling interval of 1000 ms using the parameter pollIntervall. Using the value 0 disables event printing.

Note: When deleting a stack only 'stack' parameter is required.

cfnDelete(stack:'my-stack', pollInterval:1000, retainResources :['mylogicalid'], roleArn: 'my-arn', clientRequestToken: 'my-request-token')

cfnDescribe

The step returns the outputs of the stack as map.

def outputs = cfnDescribe(stack:'my-stack')

cfnExports

The step returns the global CloudFormation exports as map.

def globalExports = cfnExports()

cfnCreateChangeSet

Create a change set to update the given CloudFormation stack using the given template from the workspace. You can specify an optional list of parameters, either as a key/value pair or a map. You can also specify a list of keepParams of parameters which will use the previous value on stack updates.

If you have many parameters you can specify a paramsFile containing the parameters. The format is either a standard JSON file like with the cli or a YAML file for the cfn-params command line utility.

Additionally you can specify a list of tags that are set on the stack and all resources created by CloudFormation.

The step returns the outputs of the stack as a map. It also contains special values prefixed with jenkins:

To prevent running into rate limiting on the AWS API you can change the default polling interval of 1000 ms using the parameter pollIntervall. Using the value 0 disables event printing.

cfnCreateChangeSet(stack:'my-stack', changeSet:'my-change-set', file:'template.yaml', params:['InstanceType=t2.nano'], keepParams:['Version'], tags:['TagName=Value'], notificationARNs:['arn:aws:sns:us-east-1:993852309656:topic'], pollInterval:1000)

or the parameters can be specified as a map:

cfnCreateChangeSet(stack:'my-stack', changeSet:'my-change-set', file:'template.yaml', params:['InstanceType': 't2.nano'], keepParams:['Version'], tags:['TagName=Value'], notificationARNs:['arn:aws:sns:us-east-1:993852309656:topic'], pollInterval:1000)

Alternatively, you can specify a URL to a template on S3 (you'll need this if you hit the 51200 byte limit on template):

cfnCreateChangeSet(stack:'my-stack', changeSet:'my-change-set', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml')

or specify a raw template:

cfnCreateChangeSet(stack:'my-stack', changeSet:'my-change-set', template: 'my template body')

By default the cfnCreateChangeSet step creates a change set for creating a new stack if the specified stack does not exist, this behaviour can be overridden by passing create: 'false' as parameter :

cfnCreateChangeSet(stack:'my-stack', changeSet:'my-change-set', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', create: 'false')

In above example if my-stack already exists, a change set stack with change set will be created, and if it doesnt exist no actions would be performed.

In a case where CloudFormation needs to use a different IAM Role for creating or updating the stack than the one currently in effect, you can pass the complete Role ARN to be used as roleArn parameter. i.e:

cfnCreateChangeSet(stack:'my-stack', changeSet:'my-change-set', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', roleArn: 'arn:aws:iam::123456789012:role/S3Access')

You can specify rollback triggers for the stack update:

cfnCreateChangeSet(stack:'my-stack', changeSet:'my-change-set', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', rollbackTimeoutInMinutes: 10, rollbackTriggers: ['AWS::CloudWatch::Alarm=arn:of:cloudwatch:alarm'])

Note: When creating a change set for a non-existing stack, either file or url are required. When updating it, omitting both parameters will keep the stack's current template.

cfnExecuteChangeSet

Execute a previously created change set to create or update a CloudFormation stack. All the necessary information, like parameters and tags, were provided earlier when the change set was created.

To prevent running into rate limiting on the AWS API you can change the default polling interval of 1000 ms using the parameter pollIntervall. Using the value 0 disables event printing.

def outputs = cfnExecuteChangeSet(stack:'my-stack', changeSet:'my-change-set', pollInterval:1000)

cfnUpdateStackSet

Create a stack set. Similar options to cfnUpdate. Will monitor the resulting StackSet operation and will fail the build step if the operation does not complete successfully.

To prevent running into rate limiting on the AWS API you can change the default polling interval of 1000 ms using the parameter pollIntervall. Using the value 0 disables event printing.

  cfnUpdateStackSet(stackSet:'myStackSet', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml')

To set a custom administrator role ARN:

  cfnUpdateStackSet(stackSet:'myStackSet', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', administratorRoleArn: 'mycustomarn')

To set a operation preferences:

  cfnUpdateStackSet(stackSet:'myStackSet', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', operationPreferences: [failureToleranceCount: 5])

When the stack set gets really big, the recommendation from AWS is to batch the update requests. This option is not part of the AWS API, but is an implementation to facilitate updating a large stack set. To automatically batch via region (find all stack instances, group them by region, and submit each region separately): (

  cfnUpdateStackSet(stackSet:'myStackSet', url:'https://s3.amazonaws.com/my-templates-bucket/template.yaml', batchingOptions: [regions: true])

cfnDeleteStackSet

Deletes a stack set.

To prevent running into rate limiting on the AWS API you can change the default polling interval of 1000 ms using the parameter pollIntervall. Using the value 0 disables event printing.

  cfnDeleteStackSet(stackSet:'myStackSet')

snsPublish

Publishes a message to SNS. Note that the optional parameter messageAttributes is assuming string only values.

snsPublish(topicArn:'arn:aws:sns:us-east-1:123456789012:MyNewTopic', subject:'my subject', message:'this is your message', messageAttributes: ['k1': 'v1', 'k2': 'v2'])

deployAPI

Deploys an API Gateway definition to a stage.

deployAPI(api:'myApiId', stage:'Prod')

Additionally you can specify a description and stage variables.

deployAPI(api:'myApiId', stage:'Prod', description:"Build: ${env.BUILD_ID}", variables:['key=value'])

awaitDeploymentCompletion

Awaits for a CodeDeploy deployment to complete.

The step runs within the withAWS block and requires only one parameter:

Simple await:

awaitDeploymentCompletion('d-3GR0HQLDN')

Timed await:

timeout(time: 15, unit: 'MINUTES'){
    awaitDeploymentCompletion('d-3GR0HQLDN')
}

listAWSAccounts

Retrieves the list of all AWS accounts of the organization. This step can only be run in the master account.

The step returns an array of Account objects with the following fields:

def accounts = listAWSAccounts()

You can specify a parent id (Root, Orga unit) with the optional parameter parent

def accounts = listAWSAccounts('ou-1234-12345678')

updateIdP

Create or update a SAML identity provider with the given metadata document.

The step returns the ARN of the created identity provider.

def idp = updateIdP(name: 'nameToCreateOrUpdate', metadata: 'pathToMetadataFile')

updateTrustPolicy

Update the assume role trust policy of the given role using the provided file.

updateTrustPolicy(roleName: 'SomeRole', policyFile: 'path/to/somefile.json')

setAccountAlias

Create or update the AWS account alias.

setAccountAlias(name: 'awsAlias')

ecrDeleteImages

Delete images in a repository.

ecrDeleteImages(repositoryName: 'foo', imageIds: ['imageDigest': 'digest', 'imageTag': 'tag'])

ecrListImages

List images in a repository.

def images = ecrListImages(repositoryName: 'foo')

ecrLogin

Create login string to authenticate docker with the ECR.

The step returns the shell command to perform the login.

def login = ecrLogin()

For older versions of docker that need the email parameter use:

def login = ecrLogin(email:true)

It's also possible to specify AWS accounts to perform ECR login into:

def login = ecrLogin(registryIds: ['123456789', '987654321'])

ecrSetRepositoryPolicy

Sets the json policy document containing ECR permissions.

The step returns the object returned by the command.

def result = ecrSetRepositoryPolicy(registryId: 'my-registryId',
                                     repositoryName: 'my-repositoryName',
                                     policyText: 'json-policyText'
)
def policyFile ="${env.WORKSPACE}/policyText.json"
def policyText = readFile file: policyFile
def result = ecrSetRepositoryPolicy(registryId: 'my-registryId',
                                     repositoryName: 'my-repositoryName',
                                     policyText: policyText
)

invokeLambda

Invoke a Lambda function.

The step returns the object returned by the Lambda.

def result = invokeLambda(
    functionName: 'myLambdaFunction',
    payload: [ "key": "value", "anotherkey" : [ "another", "value"] ]
)

Alternatively payload and return value can be Strings instead of Objects:

String result = invokeLambda(
    functionName: 'myLambdaFunction',
    payloadAsString: '{"key": "value"}',
    returnValueAsString: true
)

lambdaCleanupVersions

Cleans up lambda function versions older than the daysAgo flag. The main use case around this is for tooling like AWS Serverless Application Model. It creates lambda functions, but marks them as DeletionPolicy: Retain so the versions are never deleted. Overtime, these unused versions will accumulate and the account/region might hit the limit for maximum storage of lambda functions.

lambdaCleanupVersions(
    functionName: 'myLambdaFunction',
    daysAgo: 14
)

To discover and delete all old versions of functions created by a AWS CloudFormation stack:

lambdaCleanupVersions(
    stackName: 'myStack',
    daysAgo: 14
)

ec2ShareAmi

Share an AMI image to one or more accounts

ec2ShareAmi(
    amiId: 'ami-23842',
    accountIds: [ "0123456789", "1234567890" ]
)

elbRegisterInstance

Registers a target to a Target Group.

elbRegisterInstance(
    targetGroupARN: 'arn:aws:elasticloadbalancing:us-west-2:123456789:targetgroup/my-load-balancer/123456789',
    instanceID: 'i-myid',
    port: 8080
)

elbDeregisterInstance

Deregisters a target from a Target Group.

elbDeregisterInstance(
    targetGroupARN: 'arn:aws:elasticloadbalancing:us-west-2:123456789:targetgroup/my-load-balancer/123456789',
    instanceID: 'i-myid',
    port: 8080
)

elbIsInstanceRegistered

Check if target has registered and healthy.

The step returns true or false.

elbIsInstanceRegistered(
    targetGroupARN: 'arn:aws:elasticloadbalancing:us-west-2:123456789:targetgroup/my-load-balancer/123456789',
    instanceID: 'i-myid',
    port: 8080
)

elbIsInstanceDeregistered

Check if target has completed removed from the Target Group.

The step returns true or false.

elbIsInstanceDeregistered(
    targetGroupARN: 'arn:aws:elasticloadbalancing:us-west-2:123456789:targetgroup/my-load-balancer/123456789',
    instanceID: 'i-myid',
    port: 8080
)

Changelog

current master

1.40

1.39

1.38

1.37

1.36

1.35

1.34 (use >= 1.35!!)

1.33

1.32

1.31

1.30 (use >= 1.31!!)

1.29

1.28

1.27

1.26

1.25

1.24

1.23

1.22

1.21

1.20

1.19 (use >= 1.20!!)

1.18

1.17 (use >= 1.18!!)

1.16

1.15

1.14

1.13

1.12

1.11

1.10

1.9

1.8

1.7

1.6

1.5

1.4

1.3

1.2

1.1

1.0