This article series will focus on specific tips and tricks to aid customisation and flexibility of vRA 8.x.
Contents:
- Part 1 – Array expressions
- Part 2 – Ternary Logic
- Part 3 – Property Groups
I have always been a fan of abstracting personality from code – this leads to being able to handle changes better and aids portability. To this purpose I have been a heavy user of vRA Property Groups to store the configuration of a deployment. In this article I will demonstrate how to use an array within a Property Group to create an environment definition that is referenced by the deployment input.
The objective:
- Deploy to DevTest or Production environments from a single blueprint
- Scale the deployment both horizontally and vertically between these two environments:
- Single-node tiers in DevTest, HA in Production
- Minimum CPU and Memory in DevTest, Final-size CPU and Memory in Production
- Connect to different networks depending on the environment
- Abstract the environment specification from the Cloud Template
I will be using a three-tiered app named “Cool App” as an example for this article which has been written for/tested against vRA 8.60. Here’s how to do it:
1. Define the Property Schema
For later use by the blueprint, we need to define an array of values and how we will reference them from within the Property Group. To meet the objectives in this article I have created the following schema:
- [0] CPU – Dev/Test
- [1] Memory – Dev/Test
- [2] No. of Nodes – Dev/Test
- [3] CPU – Prod
- [4] Memory – Prod
- [5] No. of Nodes – Prod
2. Create a Property Group
- Navigate to Cloud Assembly / Design / Property Groups and select New Property Group
- Change the Property Group type to Constant Values
- Give it a name, Display Name, and Description
- Do not change the scope button
- Select the Project. This is important as the we may wish to include a secret in the future and these can only be created at the Project level

- Create a new property named web_server
- Change the type to Array
- Enter the array schema we defined earlier as the description. This will aid in selecting the right value in the blueprint expression and identifying values for a future change.
- Enter desired constant values as per the schema prefacing each with a dash and a space – this is the vRA expression syntax used to define an array (you see this in the blueprint YAML also).
- Select Create

- Create properties also for app_server and db_server with the following values:


- Finally select Create to complete the Property Group

3. Create the Cloud Template
- Create the Cool App blueprint with three vSphere Machines and two networks (I am using NSX here)
- Attach the Web servers to the DMZ network, and the App and DB servers to the Internal network
- Create Inputs for the environment
- Select your image and customization spec
- Add whatever other properties you may need – e.g. tags, properties for ABX actions etc
- Use ternary logic expression to define the properties for cpuCount:, totalMemoryMB:, and count: as per the below example for the Web Sever machine:
cpuCount: '${input.environment == "Dev" ? propgroup.CoolApp.web_server[0] : propgroup.CoolApp.web_server[3] }
In natural language, this would mean “If Dev environment is selected in the request form, set the cpuCount value as specified in the web_server property within the CoolApp Property Group at position 0, otherwise set the cpuCount value as defined in position 3”
As per our schema, this would set CPU to be 1 for Dev or 2 for Prod
Here are all the expressions:
Web Server:
cpuCount: '${input.environment == "Dev" ? propgroup.CoolApp.web_server[0] : propgroup.CoolApp.web_server[3] }'
totalMemoryMB: '${input.environment == "Dev" ? propgroup.CoolApp.web_server[1] : propgroup.CoolApp.web_server[4] }'
count: '${input.environment == "Dev" ? propgroup.CoolApp.web_server[2] : propgroup.CoolApp.web_server[5] }'
App Server:
cpuCount: '${input.environment == "Dev" ? propgroup.CoolApp.app_server[0] : propgroup.CoolApp.app_server[3] }'
totalMemoryMB: '${input.environment == "Dev" ? propgroup.CoolApp.app_server[1] : propgroup.CoolApp.app_server[4] }'
count: '${input.environment == "Dev" ? propgroup.CoolApp.app_server[2] : propgroup.CoolApp.app_server[5] }'
DB Server
cpuCount: '${input.environment == "Dev" ? propgroup.CoolApp.db_server[0] : propgroup.CoolApp.db_server[3] }'
totalMemoryMB: '${input.environment == "Dev" ? propgroup.CoolApp.db_server[1] : propgroup.CoolApp.db_server[4] }'
count: '${input.environment == "Dev" ? propgroup.CoolApp.db_server[2] : propgroup.CoolApp.db_server[5] }'
- Use ternary logic also to define which network the deployment will use depending on the environment. You could choose to add this also to the property schema but I wanted to show a simpler ternary expression example here with hard-coded values:
Net-DMZ:
type: Cloud.NSX.Network
properties:
networkType: existing
constraints:
- tag: '${input.environment == "Dev" ? "net-t98-dev-dmz" : "net-t98-prod-dmz"}'
Net-Internal:
type: Cloud.NSX.Network
properties:
networkType: existing
constraints:
- tag: '${input.environment == "Dev" ? "net-t98-dev-internal" : "net-t98-prod-internal"}'
Your final blueprint should look like this:

