cloudsoft.io

Tips and Tricks for Visual Composer

Setting Tags

Many resources within AWS have a ‘Tags’ property, such as AWS::EC2::Instance. The long-form in CloudFormation is:

Properties:
  Tags:
    - Key: key1
      Value: val1
    - Key: key2
      Value: val2

Visual Composer also accepts a short-hand for this: each tag can be entered using either the format key1=val1 or key1: val1.

Configuring tags

If you have a key or value containing these special characters, put the key and value in quotes such as "key:1": "val:1"

Each tag can also be entered as JSON (see below), e.g. {"Key": "key1", "Value": "val1"}.

JSON Values

Some properties in CloudFormation have complex types. Additional support is being added in future versions of Visual Composer for setting such values. However, it is always possible to provide a JSON value.

For example, the AWS::EC2::Instance Volumes property is a list of Device-VolumeId tuples, such as:

Properties:      
  Volumes:
    - Device: "/dev/sdf"
      VolumeId: vol-xxxxxxxx
    - Device: "/dev/sdg"
      VolumeId: vol-yyyyyyyy

This can be achieved by using the first entry {"Device": "/dev/sdf", "VolumeId": "vol-xxxxxxxx"}, and similarly for the second entry.

Configuring json values

Where a textbox is annotated with the “</>” icon, it indicates that JSON is recognised by the graphical editor at composition time - click on this icon to have the value recognised as JSON rather than a string.

However, where a string (in JSON format) is used and a complex type is expected, it will attempt to automatically convert it to the complex type when ‘Export CFN’ is clicked.

If the JSON is invalid (e.g. an incorrect field), the ‘Export CFN’ will return an error. Messages are more specific when using JSON rather than a string. For example, “Invalid blueprint: Type io.cloudsoft.aws.cfn.raw.ec2.instance.Volume has no apparent setter for Dveyez”, versus “Invalid blueprint: Cannot coerce type class java.lang.String to io.cloudsoft.aws.cfn.raw.ec2.instance.Volume”.

References

CloudFormation supports references to other resources in the template. This includes use of Ref and Fn::GetAtt.

For example, a template could create a AWS::Route53::RecordSet and a AWS::ElasticLoadBalancingV2::LoadBalancer, and could configure the RecordSet with an AliasTarget to point at the ELB.

Such a trimmed-down CloudFormation template is shown below.

Resources:
  AWSRoute53RecordSet:
    Type: "AWS::Route53::RecordSet"
    Properties:
      AliasTarget:
        HostedZoneId:
          Fn::GetAtt:
          - "Elb"
          - "CanonicalHostedZoneID"
        DNSName:
          Fn::GetAtt:
          - "Elb"
          - "DNSName"
      ..
  Elb:
    Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
    Properties:
      ...

To write this in Visual Composer, you can set the ‘Target’ value to point at the ELB, which will auto-generate this cross-reference configuration.

First add the desired resources from the palette. Then select the property whose value is to be set (e.g. ‘Target’ in this case). Click the lightning-bolt icon to choose the target reference.

Configuring lightning-bolt

This opens a wizard for choosing the target value. Use the search box to filter the targets, and click on the desired one (in this case the Load Balancer). The target must have a name - if the ‘Entity ID’ text box at the bottom of the wizard is blank, then give it a name such as ‘elb’ (otherwise a random ID will be generated). Then Click ‘Done’.

Configuring using the DSL editor

Custom CloudFormation

This Composer does not yet natively support all the fields available in CloudFormation. However you can add arbitrary CFN YAML easily in the Composer’s YAML blueprint, to support things like Mappings and Outputs. This is done by adding a extraCloudFormationYaml key in brooklyn.config at root (or on a given entity to set e.g. Metadata or a CreationPolicy there) and adding the YAML map data to be merged. For example:

services:
- type: AWS::Sample
  id: sample
  brooklyn.config:
    extraCloudFormationYaml:
      Metadata: YOUR_METADATA_HERE
brooklyn.config:
  extraCloudFormationYaml:
    Mappings: YOUR_MAPPINGS_HERE
    Outputs: YOUR_OUTPUT_HERE

will generate:

AWSTemplateFormatVersion: "2010-09-09"
Description: "Application CloudFormation exported from Cloudsoft AMP"
Parameters: {}
Mappings: YOUR_MAPPINGS_HERE
Resources:
  sample:
    Type: AWS::Sample
    Metadata: YOUR_METADATA_HERE
Outputs: YOUR_OUTPUT_HERE

YAML Model

When composing a CloudFormation template, the visual composer constructs a model in YAML. There is a bi-directional mapping to this YAML, which you can seen by clicking the two-way arrows in the top-right of the composer (click it again to switch back to the graphical view).

This YAML model (referred to as a YAML blueprint) is a simpler, portable description of applications. It uses the Cloudsoft AMP format. The CloudFormation is auto-generated from this model (i.e. the model can be thought of as an intermediate representation).

AMI Auto-Discovery

The property AWS::EC2::Instance ImageId is the AMI id within a given region, of the form ami-xxxxxxxxxxxxxxxxx.

Hard-coding these IDs within a CloudFormation template has advantages: it is the most straight-forward configuration. However, there are disadvantages: it is hard to read (requiring looking up the AMI to check what it is); it only works in one region; it will not pick up the newest AMI (e.g. of a hardened certified private image within your organisation).

There are many approaches to handle this within CloudFormation, such as using Mappings to specify different AMIs per region, or passing the AMI id as a parameter to the template, or referencing the named output from another CloudFormation stack.

Another way to handle this within Visual Composer is to use an ‘Image Name Regex’. When ‘Export CFN’ is run, it will lookup the matching AMI(s) to get the ID, and will include the ID in the generated CloudFormation. This approach may be appropriate for some use-cases, such as if using the Visual Composer REST API as part of a build pipeline to generate separate templates for each region.