Transformation by TOSCA Type

Currently, the CloudFormation plugin only supports certain Node- and RelationshipTypes defined in the TOSCA Simple Profile. The following sections shows which types are supported and how those are mapped to CloudFormation.

Supported NodeTypes

The following table contains the NodeTypes currently supported by the CloudFormation plugin and how they're mapped to CloudFormation resources.

TOSCA NodeType CloudFormation
Apache Setup through CloudFormation Init on the EC2 host
Compute EC2 resource and corresponding SecurityGroup
Database Setup through CloudFormation Init on the EC2 host
Dbms Setup through CloudFormation Init on the EC2 host
MysqlDatabase RDS resource with a mysql engine and corresponding SecurityGroup
MysqlDbms No specific resource is created
WebApplication Setup through CloudFormation Init on the EC2 host
Nodejs Setup through CloudFormation Init on the EC2 host
JavaRuntime No specific resource is created
JavaApplication Beanstalk Application and Environment and corresponding SecurityGroup

NodeType Transformation Details

These transformations take place in the TransformationModelNodeVisitor. During the transform phase of the TransformationLifeCycle, the visit() of the various NodeTypes are executed in order to fill the CloudFormationModule with the necessary information to generate the CloudFormation template and the files needed to deploy the CloudFormation stack. The following section offers a detailed explanation of the transformation behaviour for each of these NodeTypes.

Compute

Each Compute node that was previously marked in the prepare phase now gets transformed into an EC2 Instance resource with a corresponding SecurityGroup resource.

1. Security Group

The SecurityGroup is created. The security group allows giving other SecurityGroups access to them and opening of ports for the corresponding EC2 instance . If present, optional endpoint ports are opened on this security group.

2. Capability Mapping

Both the OsCapability and ComputeCapablity of the Compute node are mapped to properties of the EC2 instance by the CapabilityMapper.

First, the CapabilityMapper is used to figure out the ID of the Amazon Machine Image (AMI) corresponding to the OsCapability. To do this, we build an AmazonEC2 client with the AWS SDK for Java to get the latest image IDs from AWS. In order to get the right image ID, a DescribeImagesRequest is built with the properties of the OsCapability. When the image request is completed, the describeImages() method of the EC2 client is used to get the images fulfilling the requirements of the request. From these images, the capability mapper takes the latest image ID available which in turn is used by the visitor as the ImageId property of the EC2 instance.

Then the CapabilityMapper is used to figure out the right InstanceType for the EC2 instance corresponding to the ComputeCapability. The right instance type is determined based on the numCpus and memSize properties of the ComputeCapability. Specifically, this is done by scaling up those values until a fitting instance type is found. It is then used by the visitor as the InstanceType property of the EC2 instance. If no instance type fitting the requirements the ComputeCapability can be found, the transformation ends with a TransformationFailureException.

3. Cloudformation Init

We use the CloudFormation Init and the cfn-init script to bootstrap our EC2 instances. It allows us to call scripts, commands, install packages and download files on our EC2 instances. Specifically, the CFNinit is created and added to the CloudFormationModule but not yet to the EC2 instance, so it can still be manipulated by the visitor.

4. Creating the instance

At this point, all the necessary information in order to create the EC2 instance resource corresponding to the Compute node has been gathered. The resource gets added to the CloudFormationModule using the resource() method with the SecurityGroupId, ImageId and instanceType.

Then the CapabilityMapper uses the ComputeCapability to get the right disk size for the EC2 instance. If the disk size exceeds the standard of 8 Gb for EC2 instances, an additional EC2BlockDeviceMapping is added to the EC2 instance resource containing an Amazon Elastic Store (EBS) Block Device with the VolumeSize corresponding to the disk size of the ComputeCapability.

