API Reference

Here you will find Attini implementation details. For a full-featured example of how to use Attini, see our internal integration test.

Subsections of API Reference

Attini Configuration

The Attini Framework will look for a file in your distributions root directory called attini-config.json, attini-config.yml or attini-config.yaml. Only one of these files is allowed.

This file is required, and it should at least contain a distributionName.

distributionName: String
distributionId: String
version: String
distributionTags:
  String: String
dependencies:
  - distributionName: String
    version: String
initDeployConfig:
  template: String
  stackName: String
  forceUpdate: Boolean
  tags:
    String: String
  variables:
    String:
      String: String
  parameters:
    String:
      String: String
package:
  container:
    image: String
    loginCommands:
      - String
    options:
      - String
  prePackage:
    commands:
      - String
  postPackage:
    commands:
      - String
{
  "distributionName": "String",
  "distributionId": "String",
  "version": "String",
  "distributionTags": {
    "String": "String"
  },
  "dependencies" : [
    {
      "distributionName" : "String",
      "version" : "String"
    }
  ],
  "initDeployConfig": {
    "template": "String",
    "stackName": "String",
    "forceUpdate": "Boolean",
    "tags":{
      "String": "String"
    },
    "variables": {
      "String": {
        "String": "String"
      }
    },
    "parameters": {
      "String": {
        "String": "String"
      }
    }
  },
  "package": {
    "container": {
      "image": "String",
      "loginCommands": [
        "String"
      ],
      "options": [
        "Sting"
      ]
    },
    "prePackage": {
      "commands": [
        "String"
      ]
    },
    "postPackage": {
      "commands": [
        "String"
      ]
    }
  }
}

distributionName

Type: String

Minimum 2 and maximum 128 characters. Allowed characters: “a-z”, “A-Z”, “0-9” and “-_.”.

If you don’t have a good name in mind, using your Git repository name is a good place to start. But this is not a requirement, sometimes a distribution consists of a combination of many Git repository’s and/or external resources, and sometimes it makes sense to split a repository up into many different distributions.

Required: Yes

distributionId

Type: String

Minimum 2 and maximum 128 characters. Allowed characters: “a-z”, “A-Z”,“0-9” and “-_.”.

We recommend automatically setting the distributionId using the package section in the attini-config (see example below). This will make it easy for you to use the same package logic on your local computer as you use on your build server. The Git commit id is a good value for the distributionId because it will be easy to see what code runs in your environments. It can also be a good idea to append a timestamp to the id so that you can re-build the same commit if needed.

If you need to mock anything for your local builds (like an environment variable), see the --environment-config-script flag in the attini distribution package command.

Default: Random GUID

Required: No

version

Type: String

A semantic version for your distribution.

The version is intended to be a human-readable and sequential value to identify your distribution. It’s different from the distributionId whose primary purpose is to be a unique identifier.

It’s recommended to configure the version for distributions that are intended for production. See the --distribution-version, -v flags in the attini distribution package command.

Required: No

distributionTags

Type: Map<String,String>

Metadata that is relevant to your organization or distribution, some normal use-cases include:

  • Keep track of Git branch that was the source of the distribution.
  • Build time.
  • Build agent/build container.
  • If your distribution consists of a combination of Git repositories, this is a good place to store the Git commit of those repositories.

See limitations

Required: No

dependencies

Type: List<Dependency>

A list of distributions that this distribution is dependent on. Attini will validate that the dependency is present in the environment. Attini will also include a URL to the dependencies output in the deployment plan payload (assuming it contains one).

Find more information here.

Required: No

initDeployConfig

Type: InitDeployConfig

Configuration for the Init Deploy.

Within this object, you can use distributionName and environment as sub-string parameters, see examples below.

Required: No

package

Type: Package

Under the package section, you can configure automation you want to execute when packaging a distribution using the attini distribution package command. The attini deploy run command will also perform a package assuming the path supplied points is to a directory.

The Attini CLI will create a temp working directory when packaging a distribution. Therefore, you can manipulate any resources without it affecting the original files.

The path to the temp directory will be stored in the ATTINI_WORK_DIR environment variable during the execution of package commands.

Required: No

Examples

Configuration examples

Simple example
Simple example
distributionName: network
distributionId: 3957876a98566823744050eef132c133536ea32b
distributionTags:
  branch: feature/add-nlb
{
  "distributionName": "network",
  "distributionId": "3957876a98566823744050eef132c133536ea32b",
  "distributionTags": {
    "Version": "1.1.2",
    "Branch": "feature/add-nlb"
  }
}
Full example
distributionName: platform
distributionId: 67e13cb77e9139929057602a46229cf0162c8747
version: 1.0.1
distributionTags:
  owner: carl
  branch: hotfix/bugfix
dependencies:
  - distributionName: infra
    version: ">1.0.0"
initDeployConfig:
  template: pipeline.yaml
  stackName: "${environment}-${distributionName}-init-deploy"
  variables:
    default:
      configPath: /my/default/config.json
    dev:
      configPath: /my/dev/config.json
  parameters:
    default:
      containerTag: latest
    dev:
      containerTag: 1.0.11
  tags:
    dev:
      costCenter: Development
    prod:
      costCenter: Sales
  package:
    container:
      image: 123424324422.dkr.ecr.eu-west-1.amazonaws.com/my-build-images:latest
      loginCommands:
        - export AWS_PROFILE=Shared
        - aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin 123424324422.dkr.ecr.eu-west-1.amazonaws.com
      options: # Here you add options for the docker run command.
        - -v $HOME/.aws:/root/.aws:rw # this command will copy your local aws credentials to the container (if the container runs as root).
    prePackage:
      commands:
        - echo $ATTINI_WORK_DIR
        - export AWS_PROFILE=MyProfile
        - attini configure set-dist-id --override --random
        - attini configure set-tag --key version --value echo `1.0.2`

    postPackage:
      commands:
        - echo "done with package"
{
  "distributionName": "platform",
  "distributionId": "67e13cb77e9139929057602a46229cf0162c8747",
  "version": "1.0.1",
  "distributionTags": {
    "owner": "carl",
    "branch": "hotfix/bugfix"
  },
  "dependencies" : [
    {
      "distributionName" : "String",
      "version" : "String"
    }
  ],
  "initDeployConfig": {
    "template": "pipeline.yaml",
    "stackName": "${environment}-${distributionName}-init-deploy",
    "variables": {
      "default": {
        "configPath": "/my/default/config.json"
      },
      "dev": {
        "configPath": "/my/dev/config.json"
      }
    },
    "parameters": {
      "default": {
        "containerTag": "latest"
      },
      "dev": {
        "containerTag": "1.0.11"
      }
    },
    "tags": {
      "dev": {
        "costCenter": "Development"
      },
      "prod": {
        "costCenter": "Sales"
      }
    }
  },
  "package": {
    "container": {
        "image": "123424324422.dkr.ecr.eu-west-1.amazonaws.com/my-build-images:latest",
        "loginCommands": [
          "export AWS_PROFILE=Shared",
          "aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin 123424324422.dkr.ecr.eu-west-1.amazonaws.com"
        ],
        "options": [
          "-v $HOME/.aws:/root/.aws:rw"
        ]
    },
    "prePackage": {
      "commands": [
        "echo $ATTINI_WORK_DIR",
        "export AWS_PROFILE=MyProfile",
        "attini configure set-dist-id --override --random",
        "attini configure set-tag --key version --value echo `1.0.2`"
      ]
    },
    "postPackage": {
      "commands": [
        "echo \"done with package\""
      ]
    }
  }
}

Examples with variables

If I’ve configured my variables in the attini-config like the example below.

initDeployConfig:
  variables:
    default:
      myConfigDirectory: defaultConfigDirectory
      stackNamePrefix: sandbox
    dev:
      myConfigDirectory: devConfigDirectory
      stackNamePrefix: dev