Here is the complete blueprint YAML you can copy and paste to make it easier
name: Cool App
formatVersion: 1
version: 1
# ----------------------------------------------------#
inputs:
tenant:
type: string
title: Tenant Designation
description: Select a three character designation e.g. T03
default: T98
maxLength: 3
minLength: 3
pattern: '([A-Z])\d\d'
environment:
type: string
title: Environment
description: Select a deployment environment
oneOf:
- title: Development
const: Dev
- title: Production
const: Prod
default: Dev
# ------------------ RESOURCES --------------------#
resources:
Net-DMZ:
type: Cloud.NSX.Network
properties:
networkType: existing
constraints:
- tag: '${input.environment == "Dev" ? "net-t98-dev-dmz" : "net-t98-prod-dmz"}'
# ----------------------------------------------------#
Web_Server:
type: Cloud.vSphere.Machine
properties:
image: centos-79
customizationSpec: mlab-linux-spec-merc
cpuCount: '${input.environment == "Dev" ? propgroup.CoolApp.web_server[0] : propgroup.CoolApp.web_server[3] }'
totalMemoryMB: '${input.environment == "Dev" ? propgroup.CoolApp.web_server[1] : propgroup.CoolApp.web_server[4] }'
count: '${input.environment == "Dev" ? propgroup.CoolApp.web_server[2] : propgroup.CoolApp.web_server[5] }'
folderName: Tenants\_Dev
tags:
- key: AppName
value: Cool App
- key: Environment
value: '${input.environment}'
- key: Tenant
value: '${input.tenant}'
- key: ServerRole
value: Web Server
- key: SecurityZone
value: DMZ
constraints:
- tag: 'cloud:private'
networks:
- network: '${resource["Net-DMZ"].id}'
assignment: static
# -------------------- ABX Actions -------------------#
create_dns: true
cnameRecord: null
min_install: true
highstate: true
# ----------------- Salt Config -----------------------------#
grains: |
AppName: Cool App
Environment: Production
Tenant: T98
serverRole: Web Server
SecurityZone: DMZ
minionconfig: |
master: '${propgroup.SaltStackConfiguration.masterAddress}'
master_finger: '${propgroup.SaltStackConfiguration.masterFingerPrint}'
id: '${self.resourceName}'
# ----------------------------------------------------#
App_Server:
type: Cloud.vSphere.Machine
properties:
image: centos-79
customizationSpec: mlab-linux-spec-merc
cpuCount: '${input.environment == "Dev" ? propgroup.CoolApp.app_server[0] : propgroup.CoolApp.app_server[3] }'
totalMemoryMB: '${input.environment == "Dev" ? propgroup.CoolApp.app_server[1] : propgroup.CoolApp.app_server[4] }'
count: '${input.environment == "Dev" ? propgroup.CoolApp.app_server[2] : propgroup.CoolApp.app_server[5] }'
folderName: Tenants\_Dev
tags:
- key: AppName
value: Cool App
- key: Environment
value: '${input.environment}'
- key: Tenant
value: '${input.tenant}'
- key: ServerRole
value: App Server
- key: SecurityZone
value: Internal
constraints:
- tag: 'cloud:private'
networks:
- network: '${resource["Net-Internal"].id}'
assignment: static
# -------------------- ABX Actions -------------------#
create_dns: true
cnameRecord: null
min_install: true
highstate: true
# ----------------- Salt Config -----------------------------#
grains: |
AppName: Cool App
Environment: Production
Tenant: T98
serverRole: App Server
SecurityZone: Internal
minionconfig: |
master: '${propgroup.SaltStackConfiguration.masterAddress}'
master_finger: '${propgroup.SaltStackConfiguration.masterFingerPrint}'
id: '${self.resourceName}'
# ----------------------------------------------------#
DB_Server:
type: Cloud.vSphere.Machine
properties:
image: centos-79
customizationSpec: mlab-linux-spec-merc
cpuCount: '${input.environment == "Dev" ? propgroup.CoolApp.db_server[0] : propgroup.CoolApp.db_server[3] }'
totalMemoryMB: '${input.environment == "Dev" ? propgroup.CoolApp.db_server[1] : propgroup.CoolApp.db_server[4] }'
count: '${input.environment == "Dev" ? propgroup.CoolApp.db_server[2] : propgroup.CoolApp.db_server[5] }'
folderName: Tenants\_Dev
tags:
- key: AppName
value: Cool App
- key: Environment
value: '${input.environment}'
- key: Tenant
value: '${input.tenant}'
- key: ServerRole
value: Database Server
- key: SecurityZone
value: Internal
constraints:
- tag: 'cloud:private'
networks:
- network: '${resource["Net-Internal"].id}'
assignment: static
# -------------------- ABX Actions -------------------#
create_dns: true
cnameRecord: null
min_install: true
highstate: true
# ----------------- Salt Config -----------------------------#
grains: |
AppName: Cool App
Environment: Production
Tenant: T98
serverRole: Database Server
SecurityZone: Internal
minionconfig: |
master: '${propgroup.SaltStackConfiguration.masterAddress}'
master_finger: '${propgroup.SaltStackConfiguration.masterFingerPrint}'
id: '${self.resourceName}'
Net-Internal:
type: Cloud.NSX.Network
properties:
networkType: existing
constraints:
- tag: '${input.environment == "Dev" ? "net-t98-dev-internal" : "net-t98-prod-internal"}'
Mission Accomplished!
Selecting Dev from the deployment form will deploy a single instance of each Tier with Dev-sized CPU and RAM and attached to Development DMZ and Internal networks
Selecting Prod from the deployment form will deploy three web servers, two app servers, and two database servers with desired production CPU and RAM values which are attached to Production DMZ and Internal networks
Closing Thoughts
I hope you enjoyed reading this article and have a new appreciation of the power of Property Groups when leveraging other expression syntax tricks like arrays and ternary logic. Some other items you may want to reference inside a Property Group are:
resourceGroupName:
storage:
sshKey:
(referencing a Secret)
Until next time!
2 thoughts on “vRA Tips and Tricks – Part 3”