Finally, if the keyPair property of the CloudFormationModule was set to true, the KeyName referencing the KeyName String parameter, which is later set when the build() method of the CloudFormationModule called, is added to the EC2 instance resource and the port 22 is opened on its corresponding SecurityGroup. This allows the user to access the EC2 instance via SSH by authenticating with the right AWS Keypair.

5. During build time

After all nodes have been visited and before the template gets created, the build() method of the CloudFormationModule gets called. Here the previously built CFNInits belonging to EC2 instances and a userdata section that executes cfn-init are added to the EC2 instances.

If EC2 instances need additional files from the S3 bucket during the deployment, an Authentication and IamInstanceProfile are added to those instances to allow them to access the S3 bucket.

If the keyPair property of the CloudFormationModule is set to true, a KeyName CloudFormation parameter is added to the CloudFormationModule. This parameter must be set in the create-stack.sh script before deploying the target artifact as mentioned in the architecture chapter.

MysqlDatabase

Each MysqlDatabase gets transformed into a DBInstance resource which is a AWS RDS instance. Also a corresponding SecurityGroup resource is created.

1. CapabilityMapping

Various values do not need to mapped like the database name, the root user, the root password, or the port. These values are just taken from the node without further modifications.

Launching a RDS requires a set value for the allocatedStorage field. The ComputeCapability of the underlying Compute node is used to obtain this value. The minimum value is 20 GB the maximum 6144 GB.

The CapabilityMapper is also used to figure out the right dBInstanceClass which is similar to the InstanceType property of the EC2 but with different values. The same steps as getting the InstanceType for EC2 are taken. Refer to CapabilityMapping of Compute Node for more information.

2. Security Group

The SecurityGroup is created. The security group allows other security groups to access this one. Every resource that belongs to a security group which has an ingress rule to another security group can be accessed by resources belonging to that other securtiy group. This is what is done next. Every node that has a connectsTo relationship to this database should get access to it. The underlying compute nodes of these nodes or rather their security groups are taken and added to ingress rules to the security group of this database.

3. Creating the instance

At this point, all necessary information in order to create the RDS instance has been gathered. The instance is created with the engine value of RDS set to "MySQL".

4. Handling SQL artifact

Due to conventions the MysqlDatabase is able to carry a .sql artifact which should be executed on the database.

Sadly AWS RDS does not offer a easy solution for this. The inconvenient way is to create an EC2 instance, install a mysql client on this instance, remotely execute the sql code onto the database and finally shutdown the instance. This special EC2 instance and a corresponding SecurityGroup are created and an ingress rule for this security group is added to the database security group.

MysqlDBMS

Because the MysqlDatabases are transformed to AWS RDS, it is not required to be run a MysqlDbms on an EC2 instance. This node is omitted completely.

JavaApplication

JavaApplications are transformed to Beanstalk. This requires to create a Beanstalk Application, ApplicationVersion, ConfigurationTemplate and Environment. More information about Beanstalk can be found here.

1. Beanstalk Application

The Beanstalk Application is created. It in itself does not hold any information, but is referred to by the other resources. It is the representation of the Application.

2. Beanstalk ApplicationVersion

The Beanstalk ApplicationVersion holds the .jar artifact. It holds it as a source bundle which is a reference to a S3 Bucket and a containing file. This means the .jar artifact is marked to be uploaded to the S3 Bucket and the values are put into a SourceBundle which is attached to the also created ApplicationVersion.

3. Beanstalk ConfigurationTemplate

The ConfigurationTemplate holds the stack information of the Beanstalk Application. All available platforms can be found here.

At this point the underlying JavaRuntime, which holds Java version that the application is build for, is used. Using the JavaRuntimeMapper the java version is extracted and added to a predefined String which tells Beanstalk to run a Java Stack on Linux.

4. Adding OptionSettings to the ConfigurationTemplate

OptionSettings are options that can be added to the ConfigurationTemplate. Several option settings are added.

First a security group is created and opened to ports if there are any specified. The security group is wrapped into a option setting.

All environment variables that are set in the start lifecycle of the JavaApplication will be added as option settings.