The following will resolve to a valid AttiniCfn configuration file.

extends: ${myConfigDirectory}/file.yaml
parameters:
  ParameterKey: ParameterValue
tags:
  Key: Value

The following will also be a valid AttiniCfn step.

StepName:
  Type: AttiniCfn
  Properties:
    StackName: ${stackNamePrefix}-hello-world-lambda
    Template: /lambda.yaml

If you want to combine AWS CloudFormation Fn::Sub with Attini variables, the following syntax will work.

StepName:
  Type: AttiniCfn
  Properties:
    StackName:
      Fn::Sub:
        - ${AttiniVariable}-${CloudFormationParameter}-hello-world-lambda
        - AttiniVariable: ${stackNamePrefix}
          CloudFormationParameter: !Ref Parameter # this assumes that there is a CloudFormation Parameter called "Parameter"
    Template: /lambda.yaml

Subsections of Attini Configuration

Dependency

Find more information here.

distributionName: String
version: String
{
  "distributionName" : "String",
  "version" : "String"
}

distributionName

Type: String

A name of a distribution the current distribution is dependent on.

Required: Yes

version

Type: String

The version of the dependency. Specified using the same rules as NPM.

This can be used to make sure that all dependencies have the correct versions.

Required: No

Init Deploy Config

template: String
stackName: String
forceUpdate: Boolean
tags:
  String: String
variables:
  String:
    String: String
parameters:
  String:
    String: String | import
{
  "template": "String",
  "stackName": "String",
  "forceUpdate": "Boolean",
  "tags":{
    "String": "String"
  },
  "variables": {
    "String": {
      "String": "String"
    }
  },
  "parameters": {
    "String": {
      "String": "String" | "import"
    }
  }
}

template

Type: String

The path to the init deploy template.

Required: No

stackName

Type: String

Init deploy stack name.

Required: No

forceUpdate

Type: Boolean

If true then the init-stack will always update, even if there is no change.

Default: false

Required: No

tags

Type: Map<String,String>

Init deploy stack tags.

Required: No

variables

Type: Map<String,Map<String,String>>

Global variables for the init deploy stack. Will be passed as variables to every AttiniCfn step in the deployment plan. The key should be an environment name (dev, stage, prod, etc) or default.

Anything under default will be used only if the variable is not configured for the current environment.

How are variables different from parameters?

Variables only work within the context of AttiniCfn and its associated configuration files. If you specify Variables with the same keys in a AttiniCfn step, it will override variables in the attini-config.

Parameters are normal AWS CloudFormation parameters to the init deploy stack

Within initDeployConfig in your attini-config file there are a few variables that are always available.

environment

Will always transform to the current environment name.

Usage: ${environment}

distributionName

Will always convert to the current distributionName name.

Usage: ${distributionName}

See examples with variables.

Required: No

parameters

Type: Map<String,Map<String,String>> | Map<String,Map<String,Import>>

Parameters for the init deploy stack, the top level key key is the environment name (dev, stage, prod, etc) or default.

Anything under default will be used only if the parameter is not configured for the current environment.

Under each environment, you can configure a key-value map, where the key is the parameters name.

If your distribution has a dependency on another distribution, then you can import values directly from its output.

Example
initDeployConfig:
  parameters:
    default:
      lambdaRam: 512
      vpcId:
        sourceType: Distribution
        source:
          name: network
          mapping: $.vpc.vpcId
    dev:
      lambdaRam: 1028
    prod:
      lambdaRam: 1540

Required: No

Examples with variables

If I have configured my variables in the attini-config like the example below.

initDeployConfig:
  variables:
    default:
      myConfigDirectory: defaultConfigDirectory
      stackNamePrefix: sandbox
    dev:
      myConfigDirectory: devConfigDirectory
      stackNamePrefix: dev

The following will resolve to a valid AttiniCfn configuration file.

extends: ${myConfigDirectory}/file.yaml
parameters:
  ParameterKey: ParameterValue
tags:
  Key: Value

The following will also be a valid AttiniCfn step.

StepName:
  Type: AttiniCfn
  Properties:
    StackName: ${stackNamePrefix}-hello-world-lambda
    Template: /lambda.yaml

If you want to combine AWS CloudFormation Fn::Sub with Attini variables, the following syntax will work.

StepName:
  Type: AttiniCfn
  Properties:
    StackName:
      Fn::Sub:
        - ${AttiniVariable}-${CloudFormationParameter}-hello-world-lambda
        - AttiniVariable: ${stackNamePrefix}
          CloudFormationParameter: !Ref Parameter # this assumes that there is a CloudFormation Parameter called "Parameter"
    Template: /lambda.yaml

Subsections of Init Deploy Config

Import

sourceType: String
source: source
{
  "sourceType": "String",
  "source": "source"
}

sourceType

Type: String

Only supported value is Distribution

Required: Yes

source

Type: source

The distribution name that you want to import the value from.

Required: Yes

Subsections of Import

Source

name: String
mapping: String
{
  "name": "String",
  "mapping": "String"
}

name

Type: String

The distribution name that you want to import the value from.

Required: Yes

mapping

Type: String

The path to the value you want to import. The path follows the JSONPath syntax.

Hint

Run command attini deploy output with the Attini CLI to see a distributions output.

Required: Yes

Package

container:
  image: String
  loginCommands:
    - String
  options:
    - String
prePackage:
  commands:
    - String
postPackage:
  commands:
    - String
{
  "container": {
    "image": "String",
    "loginCommands": [
      "String"
    ],
    "options": [
      "String"
    ]
  },
  "prePackage": {
    "commands": [
      "String"
    ]
  },
  "postPackage": {
    "commands": [
      "String"
    ]
  }
}

container

Type: Container

Configure this if you want to package your distribution using a container.

Required: No

prePackage

Type: PrePackage

Instructions that will be executed after the source files are copied to a temporary directory, but before the files are pacadged into a distribution.

Required: No

postPackage

Type: List<String>

List of shell commands that is executed before the final distribution is created but before the final distribution is copied from the temp working directory.

Useful if you for example want to move the distribution somewhere after the packaging is done.

Required: No

Subsections of Package

Container

image: String
loginCommands:
  - String
options:
  - String
{
  "image": "String",
  "loginCommands": [
    "String"
  ],
  "options": [
    "String"
  ]
}

image

Type: String

An image URI which will be used to fetch a container for packaging your distribution.

Useful if you, for example, want to build your distribution locally inside a container that mimics your build server.

Note

For this configuration to take effect you need to apply the --container-build or -cb flag to the attini distribution package (or attini deploy run) command.

Required: No

loginCommands

Type: List<String>

List of shell commands that will be executed before the docker run command when using container builds.

Should only be used to log in to the image repository if the image needs to be downloaded as they are executed before the container is started.

Note

For this configuration to take effect, you need to apply the --container-repository-login or -crl flag to the attini distribution package (or attini deploy run) command.

Required: No

options

Type: List<String>

Command-line options you want to add the docker run command the Attini CLI generates and run for you.

Useful if you need to configure anything specific for your build container, for example, if you need to transfer AWS credentials to the container (-v $HOME/.aws:/root/.aws:rw).

Required: No

Post Package

commands:
  - String
{
  "commands": [
    "String"
  ]
}

postPackage

Type: List<String>

List of shell commands that is executed after the final distribution is created.

Useful if you, for example, want to move the distribution somewhere after the packaging is done.

Required: No

Pre Package

commands:
  - String
{
  "commands": [
    "String"
  ]
}

commands

Type: List<String> List of shell commands that are executed before distribution is created.

These commands are run with set -eo pipefail configuration so that the packaging will fail quickly if an error occurs. To revert this configuration (and ignore errors in your scrips), begin your commands with the line: set +eo pipefail.

