Getting Started: Cloud Assembly Code Examples [CB10094]
Starting your journey on vRA 8.x can be a little challenging. Out of numerous demanding areas, one of them is creating blueprints or do i say, cloud templates in Cloud Assembly. Converting your existing vRA 7.x blueprints to vRA 8.x cloud templates requires some clarity on YAML development. Even though, a good deal of things are already provided out of the box, considering YAML as a Code which can single-handedly establish all your cloud deployments, getting the desired state out of it can be a trickster. Hence, I would like to share some quick bits on what we can do in vRA provided YAML editor to get the job done faster.
We will start with the basics and then will move to more advanced template options.
A blank template
name: templateName
formatVersion: 1
inputs: {}
resources: {}
Literals
The following literals are supported:
- Boolean (true or false)
- Integer
- Floating point
- StringBackslash escapes double quote, single quote, and backslash itself:
"
is escaped as\"'
is escaped as\'\
is escaped as\\
Quotes only need to be escaped inside a string enclosed with the same type of quote, as shown in the following example."I am a \"double quoted\" string inside \"double quotes\"."
- Null
Environment variables
Environment names:
- orgId
- projectId
- projectName
- deploymentId
- deploymentName
- blueprintId
- blueprintVersion
- blueprintName
- requestedBy (user)
- requestedAt (time)
${env.blueprintId}
Resource variables
Resource variables let you bind to resource properties from other resources
format: resource.RESOURCE_NAME.PROPERTY_NAME
${resource.db.id}
${resource.db.networks[0].address}
${resource.app.id} (Return the string for non-clustered resources, where count isn't specified. Return the array for clustered resources.)
${resource.app[0].id} (Return the first entry for clustered resources.)
Resource self variables
Resource self variables are allowed only for resources supporting the allocation phase. Resource self variables are only available (or only have a value set) after the allocation phase is complete.
${self.address} (Return the address assigned during the allocation phase.)
Note that for a resource named resource_x
, self.property_name
and resource.resource_x.property_name
are the same and are both considered self-references.
Cluster count index
${count.index == 0 ? "primary" : "secondary"} (Return the node type for clustered resources.)
Limitations:
Use of count.index
for resource allocation is not supported. For example, the following capacity expression fails when it references the position within an array of disks created at input time.
inputs:
disks:
type: array
minItems: 0
maxItems: 12
items:
type: object
properties:
size:
type: integer
title: Size (GB)
minSize: 1
maxSize: 2048
resources:
Cloud_vSphere_Disk_1:
type: Cloud.vSphere.Disk
properties:
capacityGb: '${input.disks[count.index].size}'
count: '${length(input.disks)}'
Conditions
- Equality operators are
==
and!=
. - Relational operators are
<
>
<=
and>=
. - Logical operators are
&&
||
and!
. - Conditionals use the pattern:condition-expression
?
true-expression:
false-expression
${input.count < 5 && input.size == 'small'}
${input.count < 2 ? "small" : "large"}
Arithmetic operators
Operators are +
–
/
*
and %
.
${(input.count + 5) * 2}
String concatenation
${'ABC' + 'DEF'}
Operators [ ] and .
The expression follows ECMAScript in unifying the treatment of the [ ] and . operators.
So, expr.identifier
is equivalent to expr["identifier"]
. The identifier is used to construct a literal whose value is the identifier, and then the [ ] operator is used with that value.
${resource.app.networks[0].address}
In addition, when a property includes a space, delimit with square brackets and double quotes instead of using dot notation.
Incorrect:
input.operating system
Correct:
input["operating system"]
Construction of map
${{'key1':'value1', 'key2':input.key2}}
Construction of array
${['key1','key2']}
Functions
${function(arguments...)}
${to_lower(resource.app.name)}
Supported functions
Check list of supported functions here
In the resources
section, you can reference an input parameter using ${input.property-name}
syntax. If a property name includes a space, delimit with square brackets and double quotes instead of using dot notation: ${input["property name"]}
.
inputs:
sshKey:
type: string
maxLength: 500
resources:
frontend:
type: Cloud.Machine
properties:
remoteAccess:
authentication: publicPrivateKey
sshKey: '${input.sshKey}'
Important In cloud template code, you cannot use the word input
except to indicate an input parameter.
Optional Inputs
Inputs are usually required and marked with an asterisk. To make an input optional, set an empty default value as shown.
owner:
type: string
minLength: 0
maxLength: 30
title: Owner Name
description: Account Owner
default: ''
List of input properties
Check list of all supported properties here.
Explicit dependencies
Sometimes, a resource needs another to be deployed first. For example, a database server might need to exist first, before an application server can be created and configured to access it.
An explicit dependency sets the build order at deployment time, or for scale in or scale out actions. You can add an explicit dependency using the graphical design canvas or the code editor.
- Design canvas option — draw a connection starting at the dependent resource and ending at the resource to be deployed first.
- Code editor option — add a
dependsOn
property to the dependent resource, and identify the resource to be deployed first.An explicit dependency creates a solid arrow in the canvas.
Property bindings
Sometimes, a resource property needs a value found in a property of another resource. For example, a backup server might need the operating system image of the database server that is being backed up, so the database server must exist first.
Also called an implicit dependency, a property binding controls build order by waiting until the needed property is available before deploying the dependent resource. You add a property binding using the code editor.
- Edit the dependent resource, adding a property that identifies the resource and property that must exist first.A property binding creates a dashed arrow in the canvas.
Encrypt access credentials
resources:
apitier:
type: Cloud.Machine
properties:
cloudConfig: |
#cloud-config
runcmd:
- export apikey=${base64_encode(input.username:input.password)}
- curl -i -H 'Accept:application/json' -H 'Authorization:Basic :$apikey' http://example.com
passing inputs to ABXs
resources:
db-tier:
type: Cloud.Machine
properties:
# Command to execute
abxRunScript_script: mkdir bp-dir
# Time delay in seconds before the script is run
abxRunScript_delay: 120
# Type of the script: shell (Linux) or powershell (Windows)
abxRunScript_shellType: linux
# Could be aws, azure, etc.
abxRunScript_endpointType: '${self.endpointType}'
getting value from Property Groups
appSize: '${propgroup.propGroup_name.const_size}'
Adding a secret property
type: Cloud.Machine
properties:
name: ourvm
image: mint20
flavor: small
remoteAccess:
authentication: publicPrivateKey
sshKey: '${secret.ourPublicKey}'
username: root
Enum & oneOf (Dropdowns in Input form)
enum and oneOf both are used to provide a set of default values in the input form. However, the only difference in them is that oneOf allows for a friendly title.
inputs:
osversion:
type: string
title: Select OS Version
default: SLES12
enum:
- SLES12
- SLES15
- RHEL7
inputs:
platform:
type: string
title: Deploy to
oneOf:
# Title is what the user sees, const is the tag for the endpoints.
- title: AWS
const: aws
- title: Azure
const: azure
- title: vSphere
const: vsphere
default: vsphere
Dynamic Enums (binding with vRO action)
input1:
type: string
title: Environment
default: ''
$dynamicEnum: '/data/vro-actions/com.org.utils/getEnvironment?environment={{vmenvironment}}'
.
.
.
.
input1:
type: string
title: podId
$dynamicEnum: /data/vro-actions/com.org.helpers/getPod
This is calling a vRO action getEnvironments
inside a action module com.org.utils
with 1 input environment
. Actions with no inputs can be called with using quotes.
using vRO Custom DataTypes
inputs:
accountName:
type: string
title: Account name
encrypted: true
displayName:
type: string
title: Display name
password:
type: string
title: Password
encrypted: true
confirmPassword:
type: string
title: Password
encrypted: true
ouContainer:
type: object
title: AD OU container
$data: 'vro/data/inventory/AD:OrganizationalUnit'
properties:
id:
type: string
type:
type: string
Resource Flags
Cloud Assembly includes several cloud template settings that adjust how a resource is handled at request time. Resource flag settings aren’t part of the resource object properties schema. For a given resource, you add the flag settings outside of the properties section as shown.
resources:
Cloud_Machine_1:
type: Cloud.Machine
preventDelete: true
properties:
image: coreos
flavor: small
attachedDisks:
- source: '${resource.Cloud_Volume_1.id}'
Cloud_Volume_1:
type: Cloud.Volume
properties:
capacityGb: 1
Available resource flags
Check list of all available resource flags here.
Examples of vSphere resources
vSphere virtual machine with CPU, memory, and operating system
resources:
demo-machine:
type: Cloud.vSphere.Machine
properties:
name: demo-machine
cpuCount: 1
totalMemoryMB: 1024
image: ubuntu
vSphere machine with a datastore resource
resources:
demo-vsphere-disk-001:
type: Cloud.vSphere.Disk
properties:
name: DISK_001
type: 'HDD'
capacityGb: 10
dataStore: 'datastore-01'
provisioningType: thick
vSphere machine with an attached disk
resources:
demo-vsphere-disk-001:
type: Cloud.vSphere.Disk
properties:
name: DISK_001
type: HDD
capacityGb: 10
dataStore: 'datastore-01'
provisioningType: thin
demo-machine:
type: Cloud.vSphere.Machine
properties:
name: demo-machine
cpuCount: 2
totalMemoryMB: 2048
imageRef: >-
https://packages.vmware.com/photon/4.0/Rev1/ova/photon-ova-4.0-ca7c9e9330.ova
attachedDisks:
- source: '${demo-vsphere-disk-001.id}'
vSphere machine with a dynamic number of disks
inputs:
disks:
type: array
title: disks
items:
title: disks
type: integer
maxItems: 15
resources:
Cloud_Machine_1:
type: Cloud.vSphere.Machine
properties:
image: Centos
flavor: small
attachedDisks: '${map_to_object(resource.Cloud_Volume_1[*].id, "source")}'
Cloud_Volume_1:
type: Cloud.Volume
allocatePerInstance: true
properties:
capacityGb: '${input.disks[count.index]}'
count: '${length(input.disks)}'
vSphere machine from a snapshot image. Append a forward slash and the snapshot name. The snapshot image can be a linked clone.
resources:
demo-machine:
type: Cloud.vSphere.Machine
properties:
imageRef: 'demo-machine/snapshot-01'
cpuCount: 1
totalMemoryMB: 1024
vSphere machine in a specific folder in vCenter
resources:
demo-machine:
type: Cloud.vSphere.Machine
properties:
name: demo-machine
cpuCount: 2
totalMemoryMB: 1024
imageRef: ubuntu
resourceGroupName: 'myFolder'
vSphere machine with multiple NICs
resources:
demo-machine:
type: Cloud.vSphere.Machine
properties:
image: ubuntu
flavor: small
networks:
- network: '${network-01.name}'
deviceIndex: 0
- network: '${network-02.name}'
deviceIndex: 1
network-01:
type: Cloud.vSphere.Network
properties:
name: network-01
network-02:
type: Cloud.vSphere.Network
properties:
name: network-02
vSphere machine with an attached tag in vCenter
resources:
demo-machine:
type: Cloud.vSphere.Machine
properties:
flavor: small
image: ubuntu
tags:
- key: env
value: demo
vSphere machine with a customization spec
resources:
demo-machine:
type: Cloud.vSphere.Machine
properties:
name: demo-machine
image: ubuntu
flavor: small
customizationSpec: Linux
vSphere machine with remote access
inputs:
username:
type: string
title: Username
description: Username
default: testUser
password:
type: string
title: Password
default: VMware@123
encrypted: true
description: Password for the given username
resources:
demo-machine:
type: Cloud.vSphere.Machine
properties:
flavor: small
imageRef: >-
https://cloud-images.ubuntu.com/releases/16.04/release-20170307/ubuntu-16.04-server-cloudimg-amd64.ova
cloudConfig: |
ssh_pwauth: yes
chpasswd:
list: |
${input.username}:${input.password}
expire: false
users:
- default
- name: ${input.username}
lock_passwd: false
sudo: ['ALL=(ALL) NOPASSWD:ALL']
groups: [wheel, sudo, admin]
shell: '/bin/bash'
runcmd:
- echo "Defaults:${input.username} !requiretty" >> /etc/sudoers.d/${input.username}
Market Place
The Marketplace provides VMware Solution Exchange cloud templates and images that help you build your template library and access supporting OVA or OVFs.
Other ways to create Cloud Assembly templates
Cloud template cloning
To clone a template, go to Design, select a source, and click Clone. You clone a cloud template to create a copy based on the source, then assign the clone to a new project or use it as starter code for a new application.
Uploading and downloading
You can upload, download, and share cloud template YAML code in any way that makes sense for your site. You can even modify template code using external editors and development environments.
Note A good way to validate shared template code is to inspect it in the Cloud Assembly code editor on the design page.
Integrating Cloud Assembly with a repository
An integrated git source control repository can make cloud templates available to qualified users as the basis for a new deployment. See How do I use Git integration in Cloud Assembly.
References
- Samples by Oleg Burdaev: https://gitlab.com/vra8/bp