All OptionSettings are added to the ConfigurationTemplate.

5. Beanstalk Environment

The Beanstalk Environment is the core part because it holds all other resources together. It is created referencing the just created resources.

JavaRuntime

Because the JavaApplications are transformed to Beanstalk, it is not required to run a JavaRuntime on an EC2 instance. All the information needed from the JavaRuntime in order to build those Beanstalk resources is taken during the visit() method of the JavaApplication.

Generic Transformation of Nodes hosted on Compute

Contrary to the NodeTypes discussed above, there are various NodeTypes which don't get mapped to a specific CloudFormation resource but are rather added to the EC2 instance that they're meant to be hosted on. Specifically, this is done by the OperationHandler and EnvironmentHandler classes.

The Operationhandler takes the create, start and configure operations and adds them as files and commands to the CFNInit of the underlying EC2 instance. Specifically, this means that the dependencies and artifacts are marked as files to be uploaded to the S3 Bucket and marking the EC2 instance as an instance in need of Authentication. The authentication mentioned here is needed for the EC2 instance to access the S3 Bucket containing the files. Both artifacts and dependencies are also added as CFNFiles to the CFNInit, meaning that the cfn-init script will download them during the initial bootstrapping of these EC2 instances. Lastly, the path to the artifact on the EC2 instance and the inputs for the operation are added as a CFNCommand to the CFNInit, meaning that it will be executed by the cfn-init script during the bootstrapping.

In order to allow the nodes to access the input variables of the start operations during runtime, the inputs are also added to the environmentMap of the CloudFormationModule. Later during the transform phase, these variables are written to /etc/environment on the EC2 instance through setEnv scripts.

That being said, most of these NodeTypes require additional or alternative steps unique to them in order to be properly transformed. Next follows an explanation of how the transformation of each of these NodeTypes differs from the generic transformation behaviour.

Apache

Instead of using the create operation of the Apache node, we add the apache2 package to the CFNInit of the underlying EC2 instance. The start and configure operations are added normally as described in Generic Transformation of Nodes hosted on Compute.

Environment variables that are used during runtime by an application hosted on the Apache node must be imported from etc/environment to etc/apache/envvars. This is done through an additional command added to the CFNInit. These environment variables are added to /etc/environment during the transformation of the application as described in Generic Transformation of Nodes hosted on Compute.

If the start or configure operations were present in the Apache node, an additional service apache2 restart restart command is added to the CFNInit to ensure that the configuration modifications are properly loaded.

Dbms

In addition to the generic hosted node transformation, the port contained in the port property of the Dbms node must be opened on the underlying EC2 instance. This means that the port is opened in the SecurityGroup corresponding to the EC2 instance of the Compute host of the hostedOn relationship connected to the Database.

Database

Similar to the Dbms node, in addition to the generic hosted node transformation, the port contained in the port property of the Database node is opened on the underlying EC2 instance by opening it in the corresponding SecurityGroup.

WebApplication

The ports from the AppEndPoint of the WebApplication node are opened in the SecurityGroup of the underlying EC2 instance.

Nodejs

Instead of using the create operation of the Nodejs node, a generic create-nodejs.sh script is added to the CFNInit of the underlying EC2 instance. This script installs the latest version of Node.js 8. The start and configure operations are added normally as described in the Generic Transformation of Nodes hosted on Compute section.

The ports from the EndpointCapability of the Nodejs node are opened in the SecurityGroup of the underlying EC2 instance.

Supported RelationshipTypes

TOSCA RelationshipType
hostedOn
connectsTo: WebApplication -> Database
connectsTo: JavaApplication -> Database

Currently, the CloudFormation plugin does not require additional steps to be taken after preparing the model with the PrepareModelRelationshipVisitor during the prepare phase and transforming it with the TransformModelNodeVisitor during the transform phase in order to facilitate these relationships between the resources on AWS.