Useful if you, for example, want to configure the distribution (see attini configure command) or fetch external resources to be included in the distribution.

Required: Yes

Attini Deployment Plan

The Attini deployment plan is an abstraction on the AWS::Serverless::StateMachine CloudFormation resource. It also extends the StateMachine with features that make it an excellent deployment orchestrator. It integrates with the deployment source files, the Attini CLI, and supports the Attini State Types.

You can define your deployment plan in a programming language using the Attini CDK Constructs.

The deployment plan can ONLY be created in the Attini init deploy stack.

The deployment plan template requires the following Transform configuration:

AWSTemplateFormatVersion: "2010-09-09"
Transform:
  - AttiniDeploymentPlan
  - AWS::Serverless-2016-10-31

Attini::Deploy::DeploymentPlan

Type: Attini::Deploy::DeploymentPlan
Properties:
  DefinitionSubstitutions: Map
  PayloadDefaults: Map
  RoleArn: String
  Policies: String | List | Map
  PermissionsBoundary: String
  Tags: Map<String,String>
  DefaultRunner: String
  DeploymentPlan: DeploymentPlan Definition

DefinitionSubstitutions

Type: Map<String,String|Map>

AWS SAM compatibility: This property is passed directly to the DefinitionSubstitutions property of an AWS::Serverless::StateMachine resource.

This is useful if you want to use AWS CloudFormations Condition functions when you build your deployment plan. This can also be used for Intrinsic functions but most of them (ex Fn::Sub and Ref) can also be written straight in the deployment plan.

Required: No

PayloadDefaults

Type: Map<String,String|Map>

A method to create initial default values for the deployment payload.

These default values can be used to avoid runtime errors when reading missing values from the payload.

The PayloadDefaults currently only work in the “output” section of the payload.

Example
Properties:
  PayloadDefaults:
    output:
      MyStepName:
        MyOutput: "MyValue"

This value can be referenced in DeploymentPlan with the JSON string: $.output.MyStepName.MyOutput.

MyValue can be overwritten by a step called MyStepName if it outputs a key called MyOutput.

Required: No

RoleArn

Type: String

AWS SAM compatibility: This property is passed directly to the Role property of an AWS::Serverless::StateMachine resource.

You provide either a RoleArn or Policies.

Default: arn:aws:iam::{Account}:role/attini/attini-deployment-plan-default-states-service-role-{Region}

Required: Conditional

Info

If the parameter CreateDeploymentPlanDefaultRole on the attini-setup CloudFormation stack is false, then this is or Policies required.

Policies

Type: String | List | Map

AWS SAM compatibility: This property is passed directly to the Policies property of an AWS::Serverless::StateMachine resource.

You provide either a RoleArn or Policies.

Required: Conditional

Info

If the parameter CreateDeploymentPlanDefaultRole on the attini-setup CloudFormation stack is false, then this is or RoleArn required.

PermissionsBoundary

Type: String

AWS SAM compatibility: This property is passed directly to the PermissionsBoundary property of an AWS::Serverless::StateMachine resource.

This will only work if you create the IAM Role using the Policies configuration.

Required: No

Tags

Type: Map<String,String>

AWS SAM compatibility: This property is passed directly to the Tags property of an AWS::Serverless::StateMachine resource.

Required: No

DefaultRunner

Type: String

Override Attini’s default runner.

Note

If this is configured, it will be used for all deployment plan types which are built on-top of the Attini runner like AttiniCfn and AttiniSam. So you have to make sure that all the required software is installed on the docker image you configure.

Required: No

DeploymentPlan

Type: DeploymentPlan Definition

You can define your deployment plan in different 2 ways:

  1. Simplified syntax (List)
  2. Amazon state language (Map)

Required: Yes

Transformed resources

A Attini::Deploy::DeploymentPlan resource transforms into multiple CloudFormation resources that together create your deployment plan.

In this example, you can see how the transformed template will look.

Original template
AWSTemplateFormatVersion: "2010-09-09"
Transform:
  - AttiniDeploymentPlan
  - AWS::Serverless-2016-10-31

Resources:
  PublicWebsite:
    Type: Attini::Deploy::DeploymentPlan
    Properties:
      DeploymentPlan:
        ...

Outputs:
  DeploymentSfnPlanArn:
    Description: The arn of the StepFunction generated by PublicWebsite
    Value: !Ref AttiniDeploymentPlanSfnPublicWebsite
Transformed template
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "AttiniDeploymentPlanSfnTriggerPublicWebsite": {
      "Type": "Custom::AttiniDeploymentPlanTrigger",
      "Properties": {
        "...": "..."
      }
    },
    "AttiniDeploymentPlanSfnPublicWebsite": {
      "Type": "AWS::StepFunctions::StateMachine",
      "Properties": {
        "...": "..."
      }
    },
    "AttiniPostExecutionActionsPublicWebsite": {
      "Type": "AWS::Events::Rule",
      "Properties": {
        "...": "..."
      }
    }
  },
  "Outputs": {
    "DeploymentSfnPlanArn": {
      "Description": "The arn of the StepFunction generated by PublicWebsite deployment plan",
      "Value": {
        "Ref": "AttiniDeploymentPlanSfnPublicWebsite"
      }
    }
  }
}

Subsections of Attini Deployment Plan

Definition

The DeploymentPlan Definition is an abstraction of AWS::Serverless::StateMachine and it supports Attini types and StepFunctions native Tasks like Optimized integrations for Step Functions and AWS SDK service integrations.

The DeploymentPlan Definition has the same CloudFormation limitations as the AWS::Serverless::StateMachine Definition.

You can write your DeploymentPlan Definition using Attini simplified syntax or Amazon state language

Subsections of Definition

Amazon State Language

A definition using Amazon state language that describes your deployment.

In addition to the Amazon state language types, the deployment plan can also use the Attini types.

This definition converts to a AWS State Machine Definition.

DeploymentPlan:
  StartAt: StateName
  States:
    StateName:
      Type: String
      # Optional configuration based on State Type
      Next: String
      End: Boolean

StartAt

Type: String

The step that the deployment plan should start with. This is the same as the StartAt property in the Amazon States Language

Required: Yes

States

Type: Map<Sting,Map>

This is the same as the States property in the Amazon States Language after the Attini-specific resources (ex AttiniCfn) have been converted into a valid Amazon States Language definition.

Make sure that the actions that you specify here are allowed by the deployment plan Role.

This map has limited support for CloudFormation functions.

  • Simple functions like Ref, Fn::GetAtt and Fn::Sub work like normal CloudFormation.
  • Complex functions like Fn::Join will need to use the DefinitionSubstitutions property.
  • Conditions are not supported. You can often work around this limitation using logic in your definition, example by using the Choice state.

Required: Yes

Type

Type: String

Any valid State type like Attini types, StateMachine Task, or other StateMachine States like Pass, Wait, Succeed, Fail, Choice or Parallel.

Next

Type: String

Name of the next step.

Required: Yes, if End is not configured

End

Type: Boolean

Marks the end of a branch execution.

Required: Yes, if End is not configured

Example
DeploymentPlan:
  StartAt: ManualApproval
  States:
    ManualApproval:
      Type: AttiniManualApproval
      Next: MyDatabaseStack

    MyDatabaseStack:
      Type: AttiniCfn
      Properties:
        StackName: database
        Template: /database.yaml
      End: True

Simplified Syntax

Attini simplified syntax lets you define your deployment plan using a List instead of Amazon state language. The steps will be executed in the order of the list.

In addition to a simple list of States, the simplified syntax also supports Parallel and Choice.

DeploymentPlan:
  - Name: String
    Type: String
    # Optional configuration based on State Type

Name

Type: String

