Getting Started: Cloud Assembly Code Examples [CB10094]

Mayank Goyal
8 min readJul 11, 2022
Lear how to write vRA Cloud Assembly Code Examples | YAML Samples
Canonical link: https://cloudblogger.co.in/2022/06/14/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

--

--