VMware Cloud Community
jselover16
Contributor
Contributor

vRA 8.4 - Cloud Template Nested Arrays and Dynamic Networking

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}'
 

 

 
I have since modified the template to not rely on the nested array but I still have issues with allocating the network object as a cluster as the count fails when its more than 1.
 
By un-nesting the arrays and using the vmName property as a key, I am attempting to filter the objects created to assign what is configured for which vm.
 

 

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}'

 

 
I am still having issues with the network resource having a count greater than 1 and would like to know if there are ways around that.
 
Thanks for your help!
Labels (2)
0 Kudos
5 Replies
michaelbachmann
Contributor
Contributor

same problem here... tried for hours now but did not found a solution

Tags (1)
0 Kudos
aamodei01
Enthusiast
Enthusiast

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!

0 Kudos
jselover16
Contributor
Contributor

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}'
0 Kudos
sujithstanly27
VMware Employee
VMware Employee

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?

0 Kudos
RoMaKa
Enthusiast
Enthusiast

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

0 Kudos