Name of the State. This has to be unique within the deployment plan.

Type

Type: String

Any valid State type like Attini type, StateMachine Task, or other StateMachine States like Pass, Wait, Succeed and Fail.

Parallel and Choice are supported but have their own simplified syntax.

Example
DeploymentPlan:
  - Name: ManualApproval
    Type: AttiniManualApproval

  - Name: MyDatabaseStack
    Type: AttiniCfn
    Properties:
      StackName: database
      Template: /database.yaml

Parallel

This is a simplified syntax for the Parallel State.

The Parallel State outputs a list of the outputs from all its branches, therefore, it’s often desirable to use the AttiniMergeOutput Type after the Parallel State. This is done automatically when using the simplified syntax, assuming that the merge step has not been added manually.

DeploymentPlan:
  - Name: String
    Type: Parallel
    Branches: 
      - Name: String
        Type: String
Example
DeploymentPlan:
  - Name: MyParallelName
    Type: Parallel
    Branches:
      -
        - Name: Step_1_in_branch_1
          Type: AttiniLambdaInvoke
          Parameters:
            FunctionName: my-function
        - Name: Step_2_in_branch_1
          Type: AttiniSam
          Properties:
            Project:
              Path: /my-sam-app/
            StackName: my-sam-stack
      -
        - Name: Step_1_in_branch_2
          Type: AttiniRunnerJob
          Commands:
            - echo "hello world"

Choice

The Choice step will help you make choices depending on a condition. The condition can be based on data in the payload or CloudFormation configuration.

The simplified Choice differs from Amazon state language choice because the simplified syntax only allows for one comparison, while Amazon state language choice can have multiple.

DeploymentPlan:
  - Name: String
    Type: Choice
    Condition:
      Comparison
    IsTrue:
      - List<State>
    IsFalse:
      - List<State>

Condition

Type: Comparison

This Comparison is a direct translation for Amazon state language choice but without “Next”.

Required: Yes

IsTrue

Type: List<State>

A List of States that will be executed if the Condition is true.

Required: Yes

IsFalse

Type: List<State>

A List of States that will be executed if the Condition is false.

If IsFalse is omitted, the deployment will continue to the next step if the Condition is false (or end if it is the last step).

Required: No

Example
DeploymentPlan:
  - Name: IsDev?
    Type: Choice
    Condition:
      Variable: $.deploymentOriginData.environment
      StringEquals: dev
    IsTrue:
      - Name: RunLoadtest
        Type: AttiniRunnerJob
        Commands:
          - autocannon --amount 100 --connections 1 --connectionRate 10 --renderStatusCodes --bailout 1 https://my-site.com

Payload

When the deployment plan is executed, the Attini Framework will create a payload with a specific data structure that has to be respected for to the Attini types to function.

{
  "output": {
    "deploymentPlanStepName1": {
      "outputName": "String"
    },
    "deploymentPlanStepName2": {
      "outputPath": {
        "outputName": "String"
      }
    }
  },
  "environment": "String",
  "stackParameters": {
    "String": "String"
  },
  "customData": {},
  "deploymentOriginData": {
    "distributionName": "String",
    "deploymentTime": "epochTime",
    "deploymentSource": {
      "deploymentSourcePrefix": "String",
      "deploymentSourceBucket": "String"
    },
    "environment": "String",
    "distributionId": "String",
    "deploymentName": "String",
    "objectIdentifier": "String",
    "stackName": "String",
    "distributionTags": {
      "String": "String"
    },
    "version": "SemanticVersion",
    "samPackaged": "boolean"
  },
  "dependencies": {
    "distributionName": {
        "deploymentSourcePrefix": "String"
    }
  }
}

output

Type: Map<Map<String,String>> || Map<Map<Map<String,String>>>

This object contains outputs from previous steps. The first key under output references the State name of a previous step.

In simple scenarios, for example an AttiniCfn step, this section will just contain a key: value map from a CloudFormation stack output.

In more complex scenarios, for example when AttiniCdk step deploys multiple CloudFormation stacks, you might need an extra level in the output data structure to separate between different stacks.

environment

Type: String

The current environment.

stackParameters

Type: Map<String,String>>

The parameters for the Init Deploy stack.

customData

Type: Map<String,Map<>>

Under this field, you can add whatever data you need and the Attini Framework resources will pass it along. If data is given to the deployment plan state machine input, the input will end up under this field.

deploymentOriginData

Type: DeploymentOriginData

This object contains information about the deployment origin data.

dependencies

Type: Map<String,Map<String,String>>

If your distribution has a dependency, this data will tell you where to find the output from your dependency’s latest successful deployment.

Subsections of Payload

DeploymentOriginData

{
  "deploymentOriginData": {
    "distributionName": "String",
    "deploymentTime": "epochTime",
    "deploymentSource": {
      "deploymentSourcePrefix": "String",
      "deploymentSourceBucket": "String"
    },
    "environment": "String",
    "distributionId": "String",
    "deploymentName": "String",
    "objectIdentifier": "String",
    "stackName": "String",
    "distributionTags": {
      "String": "String"
    },
    "version": "SemanticVersion",
    "samPackaged": "boolean"
  }
}

distributionName

Type: String

The distribution name.

deploymentTime

Type: String

The time in epoch milliseconds that the Attini distribution was deployed to this environment.

deploymentSource

Type: deploymentSource

A Map containing data needed to find artifacts related to this deployment.

environment

Type: String

The current environment.

distributionId

Type: String

The distribution id.

deploymentName
Type: String An AWS Account and Region unique name for the deployment in the format {environment}-{distributionName}.

objectIdentifier

Type: String

The S3 key for the S3 object key and version (distribution) that triggered the deployment.

stackName

Type: String

The name of the Init Deploy CloudFormation stack name.

distributionTags

Type: Map<String,String>

The distribution tags from attini-config.

version

Type: String

The distribution semantic version.

samPackaged

Type: Boolean

If this is true, Attini has done a SAM Package due to a AttiniSam step in the deployment plan.

Subsections of DeploymentOriginData

DeploymentSource

{
  "deploymentSource": {
    "deploymentSourcePrefix": "String",
    "deploymentSourceBucket": "String"
  }
}

deploymentSourcePrefix

Type: String

The s3 bucket prefix for the distribution files, find more info here.

deploymentSourceBucket

Type: String

The s3 bucket for the distribution files, find more info info here.

Types

The deployment plan is built on AWS StepFunction and follows the format of AWS State Language. That means that any State Types supported by StepFunction are also supported in the deployment plan. However, Attini also supports some additional types in order to better support a deployment workflow.

Subsections of Types

AttiniCdk

To simplify deployments of AWS CDK Projects Attini provides the AttiniCdk type.

AttiniCdk uses the CDK CLI on an Attini runner job to perform the deployment, so you can optionally configure your own AWS IAM Role and container image. This way your deployment can follow the principle of least privilege and use any software versions you need.

AttiniCdk will register all the CDK stacks with Attini, so that your CDK stacks will be taken into consideration by the attini ops rogue-stacks report.

Because the AttiniCdk uses the CDK CLI to do the deployment, most configuration options will map to a CDK CLI option. If the configuration is omitted, the CDK CLI default behavior will apply, unless otherwise specified in the docs.

Non-default behavior
  1. --require-approval never will be used because the standard approval makes no sense when the deployment isn’t executed from your local workstation. If you want manual approval for changes, please follow this guide.
  2. --progress events will be used.
Type: AttiniCdk
Properties:
    Runner: String
    Path: String
    App: String
    Diff:
        Enabled: Boolean
    Environment: Map<String,String>
    Stacks: List<String>
    Context: Map<String,String>
    Plugins: List<String>
    StackConfiguration: List<CdkParameters>
    Build: String
    BuildExclude: List<String>
    Exclusively: Boolean
    NotificationArns: List<String>
    Force: Boolean
    RoleArn: String

