Hey Everyone,
My goal is to build a dynamic cloud template that I can use for a base template for onboarding. I have a few thousand machines to onboard and I want to onboard them in one cloud template that could be matched with just about every configuration of VM. Multi-Nic, Multi-Disk, in multiple VMs. The deployments will be separated by application ID and function as defined by their owners. This is a very loose grouping that can cause deployments with over 50 virtual machines, with several portgroups associated with the single deployment. I have considered adding vlan as another layer to further break down deployments, but there are still cases where I would want a dynamic number of networks to be available.
I thought the easiest way to gather this information would be to create a nested input array to house all the information per VM. This is the initial version of that idea.
formatVersion: 1
inputs:
vmArray:
type: array
title: Virtual Machine Information
description: Information about the Virtual Machines being provisioned
minItems: 1
items:
type: object
title: Virtual Machine Object
description: Individual Virtual Machine
properties:
vmName:
type: string
title: Virtual Machine Name
description: Name of the virtual machine being requested using the SECU naming convention
image:
type: string
title: Template
description: Name of the template being used for this Virtual Machine
enum:
- Win2016 Std template
- Win2019 Std template
default: Win2016 Std template
cpu:
type: object
title: Virtual Machine CPU Information
properties:
totalcores:
type: integer
title: Total Cores
description: Total number of cores. NOT cores per socket. Must be an even number
min: 2
max: 256
default: 2
sockets:
type: integer
title: Sockets
descrption: Total number of cores must be divisible by number of sockets.
enum:
- 1
- 2
- 4
default: 1
memory:
type: integer
title: Memory
description: Total Memory in GB
min: 2
max: 512
default: 4
networkArray:
type: array
title: Network Information
minItems: 1
items:
type: object
title: Network configuration per NIC
properties:
nicID:
type: number
title: NIC ID
descprtion: ID of NIC between 0 and 3
min: 0
max: 3
assignment:
type: string
title: Assignment
description: Defines whether the IP is Statically or Dynamically defined for NIC.
enum:
- static
- dynamic
default: static
ipAddress:
type: string
title: IP Address
description: IP address for NIC if statically assigned.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
vlanID:
type: number
title: VLAN ID
description: 4 digit VLAN ID associated with network connected to NIC. Example 0024
pattern: '^[0-9]{4}$'
gateway:
type: string
title: Gateway
description: Default gateway of the network associated with NIC.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
cidr:
type: string
title: Subnet CIDR
description: Subnet Mask in CIDR format. Example 192.168.100.0/24
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,2}$'
dnsServers:
type: array
title: DNS Servers
description: DNS Servers for network connected to NIC.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
dnsSearchDomain:
type: array
title: DNS Search Domains
description: Search domains use when resolving unqualified names in DNS.
default: ncsecu.local
domain:
type: string
title: Domain
description: Domains suffix used for the hostname on this NIC.
scsiControllers:
type: integer
title: SCSI Controllers
description: Number of SCSI Controllers attached to Virtual Machine
min: 1
max: 4
default: 1
diskArray:
type: array
title: Storage Information
items:
type: object
title: Configuration per additional disk
properties:
name:
type: string
title: disk name
description: descriptive name for this disk
default: Additional Disk
scsiController:
type: string
title: SCSI Controller
descrption: SCSI Controller for this Disk
enum:
- SCSI_Controller_0
- SCSI_Controller_1
- SCSI_Controller_2
- SCSI_Controller_3
default: SCSI_Controller_0
scsiID:
type: integer
title: SCSI ID
description: SCSI ID on SCSI Controller for this DISK (Cannot be 0/0)
min: 0
max: 8
default: 1
diskSize:
type: integer
title: Disk Size GB
description: Disk size in GB
min: 1
max: 4096
default: 20
I planned to use this to hopefully loop through the array and "fill out" the information in the resource portion but I have found that I don't know if the nested arrays will work like I am assuming or at all. I don't know if it is possible to have the count.index unique to the array or if that is just a interchangeable variable.
Here is my resources section...
resources:
PortGroup:
type: Cloud.vSphere.Network
allocatePerInstance: true
properties:
networkType: existing
name: '${"vlan-" + input.vmArray[count.index].networkArray[count.index].vlanID}'
constraints:
- tag: '${"vlan:" + input.vmArray[count.index].networkArray[count.index].vlanID}'
count: '${length(input.vmArray[count.index].networkArray)}'
VirtualMachine:
type: Cloud.vSphere.Machine
recreatePropertiesOnUpdate:
- vmArray
allocatePerInstance: true
properties:
image: Win2016 Std template
cpuCount: 4
count: '${length(input.vmArray)}'
totalMemoryMB: 1024
name: '${input.vmarray[*].vmName}'
networkConfig: '${input.vmArray[count.index].networkArray}'
networks: '${map_to_object(resource.PortGroup[*].id, "network")}'
attachedDisks: '${map_to_object(resource.AdditionalDisks[*].id, "source")}'
AdditionalDisks:
type: Cloud.vSphere.Disk
allocatePerInstance: true
properties:
capacityGb: '${input.vmArray[count.index].diskArray[count.index].diskSize}'
count: '${length(input.vmArray[count.index].diskArray)}'
name: '${input.vmArray[count.index].diskArray[count.index].diskName}'
SCSIController: '${input.vmArray[count.index].diskArray[count.index].scsiController}'
formatVersion: 1
inputs:
vmArray:
type: array
title: Virtual Machine Information
description: Information about the Virtual Machines being provisioned
minItems: 1
items:
type: object
title: Virtual Machine Object
description: Individual Virtual Machine
properties:
vmName:
type: string
title: Virtual Machine Name
description: Name of the virtual machine being requested using the SECU naming convention
image:
type: string
title: Template
description: Name of the template being used for this Virtual Machine
enum:
- Win2016 Std template
- Win2019 Std template
default: Win2016 Std template
cpu:
type: object
title: Virtual Machine CPU Information
properties:
totalcores:
type: integer
title: Total Cores
description: Total number of cores. NOT cores per socket. Must be an even number
min: 2
max: 256
default: 2
sockets:
type: integer
title: Sockets
descrption: Total number of cores must be divisible by number of sockets.
enum:
- 1
- 2
- 4
default: 1
memory:
type: integer
title: Memory
description: Total Memory in GB
min: 2
max: 512
default: 4
networkArray:
type: array
title: Network Information
minItems: 1
items:
type: object
title: Network configuration per NIC
properties:
vmName:
type: string
title: Virtual Machine Name
description: Used to associate Network with VM.
nicID:
type: number
title: NIC ID
descprtion: ID of NIC between 0 and 3
min: 0
max: 3
assignment:
type: string
title: Assignment
description: Defines whether the IP is Statically or Dynamically defined for NIC.
enum:
- static
- dynamic
default: static
ipAddress:
type: string
title: IP Address
description: IP address for NIC if statically assigned.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
vlanID:
type: number
title: VLAN ID
description: 4 digit VLAN ID associated with network connected to NIC. Example 0024
pattern: '^[0-9]{4}$'
gateway:
type: string
title: Gateway
description: Default gateway of the network associated with NIC.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
cidr:
type: string
title: Subnet CIDR
description: Subnet Mask in CIDR format. Example 192.168.100.0/24
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,2}$'
dnsServers:
type: array
title: DNS Servers
description: DNS Servers for network connected to NIC.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
dnsSearchDomain:
type: array
title: DNS Search Domains
description: Search domains use when resolving unqualified names in DNS.
domain:
type: string
title: Domain
description: Domains suffix used for the hostname on this NIC.
default: ncsecu.local
diskArray:
type: array
title: Storage Information
items:
type: object
title: Configuration per additional disk
properties:
vmName:
type: string
title: VM Name
description: Virtual Machine Name
name:
type: string
title: disk name
description: descriptive name for this disk
default: Additional Disk
scsiController:
type: string
title: SCSI Controller
descrption: SCSI Controller for this Disk
enum:
- SCSI_Controller_0
- SCSI_Controller_1
- SCSI_Controller_2
- SCSI_Controller_3
default: SCSI_Controller_0
scsiID:
type: integer
title: SCSI ID
description: SCSI ID on SCSI Controller for this DISK (Cannot be 0/0)
min: 0
max: 8
default: 1
diskSize:
type: integer
title: Disk Size GB
description: Disk size in GB
min: 1
max: 4096
default: 20
resources:
PortGroup:
type: Cloud.vSphere.Network
allocatePerInstance: true
properties:
networkType: existing
name: '${"vlan-" + input.networkArray[count.index].vlanID}'
constraints:
- tag: '${"vlan:" + input.networkArray[count.index].vlanID}'
count: '${length(input.networkArray)}'
vmname: '${input.networkArray[count.index].vmName}'
VirtualMachine:
type: Cloud.vSphere.Machine
recreatePropertiesOnUpdate:
- vmConfig
- diskConfig
- networkConfig
allocatePerInstance: true
properties:
image: Win2016 Std template
cpuCount: '${input.vmArray[count.index].cpu.totalcores}'
count: '${length(input.vmArray)}'
totalMemoryMB: '${input.vmArray[count.index].memory}'
name: '${input.vmArray[count.index].vmName}'
networkConfig: '${input.networkArray}'
vmConfig: '${input.vmArray}'
diskConfig: '${input.diskArray}'
networks: '${map_to_object(filter_by({resource.PortGroup[*]}, vmname => vmname == resource.VirtualMachine.name}).id, "network")}'
attachedDisks: '${map_to_object(filter_by({resource.AdditionalDisks[*]}, vmname => vmname == resource.VirtualMachine.name}).id, "source")}'
AdditionalDisks:
type: Cloud.vSphere.Disk
allocatePerInstance: true
properties:
capacityGb: '${input.diskArray[count.index].diskSize}'
name: '${input.diskArray[count.index].diskName}'
SCSIController: '${input.diskArray[count.index].scsiController}'
count: '${length(input.diskArray)}'
unitNumber: '${input.diskArray[count.index].scsiID}'
vmname: '${input.diskArray[count.index].vmName}'
same problem here... tried for hours now but did not found a solution
Hey - I know this is a little dated, but I'm trying you blueprint out as it very close to our use case of multiple machine, multiple unique disk config per machine, and I noticed you used the filter function embedded into the map_to function which was something I hadn't thought about. I think I understand how you are creating the key:value pair there, but when I tried out your blueprint, I'm getting an error:
Failed
class String cannot be cast to class java.util.List (String and java.util.List are in module java.base of loader 'bootstrap')
- I have narrowed this down to the attachedDisks like, and not being 100% a java guru, I did my homework, I believe I understand the issue, but the problem is I cant see what the data model looks like going into line, so I'm having a hard time walking it backward to understand. Did you run into this or did this stop functioning after a certain vRA version? (you mentioned 8.4, I'm running 8.6.2)
thanks!
I created a support ticket and found that the nested arrays are not supported as of now. I do have the storage piece worked out but I still cannot dynamically add multiple networks. Here is what I currently have but its not fully tested and production ready.
formatVersion: 1
inputs:
vmArray:
type: array
title: Virtual Machine Information
description: Information about the Virtual Machines being provisioned
minItems: 1
items:
type: object
title: Virtual Machine Object
description: Individual Virtual Machine
properties:
vmName:
type: string
title: Virtual Machine Name
description: Name of the virtual machine being requested using the SECU naming convention
image:
type: string
title: Template
description: Name of the template being used for this Virtual Machine
enum:
- Win2016 Std template
- Win2019 Std template
default: Win2016 Std template
cpu:
type: object
title: Virtual Machine CPU Information
properties:
totalcores:
type: integer
title: Total Cores
description: Total number of cores. NOT cores per socket. Must be an even number
min: 2
max: 256
default: 2
sockets:
type: integer
title: Sockets
descrption: Total number of cores must be divisible by number of sockets.
enum:
- 1
- 2
- 4
default: 1
memory:
type: integer
title: Memory
description: Total Memory in GB
min: 2
max: 512
default: 4
networkArray:
type: array
title: Network Information
minItems: 1
items:
type: object
title: Network configuration per NIC
properties:
vmName:
type: string
title: Virtual Machine Name
description: Used to associate Network with VM.
nicID:
type: integer
title: NIC ID
descprtion: ID of NIC between 0 and 1
min: 0
max: 1
assignment:
type: string
title: Assignment
description: Defines whether the IP is Statically or Dynamically defined for NIC.
enum:
- static
- dynamic
default: static
ipAddress:
type: string
title: IP Address
description: IP address for NIC if statically assigned.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
vlanID:
type: number
title: VLAN ID
description: 4 digit VLAN ID associated with network connected to NIC. Example 0024
pattern: '^[0-9]{4}$'
gateway:
type: string
title: Gateway
description: Default gateway of the network associated with NIC.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
cidr:
type: string
title: Subnet CIDR
description: Subnet Mask in CIDR format. Example 192.168.100.0/24
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,2}$'
dnsServers:
type: array
title: DNS Servers
description: DNS Servers for network connected to NIC.
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
dnsSearchDomain:
type: array
title: DNS Search Domains
description: Search domains use when resolving unqualified names in DNS.
domain:
type: string
title: Domain
description: Domains suffix used for the hostname on this NIC.
default: ncsecu.local
diskArray:
type: array
title: Storage Information
items:
type: object
title: Configuration per additional disk
properties:
vmName:
type: string
title: Virtual Machine Name
description: Virtual Machine Name
name:
type: string
title: disk name
description: descriptive name for this disk
default: Additional Disk
scsiController:
type: string
title: SCSI Controller
descrption: SCSI Controller for this Disk
enum:
- SCSI_Controller_0
- SCSI_Controller_1
- SCSI_Controller_2
- SCSI_Controller_3
default: SCSI_Controller_0
scsiID:
type: integer
title: SCSI ID
description: SCSI ID on SCSI Controller for this DISK (Cannot be 0/0)
min: 0
max: 8
default: 1
diskSize:
type: integer
title: Disk Size GB
description: Disk size in GB
min: 1
max: 4096
default: 20
resources:
PortGroup0:
type: Cloud.vSphere.Network
properties:
networkType: existing
name: '${"vlan-" + input.networkArray[count.index].vlanID}'
constraints:
- tag: '${"vlan:" + input.networkArray[count.index].vlanID}'
vmname: '${input.networkArray[count.index].vmName}'
nicID: '${input.networkArray[count.index].nicID}'
VirtualMachine:
type: Cloud.vSphere.Machine
recreatePropertiesOnUpdate:
- vmConfig
- diskConfig
- networkConfig
allocatePerInstance: true
properties:
image: '${input.vmArray[count.index].image}'
cpuCount: '${input.vmArray[count.index].cpu.totalcores}'
count: '${length(input.vmArray)}'
totalMemoryMB: '${input.vmArray[count.index].memory}'
name: '${input.vmArray[count.index].vmName}'
networkConfig: '${input.networkArray}'
vmConfig: '${input.vmArray}'
diskConfig: '${input.diskArray}'
networks:
- network: '${resource.PortGroup0.id}'
attachedDisks: '${map_to_object(filter_by(resource.AdditionalDisk[*], x => x.vmname == input.vmArray[count.index].vmName).id, "source")}'
AdditionalDisk:
type: Cloud.vSphere.Disk
allocatePerInstance: true
properties:
capacityGb: '${input.diskArray[count.index].diskSize}'
name: '${input.diskArray[count.index].diskName}'
SCSIController: '${input.diskArray[count.index].scsiController}'
count: '${length(input.diskArray)}'
unitNumber: '${input.diskArray[count.index].scsiID}'
vmname: '${input.diskArray[count.index].vmName}'
Hello,
I am trying to create a similar Cloud Template where the user needs to create multiple VMs. Each VM will ahve only a Single NIC but its different Network for each VM. The User should be able to specify the Network Name and IP Address for each VM. I was able to perform it using the vmArray but the Network Array is giving me the similar issue where the maximum count is 1.
Any thoughts or were you able to fix your template?
Hi everyone,
I had the same problem with 8.13.1 and was talking to a support technician about that. The "count" property on the network resource is limited to be either 0 (no network resource) or 1 (one network resource). You can see the according error message if you try to enter "count: 2" in the network resource properties. I made a feature request to change the behaviour of the network-count to the behaviour of the disk-/machine-count, but I do not know if or when that will be implemented...
B*B,
Robert