Module Digest
How to use VaporShell in its entirety
- The VaporShell.Template Object
- Walking Through the Template Anatomy
- Intrinsic Functions
- Condition Functions
- Pseudo Parameters
The VaporShell.Template Object
The VaporShell.Template
is created when you either initialize a new template with Initialize-VaporShell
or import an existing one with Import-VaporShell
. This object includes an Add and Remove script method for each of the following template attributes (examples of each for reference):
- Metadata
1
2
3
$template = Initialize-VaporShell
$template.AddMetadata( (New-VaporMetadata -LogicalId "Instances" -Metadata @{Description = "These are my instances"}) )
$template.RemoveMetadata( "Instances" )
- Parameters
1
2
3
$template = Initialize-VaporShell
$template.AddParameter( (New-VaporParameter -LogicalId "DBPassword" -Type String -NoEcho ) )
$template.RemoveParameter( "DBPassword" )
- Mappings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$template = Initialize-VaporShell
$template.AddMapping( (New-VaporMapping -LogicalId "RegionMap" -Map @{
"us-east-1" = @{
"32" = "ami-6411e20d"
"64" = "ami-7a11e213"
}
"us-west-1" = @{
"32" = "ami-c9c7978c"
"64" = "ami-cfc7978a"
}
}
)
)
$template.RemoveMapping( "RegionMap" )
- Conditions
1
2
3
$template = Initialize-VaporShell
$template.AddCondition( (New-VaporCondition -LogicalId "CreateProdResources" -Condition (Add-ConEquals -FirstValue (Add-FnRef -Ref "EnvType") -SecondValue "prod") ) )
$template.RemoveCondition( "CreateProdResources" )
- Resources
1
2
3
$template = Initialize-VaporShell
$template.AddResource( (New-VSApiGatewayRestApi -LogicalId "MyApi" -Description "My REST API") )
$template.RemoveResource( "MyApi" )
- Outputs
1
2
3
$template = Initialize-VaporShell
$template.AddOutput( (New-VaporOutput -LogicalId "BackupLoadBalancerDNSName" -Description "The DNSName of the backup load balancer" -Value (Add-FnGetAtt -LogicalNameOfResource "BackupLoadBalancer" -AttributeName "DNSName") ) )
$template.RemoveOutput( "BackupLoadBalancerDNSName" )
- Transforms
If you’d like to add/remove a top level transform, you would use the following script methods:
1
2
3
$template = Initialize-VaporShell
$template.AddTransform( (Add-Include -Location "s3://MyAmazonS3BucketName/single_wait_condition.yaml") )
$template.RemoveTransform( )
Walking Through the Template Anatomy
Base Attributes
The Base Attributes are common items within your CloudFormation template that are more descriptive of the template itself than of resources.
FormatVersion
The AWSTemplateFormatVersion section (optional) identifies the capabilities of the template. The latest template format version is 2010-09-09 and is currently the only valid value.
The FormatVersion is set with Initialize-VaporShell
and defaults to "2010-09-09"
Description
The template description. Total byte count for the description has to be greater than 0 but less than 1024.
The description is set with Initialize-VaporShell
Metadata
You can use the optional Metadata section to include arbitrary JSON objects that provide details about the template.
You add metadata to an already existing VaporShell.Template
object by using the object’s AddMetadata()
script property combined with New-VaporMetadata
.
Parameters
You can use the optional Parameters section to pass values into your template when you create a stack. With parameters, you can create templates that are customized each time you create a stack. Each parameter must contain a value when you create a stack. You can specify a default value to make the parameter optional so that you don’t need to pass in a value when creating a stack. AWS CloudFormation will use the default value.
You add parameters to an already existing VaporShell.Template
object by using the object’s AddParameter()
script property combined with New-VaporParameter
.
Mappings
The optional Mappings section matches a key to a corresponding set of named values. For example, if you want to set values based on a region, you can create a mapping that uses the region name as a key and contains the values you want to specify for each specific region. You use the Add-FnFindInMap
intrinsic function to retrieve values in a map.
You add mappings to an already existing VaporShell.Template
object by using the object’s AddMapping()
script property combined with New-VaporMapping
.
Conditions
The optional Conditions section includes statements that define when a resource is created or when a property is defined. For example, you can compare whether a value is equal to another value. Based on the result of that condition, you can conditionally create resources.
You add conditions to an already existing VaporShell.Template
object by using the object’s AddCondition()
script property combined with New-VaporCondition
.
Resources
The required Resources section declares the AWS resources that you want to include in the stack, such as an Amazon EC2 instance or an Amazon S3 bucket. You must declare each resource separately; however, if you have multiple resources of the same type, you can declare them together by separating them with commas.
You add resources to an already existing VaporShell.Template
object by using the object’s AddResource()
script property combined with New-VaporResource
. This is especially useful when you’d like to add a custom resource type to your template.
Resource Types
VaporShell also comes with ~200 specific Resource Type functions to make things easier. These all use New-VaporResource
to compile the final object, so you are free to use any of those with the AddResource()
script method as well. To make them easier to identify, all Resource Type functions follow this naming convention: New-VS{ResourceName}
You can view the available resource type functions on the glossary page: Resource Types
Resource Property Types
Resource Property Types are typically not passed directly into a template attribute. These are special object types that fit into Resource Type parameters. They can be easily identified as well; all Resource Property Type functions follow this naming convention: Add-VS{ResourcePropertyName}
Here’s an example of a resource property [ApiGatewayDeploymentStageDescription] passed in as a parameter for a resource [ApiGatewayDeployment], with another resource property passed into it [ApiGatewayDeploymentMethodSetting]:
1
2
3
$template.AddResource(
(New-VSApiGatewayDeployment -LogicalId "GatewayDeployment" -StageDescription (Add-VSApiGatewayDeploymentStageDescription -MethodSettings (Add-VSApiGatewayDeploymentMethodSetting -LoggingLevel ERROR) ) )
)
Resource Attributes
Resource Attributes are typically policies surrounding resources, such as Creation Policies, Deletion Policies and Update Policies. All resources have them as available parameters. There are 2 helper functions for adding in a CreationPolicy and/or UpdatePolicy to a resource:
Add-CreationPolicy
Add-UpdatePolicy
AWS Documentation on Resource Attributes
Adding UserData
Adding UserData to a Resource with VaporShell is designed to be quick and easy with the Add-UserData
function. You have the option to either provide an array of Strings and/or Intrinsic Functions, a single String or Intrinsic Function, or even read from a local file.
Important items to remember when using Add-UserData
:
- Special characters in
-String
parameter values should be written in PowerShell format (i.e. `n instead of \n). These will be converted to JSON format once the VaporShell template is exported. - If using the
-File
parameter, the local file must not contain any Intrinsic Functions, as they will be escaped when the template object is exported and taken as string literals. - If using the
-File
parameter with PowerShell or CMD script files (Windows-centric UserData), you do not need to place the PowerShell/script open and close tags in the script file. This allows you to develop and test the script without them to prevent errors from unknown commands being run.- If the file is a .ps1,
Add-UserData
will add in the open<PowerShell>
and close</PowerShell>
tags if the script file does not already contain them. - If the file is a .bat or .cmd, it will add in
<script>
and</script>
if not already present on the file itself.
- If the file is a .ps1,
Using the String parameter
Here’s an example of how you would use the String parameter:
1
2
3
4
5
6
7
8
9
10
11
12
New-VSEC2Instance -UserData (Add-UserData -String `
"#!/bin/bash -xe`n",
"yum update -y aws-cfn-bootstrap`n",
"/opt/aws/bin/cfn-init -v \`n",
" --stack Stack1 \`n",
" --resource LaunchConfig \`n",
" --configsets wordpress_install \`n",
" --region ", (Add-FnRef "$_AWSRegion"), "`n",
"/opt/aws/bin/cfn-signal -e $? \`n",
" --stack Stack1 \`n",
" --resource WebServerGroup \`n",
" --region ", (Add-FnRef "$_AWSRegion"), "`n" ) -LogicalId "MyInstance" -AvailabilityZone "us-west-1a" -ImageId "ami-6411e20d"
Using the File parameter
Here’s an example of how you would do the same thing using the File parameter:
1
New-VSEC2Instance -UserData (Add-UserData -File ".\UserData.sh") -LogicalId "MyInstance" -AvailabilityZone "us-west-1a" -ImageId "ami-6411e20d"
NOTE: This file will explicitly state the region, not leverage the Ref Intrinsic Function to pull the deployment region
Outputs
The optional Outputs section declares output values that you can import into other stacks (to create cross-stack references), return in response (to describe stack calls), or view on the AWS CloudFormation console. For example, you can output the S3 bucket name for a stack to make the bucket easier to find.
You add outputs to an already existing VaporShell.Template
object by using the object’s AddOutput()
script property combined with New-VaporOutput
.
Transforms
Includes
You can add an Includes at the top-level of an already existing VaporShell.Template
object by using the object’s AddTransform()
script property combined with Add-Include
passed in as the parameter.
You can also use the AWS::Include transform anywhere within the AWS CloudFormation template except in the template parameters section or the template version field. For example, you can use AWS::Include in the mappings section.
Serverless
VaporShell has full coverage of the Serverless transform resources as of version 0.7.10. If you add any Serverless resources to the template object via $template.AddResource()
, it will automatically add the top-level Transform.
Here’s an example of using Serverless transforms to build this example template found on awslabs’ GitHub:
1
2
3
4
5
6
7
8
$t = Initialize-VaporShell -Description "Simple CRUD webservice. State is stored in a SimpleTable (DynamoDB) resource."
$t.AddResource(
( New-SAMFunction -LogicalId "GetFunction" -Handler "index.get" -Runtime "nodejs4.3" -CodeUri "s3://<bucket>/api_backend.zip" -Policies "AmazonDynamoDBReadOnlyAccess" -Environment (@{TABLE_NAME = (Add-FnRef "Table")}) -Events (Add-SAMApiEventSource -LogicalId "GetResource" -Path "/resource/{resourceId}" -Method "get") ),
( New-SAMFunction -LogicalId "PutFunction" -Handler "index.put" -Runtime "nodejs4.3" -CodeUri "s3://<bucket>/api_backend.zip" -Policies "AmazonDynamoDBFullAccess" -Environment (@{TABLE_NAME = (Add-FnRef "Table")}) -Events (Add-SAMApiEventSource -LogicalId "PutResource" -Path "/resource/{resourceId}" -Method "put") ),
( New-SAMFunction -LogicalId "DeleteFunction" -Handler "index.delete" -Runtime "nodejs4.3" -CodeUri "s3://<bucket>/api_backend.zip" -Policies "AmazonDynamoDBFullAccess" -Environment (@{TABLE_NAME = (Add-FnRef "Table")}) -Events (Add-SAMApiEventSource -LogicalId "DeleteResource" -Path "/resource/{resourceId}" -Method "delete") ),
( New-SAMSimpleTable -LogicalId "Table" )
)
Export-VaporShell -VaporShellTemplate $t
Resulting JSON:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Simple CRUD webservice. State is stored in a SimpleTable (DynamoDB) resource.",
"Transform": "AWS::Serverless-2016-10-31",
"Resources": {
"GetFunction": {
"Type": "AWS::Serverless::Function",
"Properties": {
"Handler": "index.get",
"Runtime": "nodejs4.3",
"CodeUri": "s3://\u003cbucket\u003e/api_backend.zip",
"Policies": "AmazonDynamoDBReadOnlyAccess",
"Environment": {
"Variables": {
"TABLE_NAME": {
"Ref": "Table"
}
}
},
"Events": {
"GetResource": {
"Properties": {
"Path": "/resource/{resourceId}",
"Method": "get"
},
"Type": "Api"
}
}
}
},
"PutFunction": {
"Type": "AWS::Serverless::Function",
"Properties": {
"Handler": "index.put",
"Runtime": "nodejs4.3",
"CodeUri": "s3://\u003cbucket\u003e/api_backend.zip",
"Policies": "AmazonDynamoDBFullAccess",
"Environment": {
"Variables": {
"TABLE_NAME": {
"Ref": "Table"
}
}
},
"Events": {
"PutResource": {
"Properties": {
"Path": "/resource/{resourceId}",
"Method": "put"
},
"Type": "Api"
}
}
}
},
"DeleteFunction": {
"Type": "AWS::Serverless::Function",
"Properties": {
"Handler": "index.delete",
"Runtime": "nodejs4.3",
"CodeUri": "s3://\u003cbucket\u003e/api_backend.zip",
"Policies": "AmazonDynamoDBFullAccess",
"Environment": {
"Variables": {
"TABLE_NAME": {
"Ref": "Table"
}
}
},
"Events": {
"DeleteResource": {
"Properties": {
"Path": "/resource/{resourceId}",
"Method": "delete"
},
"Type": "Api"
}
}
}
},
"Table": {
"Type": "AWS::Serverless::SimpleTable"
}
}
}
Resulting YAML (if cfn-flip is installed as well):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
AWSTemplateFormatVersion: '2010-09-09'
Description: Simple CRUD webservice. State is stored in a SimpleTable (DynamoDB) resource.
Transform: AWS::Serverless-2016-10-31
Resources:
GetFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.get
Runtime: nodejs4.3
CodeUri: s3://<bucket>/api_backend.zip
Policies: AmazonDynamoDBReadOnlyAccess
Environment:
Variables:
TABLE_NAME: !Ref 'Table'
Events:
GetResource:
Properties:
Path: /resource/{resourceId}
Method: get
Type: Api
PutFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.put
Runtime: nodejs4.3
CodeUri: s3://<bucket>/api_backend.zip
Policies: AmazonDynamoDBFullAccess
Environment:
Variables:
TABLE_NAME: !Ref 'Table'
Events:
PutResource:
Properties:
Path: /resource/{resourceId}
Method: put
Type: Api
DeleteFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.delete
Runtime: nodejs4.3
CodeUri: s3://<bucket>/api_backend.zip
Policies: AmazonDynamoDBFullAccess
Environment:
Variables:
TABLE_NAME: !Ref 'Table'
Events:
DeleteResource:
Properties:
Path: /resource/{resourceId}
Method: delete
Type: Api
Table:
Type: AWS::Serverless::SimpleTable
Intrinsic Functions
AWS CloudFormation provides several built-in functions that help you manage your stacks. Use intrinsic functions in your templates to assign values to properties that are not available until runtime.
VaporShell includes functions for each Intrinsic function. You can find more info in the Glossary.
Here’s an example where the Add-FnRef
function is used to fill out the RestApiId for an APIGatewayDeployment:
1
2
3
$template.AddResource(
(New-VSApiGatewayDeployment -LogicalId "GatewayDeployment" -RestApiId (Add-FnRef -Ref "MyApi"))
)
Condition Functions
You can use intrinsic functions, such as Add-FnIf
, ``Add-FnEquals, and
Add-FnNot`, to conditionally create stack resources. These conditions are evaluated based on input parameters that you declare when you create or update a stack. After you define all your conditions, you can associate them with resources or resource properties in the Resources and Outputs sections of a template.
You define all conditions in the Conditions section of a template except for Add-FnIf
conditions. You can use the Add-FnIf
condition in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template.
You can find more info in the Glossary.
Pseudo Parameters
Having trouble remembering those Pseudo Parameters? VaporShell includes them as imported variables for convenience. They all begin with $_AWS
, so start typing then tab to cycle through them in most ISE’s.
When using these in commands, i.e. Add-FnRef -Ref "$_AWSRegion"
, make sure you surround the variable in double quotes to cast to string indefinitely
Here’s a table of the variables for a quick reference:
Pseudo Parameter | VaporShell Variable |
---|---|
$_AWSAccountId | AWS::AccountId |
$_AWSInclude | AWS::Include |
$_AWSNotificationARNs | AWS::NotificationARNs |
$_AWSNoValue | AWS::NoValue |
$_AWSRegion | AWS::Region |
$_AWSStackId | AWS::StackId |
$_AWSStackName | AWS::StackName |