Runner

Type: String

Reference a Attini::Deploy::Runner recourse, find more information here.

Required: No

Path

Type: String

Location of your CDK project directory inside your Attini distribution.

Required: Yes

App

Type: String

This property is passed to the --app option in the CDK CLI.

If your project has a cdk.json file with the "app" property configured, this is not needed.

Required: No

Diff

Type: Diff

Required: No

Environment

Type: Map<String,String>

This property lets you set environment variables on the container that will deploy the CDK project. This way, the CDK project can get data from the deployment plan payload.

Your code can access these environment variables directly, via the Context configuration, or the StackConfiguration (parameters).

Example
Type: AttiniCdk
Properties:
    Path: my-app
    Environment:
      ENV.$: $.environment
      VPC_ID.$: $.output.vpc.id

Required: No

Stacks

Type: List<String>

The Stacks in your CDK project to deploy. If omitted, the --all option in the CDK CLI will be used.

Required: No

Default: All

Context

Type: Map<String,String>

This property is passed to the --context option in the CDK CLI.

Example
Type: AttiniCdk
Properties:
    Path: my-app
    Context:
      vpd_id: $.output.vpc.id

Required: No

Plugins

Type: List<String>

This property is passed to the --plugin option in the CDK CLI.

Required: No

StackConfiguration

Type: List<CdkParameters>

This property is passed to the --parameters option in the CDK CLI.

Required: No

Build

Type: String

This property is passed to the --build option in the CDK CLI.

Example
Type: AttiniCdk
Properties:
    Path: my-app
    Build: |
      echo "My build commands"
      npm install      

Required: No

BuildExclude

Type: List<String>

This property is passed to the --build-exclude option in the CDK CLI.

Required: No

NotificationArns

Type: List<String>

This property is passed to the --notification-arns option in the CDK CLI.

Required: No

Force

Type: Boolean

This property is passed to the --force option in the CDK CLI.

Required: No

RoleArn

Type: String

This property is passed to the --role-arn option in the CDK CLI.

Required: No

Subsections of AttiniCdk

CdkParameters

StackConfiguration:
    - StackName: String
      Parameters: Map<String,String>

StackName

Type: String

The stack that the parameter should be applied to, this is only required if the CDK App has more than one stack.

Required: No

Parameters

Type: Map<String,String>

Key and Value map with the parameters for your stack.

Required: Yes

Example
StackConfiguration:
    - StackName: MyStackName
      Parameters:
          VpcId: $.output.vpc.id

Diff

Diff:
  Enabled: Boolean

Enabled

Type: Boolean

If set to true, the deployment plan will perform a cdk diff, and if there is a change, it will require manual approval.

Required: Yes

AttiniCfn

AttiniCfn will create, update, or delete a CloudFormation stack.

See more information about the configuration options here.

Note

If a stack is in “ROLLBACK_COMPLETE” state, and you re-run the deployment plan, the stack will be deleted and recreated. The “ROLLBACK_COMPLETE” state only occurs after a failed creation, and the rollback has deleted all the resources in the stack.

Type: AttiniCfn
Properties:
    Template: String
    StackName: String
    ConfigFile: String
    Parameters: Map<String,String>
    Tags: Map<String,String>
    StackRoleArn: String
    ExecutionRoleArn: String
    Region: String
    OutputPath: String
    Variables: Map<String,String>
    Action: String
    EnableTerminationProtection: Boolean

Template

Type: String

The path to the CloudFormation template. Can either be:

  1. A path to a file in the distribution.
  2. A URL to a public S3 file, starting with https://.
  3. An S3 path, starting with s3://.

Required: Yes (can be configured in the ConfigFile)

StackName

Type: String

AWS API compatibility: This property is passed directly to the StackName property of the CreateStack or UpdateStack API call.

Required: Yes (can be configured in the ConfigFile)

ConfigFile

Type: String

This is a reference to a JSON or a YAML file in the distribution.

Note

Public HTTPS endpoints, ex https://path/to/my/parameters.json does not work for configuration files.

Find more info in the CloudFormation configuration documentation

Required: No

Parameters

Type: Map<String, String>

The CloudFormation parameters, find more info in the CloudFormation configuration documentation

Required: No (can be configured in the ConfigFile)

Tags

Type: Map<String,String>

The CloudFormation stack tags.

Required: No (can be configured in the ConfigFile)

StackRoleArn

Type: String

Arn of the StackRole, find more info here: AWS CloudFormation service role

Note

This IAM Role has to be in the same AWS Account that the CloudFormation stack is deployed in, so if “ExecutionRoleArn” is in a different AWS account, this “StackRoleArn” has to be in the same account as the “ExecutionRoleArn” If the “StackRoleArn” is in a different AWS Account then the “ExecutionRoleArn” you will receive a “Cross-account pass role is not allowed.” error.

Find more information about the security aspects of StackRoles here

Required: Conditional (can be configured in the ConfigFile)

Info

If the parameter “GiveAdminAccess” in attini-setup is false, this parameter or ExecutionRoleArn is required.

ExecutionRoleArn

Type: String

The role that you want to be assumed when the Attini Framework deploys the CloudFormation stack. This can be useful if you are:

The ExecutionRole has to trust the attini action default role arn:aws:iam::{AccountId}:role/attini/attini-action-role-{Region} so that it can be assumed.

Example trust relationship policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::111111111111:role/attini/attini-action-role-eu-west-1"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
Note

If you configure an execution role in another account or region, the Attini Framework will use a polling pattern to verify the state of the stack, this makes the deployment plan execution slower, and it can lead to throttling issues if it’s used a lot.

Find more information about the security aspects of ExecutionRoles here.

Required: No (can be configured in the ConfigFile)

Default: arn:aws:iam::{AccountId}:role/attini/attini-action-role-{Region}

Region

Type: String

Configure the region you want the CloudFormation stack in.

Note

If you configure a Region other than the current region the Attini Framework will use a polling pattern to verify the state of the stack. This makes the deployment plan execution slower, and it can lead to throttling issues if it's used a lot.

Required: No

Default: Current region

OutputPath

Type: String

If you need an extra level of separation for your payload output, you can use OutputPath. This is useful if you need to have multiple output sections from one step, example when you use AttiniMap.

If you, for example, have a State name buzz and an OutputPath: foo the output payload will look like this:

{
  "output": {
    "buzz": {
      "foo": {
        "OutputKey": "OutputValue"
      }
    }
  }
}

Required: No (can be configured in the ConfigFile)

Variables

Type: Map<String,String>

If your step has a ConfigFile configured, you can use Variables to pass values from your deployment plan payload into the file.

If you, for example, have an AttiniCfn State with the following config:

StateName:
  Type: AttiniCfn
  Properties:
    Template: /ecs-service.yaml
    ConfigFile: /ecs-config.yaml
    Variables:
      Environment: !Ref AttiniEnvironmentName
      DatabasePort.$: $.output.Database.Port
      StackRoleArn.$: $.output.StackRoles.EcsStackRole
    StackName: ecs-service

Your ConfigFile can look like this:

stackRoleArn: ${StackRoleArn}
parameters:
  ServiceName: ${Environment}-my-ecs-service
  DatabasePort: ${DatabasePort}
Note

By using Variables you can replace or manipulate any AttiniCfn configuration except for the ConfigFile path.

Required: No (can be configured in the ConfigFile)

Action

Type: String

Specify if the stack should be deployed (created/updated), or deleted.

Allowed values: Deploy | Delete

Required: No (can be configured in the ConfigFile)

Default: Deploy

EnableTerminationProtection

Type: Boolean

Specify if termination protection should be enabled for the stack.

Note

When first creating a stack, this is an atomic operation. However when updating an existing stack, the termination protection will be updated before the rest of the stack. This means that if the stack update fails and a rollback is performed, the termination protection will not be rolled back with the rest of the updates.

Required: No (can be configured in the ConfigFile)

Default: false

AttiniImport

The Attini import step can be used for importing data from different sources. A common use case for this type is reading data from the output of another distribution. For example, you could have a distribution responsible for setting up a network that exposes a VPC id. Then the VPC-id can be imported by other deployment plans.

Type: AttiniImport
Properties:
    SourceType: String
    Source: S3Source | DistributionSource
    Mapping: Map<String,String>
    ExecutionRoleArn: String

SourceType

Type: String

Specifies what kind of source should be used.

Allowed values: Distribution | S3

Required: Yes

Source

Type: S3Source | DistributionSource

Different sources require different information in order to import them. For example, S3 needs a bucket and key while a distribution needs the name of the distribution.

Which Source you need is decided by the SourceType.

Required: Yes

Mapping

Type: Map<String,String>

A key/value map where the value is a path to a value in the imported document. The path follows the JSONPath syntax. The value on the path will be included in the output of the step under the same key name as the mapping.

For example the following JSON source:

{
  "my-service-endpoint": "https://some-endpoint.com"
}

With the following mapping:

endpoint: $.my-service-endpoint

Would produce the following output for the step in the deployment plan payload.

{
  "endpoint": "https://some-endpoint.com"
}

Required: Yes

ExecutionRoleArn

Type: String

The arn of the execution role that should be used for accessing the source. At the moment only needed for the S3 source type if Attini does not have access to the S3 Bucket.

Required: No

Default: None

Subsections of AttiniImport

DistributionSource

Used when the source of the import should be another distribution deployed in the environment. Before a distribution can import the output of another distribution, it first needs to be declared as a dependency in the attini-config file.

Source:
  Name: String

Name

Type: String

The name of the distribution.

Required: Yes

Example
SourceType: Distribution
Source:
    Name: network

S3Source

Used when the source of the import should be a file on S3. The file must be in either a JSON or a YAML format.

Key: String
Bucket: String

Key

Type: String

The S3 Key of the document to import.

Required: Yes

Bucket

Type: String

The S3 Bucket where the document is located.

Required: Yes

Example
SourceType: S3
Source:
    Key: /my/s3/key.json
    Bucket: my-bucket

AttiniLambdaInvoke

AttiniLambdaInvoke will call a Lambda function while preserving the payload for subsequent steps. This is an abstraction of the Amazon state language Lambda integration and all parameters are supported.

The difference between using StepFunction native Lambda invoke functionality and the AttiniLambdaInvoke is that AttiniLambdaInvoke will automatically configure the Lambda output to comply with the deployment plan payload structure.

Type: AttiniLambdaInvoke
Parameters:
  FunctionName: String

FunctionName

Type: String

Lambda function name.

Required: Yes

Payload

Type: Map<String,String

This is passed directly to the Payload configuration in the Step Functions, and it works the same way.

By default, the entire deployment plan payload will be passed as input to the Lambda function.

Required: No

Example
Type: AttiniLambdaInvoke
Parameters:
  FunctionName: my-lambda-function

AttiniManualApproval

AttiniManualApproval

The manual approval step will pause the deployment plan and wait for confirmation before continuing. The deployment can be resumed by running the attini deploy continue command with the Attini CLI.

Type: AttiniManualApproval
Example
  ExampleDeployment:
    Type: Attini::Deploy::DeploymentPlan
    Properties:
      DeploymentPlan:
        - Name: WaitForApproval 
          Type: AttiniManualApproval

AttiniMap

Note

Experimental feature!

This is an abstraction of the Amazon state language Map that help you use AttiniCfn within a Map.

In an AttiniMap, your AttiniCfn will need to have OutputPath configured.

At the moment, it requires a list of S3 Objects keys that are served as input for each iteration. We are working on improving AttiniMap to make it more user-friendly.

This is passed directly the AWS StepFunction inline Map state, so you can find more information in its documentation.

Type: AttiniMap
ItemsPath: String
MaxConcurrency: Number
Iterator:
  StartAt: StateName
  States:
    StateName:
      Type: AttiniCfn

AttiniMergeOutput

Type: AttiniMergeOutput

Some AWS StepFunction types return a list instead of an object, for example, Parallel or Map.

To make the payload easier to work with, the merge step can merge all the data in the list into one object.

Info

This is added automatically after a parallel step when using the simplified syntax.

Example
AWSTemplateFormatVersion: "2010-09-09"
Transform:
  - AttiniDeploymentPlan
  - AWS::Serverless-2016-10-31

Resources:

  ExampleDeploy:
    Type: Attini::Deploy::DeploymentPlan
    Properties:
      DeploymentPlan:
        StartAt: Step1
        States:
          Step1:
            Type: Parallel
            Next: MergeOutputsFromStep1
            Branches:
              -
                StartAt: Stack1
                States:
                  Stack1:
                    Type: AttiniCfn
                    Properties:
                      Template: /template-1.yaml
                      StackName: stack-1
                    End: true
              -
                StartAt: Stack2
                States:
                  Stack2:
                    Type: AttiniCfn
                    Properties:
                      Template: /template-2.yaml
                      StackName: stack-2
                    End: true

          MergeOutputsFromStep1:
            Type: AttiniMergeOutput
            Next: Step2

          Step2:
            Type: AttiniCfn
            Properties:
              Template: /template-3.yaml
              StackName: stack-3
            End: true

AttiniRunnerJob

The AttiniRunnerJob is a quick and cost-efficient way to run shell commands using a container.

Find detailed information about the Attini::Deploy::Runner type here.

Find information about the Attini Runner architecture here.

Type: AttiniRunnerJob
Properties:
  Runner: String
  Environment: Map<String,String>
  Commands: List<String>

Runner

Type: String

Reference a Attini::Deploy::Runner recourse, find more information here.

Default: Attini default runner

Required: No

Environment

Type: Map<String,String>

This property lets you set environment variables on the Runner.

Example
Type: AttiniRunnerJob
Properties:
  Environment:
    ENV.$: $.environment
    VPC_ID.$: $.output.vpc.id
  Commands:
    - echo ${VPC_ID}

Required: No

Commands

Type: List<String>

List of shell commands that runs the job.

These commands are run with set -eo pipefail configuration so that they fail quickly. To revert this configuration (and ignore errors in your scrips), begin your commands with the line: set +eo pipefail.

Note

These strings can NOT integrate with the payload through Amazon state language using the $. syntax or its intrinsic functions.

If you need these commands to integrate with the payload, see the “Environment” configuration or Attini runner input and output.

Required: Yes

Example
HelloWorldRunner:
  Type: Attini::Deploy::Runner
  Properties:
    TaskDefinitionArn: !Ref RunnerTaskDefinition
    EcsCluster: test
    AwsVpcConfiguration:
      Subnets:
          - "subnet-aaaaaaaa"
          - "subnet-bbbbbbbb"
          - "subnet-cccccccc"
      SecurityGroups:
          - 'sg-11111111'
      assignPublicIp: ENABLED


ExampleDeployment:
  Type: Attini::Deploy::DeploymentPlan
  Properties:
    DeploymentPlan:
      - Name: Step1
        Type: AttiniRunnerJob
        Properties:
          Runner: HelloWorldRunner
          Commands:
            - echo "my shell commands"

AttiniSam

To simplify the use of the AWS Serverless Application Model (SAM) Attini will automatically build and package your SAM Applications if they are defined in the deployment plan using this (AttiniSam) type.

Attini will package the SAM App and use AttiniCfn to deploy it, meaning that most configurations will work the same way.

For more information on how Attini manages SAM Apps, see Attini and AWS SAM.

Type: AttiniSam
Properties:
    Project:
        Path: String
        Template: String
        BuildDir: String
    StackName: String
    ConfigFile: String
    Parameters: Map<String,String>
    Tags: Map<String,String>
    StackRoleArn: String
    ExecutionRoleArn: String
    Variables: Map<String,String>
    Action: String
    EnableTerminationProtection: Boolean
Note

Region from AttiniCfn is not supported because CloudFormation requires Lambda code to be stored in the same region as its being deployed to. The Attini Framework will package the SAM Application into an S3 Bucket in your current region only.

Attini does not support packaging AWS Lambda function with container images.

Project

Type: SamProject

Required: Yes

StackName

See StackName in AttiniCfn.

ConfigFile

See ConfigFile in AttiniCfn.

Parameters

See Parameters in AttiniCfn.

Tags

See Tags in AttiniCfn.

StackRoleArn

See StackRoleArn in AttiniCfn.

ExecutionRoleArn

See ExecutionRoleArn in AttiniCfn.

Variables

See Variables in AttiniCfn.

Action

See Action in AttiniCfn.

EnableTerminationProtection

See EnableTerminationProtection in AttiniCfn.

Subsections of AttiniSam

Project

Project:
  Path: String
  Template: String
  BuildDir: String

Path

Type: String

The path in your Attini project.

Required: Yes

BuildDir

Type: String

The path to a directory where the built artifacts are stored. This directory and all of its content are removed with this option.

See -b and --build-dir options in AWS SAM CLI build documentation.

Required: No

Default: .aws-sam/build

Template

Type: String

The path and file name of AWS SAM template file.

See -t, --template and --template-file option in AWS SAM CLI build documentation.

Required: No

Default: template.yaml

Example
Project:
  Path: /sam-app

Attini Runner


Supported operating systems and CPU architectures

The Attini Runner works on the following operating systems and CPU architectures:

  • Linux running on x86_64 architecture
  • Linux running on aarch64/arm64 architecture
Info

If you need support for other operating systems or CPU architectures, please email support@attini.io and we will try to accommodate the request.

You can find your operating system and CPU architecture by running uname -s and uname -m in a terminal. Please include this information in the support email.


Amazon ECS service quotas

The Attini Runner is run as an ECS Task, which means that all Amazon ECS limitations also apply to the Attini Runner.


Attini Runner information API

List the available operating systems and CPU architectures
curl https://docs.attini.io/api/v1/runner/get-supported-platforms
Get available Attini Runner versions
curl https://docs.attini.io/api/v1/runner/get-runner-versions/{cpu_architecture}/{operating_systems}
Examples
curl https://docs.attini.io/api/v1/runner/get-runner-versions/$(uname -m)/Linux
curl https://docs.attini.io/api/v1/runner/get-runner-versions/x86_64/Linux
curl https://docs.attini.io/api/v1/runner/get-runner-versions/aarch64/Linux
Get re-routed to the Attini Runner location
curl https://docs.attini.io/api/v1/runner/get-runner/{cpu_architecture}/{operating_systems}/{version}
Examples
curl https://docs.attini.io/api/v1/runner/get-runner/$(uname -m)/Linux/latest
curl https://docs.attini.io/api/v1/runner/get-runner/x86_64/Linux/1.0.0
curl https://docs.attini.io/api/v1/runner/get-runner/aarch64/Linux/1.0.0

Subsections of Attini Runner

Attini::Deploy::Runner

The Attini::Deploy::Runner resource only works in conjunction with the Attini deployment plan. See AttiniRunnerJob for more information.

The Attini::Deploy::Runner can only be created in the Attini init deploy stack.

Type: Attini::Deploy::Runner
Properties:
  TaskDefinitionArn: String
  ContainerName: String
  EcsCluster: String
  RoleArn: String
  Image: String
  Memory: Integer
  Cpu: Integer
  Ec2Configuration:
    Ami: String
    InstanceType: String
    InstanceProfileName: String
  RunnerConfiguration:
    MaxConcurrentJobs: Number
    IdleTimeToLive: Number
    JobTimeout: Number
    LogLevel: String
  AwsVpcConfiguration:
    Subnets: String,String
    SecurityGroups: String,String
    AssignPublicIp: String
  Startup:
    Commands:
      - String
    CommandsTimeout: Number

TaskDefinitionArn

Type: String

ECS task definition that the Attini Runner should use.

Note

The container image ENTRYPOINT or ECS task definition Entrypoint, must NOT be configured. If the ENTRYPOINT is configured, it will cause the Attini Runner not to start properly.

Depending on the ENTRYPOINT content, it can cause zombie ECS tasks.

Container image CMD and ECS task definition Command will be overwritten by the RunTask API call that Attini will call on your behalf.

To run commands from the Attini Runner, use the Attini::Deploy::DeploymentPlan AttiniRunnerJob type.

If you want to use CloudFormation to define the task definition, see AWS::ECS::TaskDefinition for more information.

Your TaskDefinitions IAM Role requires a basic execution policy called:

arn:aws:iam::${AccountId}:policy/attini-runner-basic-execution-policy-${Region}

The “TaskDefinitionArn” configuration can not be combined with the “Image” configuration.

If “TaskDefinitionArn” and “Image” is omitted, default task definition will be used.

Required: No

ContainerName

Type: String

The name of the container in the task definition that should run the runner jobs. This is required if there is more than one container definition in the specified task definition.

Required: Conditional

EcsCluster

Type: String

The name of the Attini Runners ECS Cluster.

Required: No

Default: attini-default

RoleArn

Type: String

This IAM Role will override the IAM Role from the TaskDefinition.

This IAM Role requires a basic execution policy that allows the runner to communicate with the deployment plan:

arn:aws:iam::${AccountId}:policy/attini-runner-basic-execution-policy-${Region}
CloudFormation example:
AttiniRunnerRole:
  Type: AWS::IAM::Role
  Properties:
    Description: Attini runner task role
    Path: /attini/
    AssumeRolePolicyDocument:
      Version: 2012-10-17
      Statement:
        -
          Effect: Allow
          Principal:
            Service: ecs-tasks.amazonaws.com
          Action: sts:AssumeRole
    ManagedPolicyArns:
      - !Sub arn:aws:iam::${AWS::AccountId}:policy/attini-runner-basic-execution-policy-${AWS::Region}

Required: No

Default: arn:aws:iam::{AccountId}:role/attini/attini-default-runner-role-{Region}

Image

Type: String

A Container image that the runner should use. If you configure this value, Attini will configure a TaskDefinition for you with the following configuration:

{RunnerName}TaskDefinition:
  Type: AWS::ECS::TaskDefinition
  Properties:
    ContainerDefinitions:
      - Name: Container
        Image: ${Image}
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group: !Ref {RunnerName}LogGroup
            awslogs-region: !Ref AWS::Region
            awslogs-stream-prefix: logs
    Cpu: 512
    ExecutionRoleArn: # Set to {RoleArn} or "Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/attini/attini-default-runner-role-${AWS::Region}"
    TaskRoleArn: # Set to {RoleArn} or "Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/attini/attini-default-runner-role-${AWS::Region}"
    Memory: 3072
    NetworkMode: awsvpc
    RequiresCompatibilities:
      - FARGATE


{RunnerName}LogGroup:
  Type: AWS::Logs::LogGroup
  Properties:
    RetentionInDays: 90

If you want to change any configuration, you can create your own task definition.

The “Image” configuration can not be combined with the “TaskDefinitionArn” configuration.

If “TaskDefinitionArn” and “Image” is omitted, default task definition will be used.

Required: No

Memory

Type: Number

This configuration will override the memory configuration from the TaskDefinition.

If the runner uses Fargate, this has to be a valid Fargate CPU and memory configuration.

If the runner uses EC2, we recommend the memory configuration to be ca 70-80% of the available memory of the EC2 Host so that there is some memory left for the Host OS. Exactly how much memory your Host OS needs depends on your workload so you might need to adjust this if you face any issues.

Required: No

Cpu

Type: Number

This configuration will override the CPU configuration from the TaskDefinition.

If the runner uses Fargate, this has to be a valid Fargate CPU and memory configuration.

If the runner uses EC2, this value has to be smaller than the available Host CPU.

Required: No

Ec2Configuration

Type: Ec2Configuration

Configuration for the runner EC2 Host.

If this EC2 configuration is set, the Attini runner will use ECS EC2 launch type, otherwise Fargate launch type will be used. Consequently, the task definition has to be compatible with the correct launch type.

Find more information in the .

Required: No

RunnerConfiguration
Type: RunnerConfiguration

Configuration for the runner.

Required: No

AwsVpcConfiguration

Type: AwsVpcConfiguration

The VPC configuration for the Runner ECS task.

Note

If AwsVpcConfiguration is omitted, Attini will use the default VPC and create a new security group resource in the init deploy stack. The security group will have no inbound rules (no openings), but allow all outgoing traffic.

Required: No

Startup

Type: StartupConfiguration

Startup instructions for the Attini Runner.

Required: No

Limitations

CloudFormation intrinsic functions

Some parts of the Attini::Deploy::Runner configuration will be moved into the deployment plan state language definition so that it can be used by when Attini runs the RunTask API Call. This means that some CloudFormation functions (ex Fn::Join or Fn::ImportValue) might not work as expected. As a workaround, your can use deployment plan definition substitutions and reference the substitutions in the Attini::Deploy::Runner.

Subsections of Attini::Deploy::Runner

AwsVpcConfiguration

AwsVpcConfiguration:
    Subnets: String,String
    SecurityGroups: String,String
    AssignPublicIp: String

Subnets

Type: String,String

A comma-separated list of the subnets’ ids associated with the ECS task. For more information, see the AWS ECS VPC documentation

Required: Yes

Default: default VPC subnets

SecurityGroups

Type: String,String

A comma-separated list of the security group ids associated with the ECS task. For more information see the AWS ECS VPC documentation

Required: No

Default: String,String

AssignPublicIp

Type: String

For more information, see the AWS ECS VPC documentation.

Required: No

Allowed Values: ENABLED | DISABLED

Default: ENABLED

Ec2Configuration

Ec2Configuration:
    Ami: String
    InstanceType: String
    InstanceProfileName: String

Ami

Type: String

The Ami (Amazon Machine Image) has to be a valid AMI ID or one of the following values:

  • AmazonLinux2
  • AmazonLinux2_arm64
  • AmazonLinux2_gpu
  • AmazonLinux2_inf
  • AmazonLinux2023
  • AmazonLinux2023_arm64
  • AmazonLinux2023_inf

Attini will use a corresponding recommended AMI fetched from AWS SSM Parameter store to get the correct AMI ID for your region.

If you configure your own AMI ID, it needs the ECS agent installed and enabled.

Required: No

Default: AmazonLinux2

InstanceType

Type: String

AWS Instance type, for example m5.large.

Required: Yes

InstanceProfileName

Type: String

Using an instance profile name, you can give your EC2 custom IAM Access.

Required: No

Default: `attini-runner-default-instance-profile-{Region} (created by attini-setup)

RunnerConfiguration

RunnerConfiguration:
    MaxConcurrentJobs: Number
    IdleTimeToLive: Number
    JobTimeout: Number
    LogLevel: String

RunnerConfiguration

Type: Number

The max number of concurrent jobs the Attini Runner will execute.

Required: No

Default: 5

Allowed Range: 1-20

IdleTimeToLive

Type: Number

The number of seconds the Attini Runner will stay alive without any jobs executing. New jobs will reset the countdown.

Required: No

Default: 3600

Allowed Range: 60-86400

JobTimeout

Type: Number

The number of seconds a job can execute before the Attini Runner aborts the execution.

Required: No

Default: 3600

Allowed Range: 5-172800

LogLevel

Type: String

The log level of the Attini Runner.

Required: No

Default: INFO

Allowed Values: DEBUG | INFO | WARN | ERROR | OFF | ALL

StartupConfiguration

Startup:
    Commands: List<String>
    CommandsTimeout: Number

Commands

Type: List<String>

List of shell commands that runs when the Attini Runner starts.

Required: No

Default: None

CommandsTimeout

Type: Number

The number of seconds the startup commands can be executed before the Attini Runner aborts the execution.

Required: No

Default: 3600

Allowed Range: 5-172800

Environment Variables

You can configure any environment variables you need on the Attini Runner via the image build process (ex Dockerfile) or using the ECS task definition.

However, the Attini Framework will automatically populate these environment variables:

ATTINI_ENVIRONMENT_NAME

The environment from the payload.

ATTINI_DISTRIBUTION_NAME

The distributionName from the payload.

ATTINI_DISTRIBUTION_ID

The distributionId from the payload.

ATTINI_ARTIFACT_STORE

The deploymentSource.deploymentSourceBucket from the payload.

ATTINI_DISTRIBUTION_ARTIFACTS_PREFIX

The deploymentSource.deploymentSourcePrefix from the payload.

ATTINI_INPUT

The location of a JSON file that contains the input payload. Find more information here.

ATTINI_OUTPUT

The location of a JSON file that the Attini Runner will pass as output to the payload. Find more information here.

ATTINI_SOURCE_DIR

The working directory from where the AttiniRunnerJob is executed. This directory will also contain all the original files from the Attini distribution.

ATTINI_STEP_NAME

The name of the deployment plan step name.

ATTINI_AWS_ACCOUNT

The current AWS Account.

ATTINI_AWS_REGION

The current AWS Region.

Install the Attini Runner

The Attini Runner will automatically be installed at boot if it’s not already installed. However, it is recommended to install it on your own build image. This will decrease startup time, give you better control over software versions, and reduce the risk of other failures. Installing the Attini Runner at boot also required internet access.

We recommend you configure a Linux user for security reasons. If you pre-install all the software your deployment needs, the use-cases for running jobs as root decrease significantly.

Example Dockerfile
Note

For the below dockerfile to work, you need to authenticate with the Amazon ECR public registries using the command:

aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
# Define the base image and update all software
FROM public.ecr.aws/amazonlinux/amazonlinux2:latest
RUN yum update -y && yum clean all

# Install the attini-runner
RUN curl -sfL#o /usr/local/bin/attini-runner https://docs.attini.io/api/v1/runner/get-runner/$(uname -m)/$(uname -s)/latest; chmod +x /usr/local/bin/attini-runner

# Configure a user (recommended)
RUN yum install -y shadow-utils && yum clean all && useradd attini
USER attini

Payload Input/Output

Input

Within the Attini Runner job, you can access the deployment plan payload input via a JSON file available on the runner. The path to the JSON file is available to the job commands via the ATTINI_INPUT environment variable.

Output

If you want the later steps in the deployment plan to access information from your job, you can save that data to a file on the runner. That file path is available through the ATTINI_OUTPUT environment variable.

The contents of the output file will be passed to the deployment plan payload under the path output.[StepName]. If the contents are valid JSON, it will be passed as-is. If the contents are not valid JSON it will be converted to a JSON object with the contents being present under the "result" field, for example {"result": "my-none-json-value"}.

Hint: jq is a good tool when you work with JSON using bash.

Example
StepName:
  Type: AttiniRunnerJob
  Properties:
    Runner: HelloWorldRunner
    Commands:
      - cat ${ATTINI_INPUT} # This will print the input as a string.
      - echo '{"MyKey":"MyValue"}' > ${ATTINI_OUTPUT} # This will add the JSON object to the output

Content