VRA Cloud -Add the users in Projects and Change the owner of deployment dynamically using Python abx action

Recently i came across the used case , Where daily 100+ deployments are getting submitted via Service Account with CI/CD tool Jenkins or Code stream. Later VRA admin has to change the owner of the deployment to end user manually and To change the Owner of deployment currently VRA support only for those user who are explicitly part of project . VRA Admin first add the user in project and assign the permission then he does the change owner task.

Although it is 3-5 click Job but If we have to do for 100+ user , this can become very tedious task . To ease the Job I have created the Python ABX action and Yaml which will take the input who shall we be the owner of the deployment and Will add that user in Project and assign the ownership of deployment to specified user. Below shows the flow of operation.

As we see First we need Catalog Item which accepts the above items . For that below is the Yaml reference.

formatVersion: 1
inputs:
  email:
    type: string
    title: Owner Email
    pattern: "^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9]+.[a-zA-Z0-9]+$"
    description: 'Enter valid email Address exam: support@vmwarecode.com'
  role:
    type: string
    title: User Role
    enum:
      - administrator
      - member
      - viewer
  type:
    type: string
    title: User Type
    enum:
      - user
resources:
  Cloud_vSphere_Machine_1:
    type: Cloud.vSphere.Machine
    properties:
      image: Linux
      flavor: Small
      constraints:
        - tag: 'vCenter155:Cluster'
      networks:
        - network: '${resource.Cloud_vSphere_Network_1.id}'
  Cloud_vSphere_Network_1:
    type: Cloud.vSphere.Network
    properties:
      networkType: existing
      constraints:
        - tag: 'vCenter155:network'

Save the Blueprint and release it , Catalog Item will look like below.

Next step is create the Python ABX action, To do that we have some prerequisites
1. Save the VRA cloud api url in secrets by name VRAURL
2. Save CSP token with full role permission in secrets by name token.

Here is the screenshot for reference.

Once we have created above 2 secrets , we are good to go for creating Python ABX action.
Here is the code , Only thing I have hardcoded in Project ID in code in line number 11 . you may provide your project ID in code.

import requests
import json
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def handler(context, inputs):
    vraurl = context.getSecret(inputs['VRAURL'])
    token = context.getSecret(inputs['token'])
    deploymentid = inputs['deploymentId']
    id = '4d0f75d5-8855-481b-a78d-2e5957fd8cc4'
    email = inputs['requestInputs']['email']
    role = inputs['requestInputs']['role']
    type = inputs['requestInputs']['type']
    api_version_url = f'{vraurl}/iaas/api/about'
    headers = {
        'accept': "application/json",
        'content-type': "application/json"
    }
    output = requests.get(url=api_version_url, headers=headers, verify=False)
    if output.status_code == 200:
        latest_api_version = output.json()['latestApiVersion']
        apiversion = latest_api_version
        # Getting the Bearer token

        # Getting the bearer token
        iaasUrl = f"{vraurl}/iaas/api/login?apiVersion={apiversion}"
        refreshtoken = token
        iaasPayload = f'{{"refreshToken": "{refreshtoken}"}}'
        iaasApiOutput = requests.post(iaasUrl, data=iaasPayload, headers=headers, verify=False)
        if iaasApiOutput.status_code == 200:
            print('Authentication completed with VRA Cloud')
            jsondata = iaasApiOutput.json()['token']
            bearerToken = "Bearer " + jsondata
            bearertoken = bearerToken
            headers = {
                'accept': "application/json",
                'content-type': "application/json",
                'authorization': bearertoken
            }

            # adding the New User to Project
            url = f'{vraurl}/project-service/api/projects/{id}/principals'
            payload_schema = {
                "modify": [
                    {
                        "email": "",
                        "type": "",
                        "role": ""
                    }
                ],
                "remove": [
                    {
                        "email": "",
                        "type": ""
                    }
                ]
            }
            user_inputs = {
                "email": email,
                "type": type,
                "role": role
            }
            payload_schema['modify'][0].update(user_inputs)
            apioutput2 = requests.patch(url, headers=headers, data=json.dumps(payload_schema), verify=False)
            if apioutput2.status_code == 200:
                # Changing the owner
                print(f'User {email} has been added to Project')
                url2 = f'{vraurl}/deployment/api/deployments/{deploymentid}/requests'
                data = {
                    "actionId": "Deployment.ChangeOwner",
                    "inputs": {
                        'New Owner': email
                    }
                }
                apioutput3 = requests.post(url2, headers=headers, data=json.dumps(data), verify=False)
                print(apioutput3)
            else:
                print(apioutput2)
                print(apioutput2.json())
        else:
            print(iaasApiOutput.status_code)
            print(iaasApiOutput.json())
    else:
        print(output.status_code)
        print(output.json())

Below is the Reference screenshot of Python ABX action.

Once we have created the Python Action , Last step is create the subscription.

We are using Deployment completed event here and Here is the screenshot.

All configuration is sorted , Now Once you submit the build via CI/CD or self Service , It will add the user in project with specified permission and change the deployment owner.

How to provide VM lease date during the submission of VM build in VRA8 using ABX flow

Recently I was on working on scenario where we want to provide the lease date of VM at the time of submission. It is well known feature in 7.x which we get .


In VRA 8.x we can play with lease only with Day 2 actions.

With the help of extensibility you can provide the lease time during submission and use extensibility to trigger abx flow/ workflow as day 2.

The flow looks like below .

Here is my Yaml looks like.

formatVersion: 1
inputs:
  leaseDate:
    type: string
    title: Lease Date
    format: date-time
resources:
  Cloud_Network_1:
    type: Cloud.Network
    properties:
      constraints:
        - tag: 'vsphere:network'
      networkType: existing
  Cloud_vSphere_Machine_1:
    type: Cloud.vSphere.Machine
    properties:
      image: Images
      abxaction: 'yes'
      leaseDate: '${input.leaseDate}'
      cpuCount: 1
      totalMemoryMB: 1024
      awaitIp: false
      customizeGuestOs: false
      storage:
        constraints:
          - tag: 'vsphere:ds'
      constraints:
        - tag: 'vsphere:cluster'
      networks:
        - network: '${resource.Cloud_Network_1.id}'

Here us my Catalog log request will look like.

It is simple blueprint and catalog request where I am using date-time as format in input and will be using for my ABX flow .

Here is the quick look of both abx action in flow
1. VRAtoken
2. Extend Lesse

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def handler(context, inputs):
    vrafqdn = inputs['vrafqdn']
    username = inputs['username']
    password = inputs['password']
    refreshtokenurl = f"https://{vrafqdn}/csp/gateway/am/api/login?access_token"
    iaasUrl = f"https://{vrafqdn}/iaas/api/login"
    headers = {
        'accept': "application/json",
        'content-type': "application/json"
    }
    payload = f'{{"username":"{username}","password":"{password}"}}'
    apioutput = requests.post(refreshtokenurl, data=payload, verify=False, headers=headers)
    refreshtoken = apioutput.json()['refresh_token']
    iaasPayload = f'{{"refreshToken": "{refreshtoken}"}}'
    iaasApiOutput = requests.post(iaasUrl, data=iaasPayload, headers=headers, verify=False).json()['token']
    bearerToken = "Bearer " + iaasApiOutput
    print(bearerToken)
    outputs = {}
    outputs['vratoken'] = bearerToken
    return outputs
Here is another action of setting the lease.
import requests
import json
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def handler(context, inputs):
    token = inputs['vratoken']
    vrafqdn = inputs['vrafqdn']
    deploymentid = inputs['deploymentId']
    print(token)
    print(deploymentid)
    leasedate = inputs['requestInputs']['leaseDate']
    url = f'https://{vrafqdn}/deployment/api/deployments/{deploymentid}/requests'
    headers = {
        'accept': "application/json",
        'content-type': "application/json",
        'authorization': token
        }
    data = {
        "actionId": "Deployment.ChangeLease",
        "inputs": {
            'Lease Expiration Date': leasedate
            }
        }
    jdata = json.dumps(data)
    apioutput = requests.post(url, headers=headers,data=jdata, verify=False)
    print(apioutput)
    print(apioutput.json())

Once we are done with creating the ABX action , we can create ABX Flow .

Here is the quick look for ABX flow

Once we are done with setting the flow , Last Part which is left is configuring the subscription.

Here is the quick look how my subscription looks like , we will be setting this on Deployment completed.

Disclaimer : My VRA lab has internet connectivity , so I can use any module online , you may need to make the action as module and zip it ,before you use as ABX action/flow . If you are using VRA Cloud then we can use as it is without any change.
Also This flow will trigger twice once ,One time failure is expected .

How to use Compute allocation & Network configure subscription to change the IP address and Rename of VM in VRA 8

As we talk about the automation in VM provisioning , One of the crucial step is to get the IP address from external source.

Recently I was working on used case where we want to provide the IP addresses at the time of submitting the provisioning.

There are multiple ways to do it in VRA and VRO . I am using VRA ABX Python action to achieve it.

Used Case: I want to submit more than one machine at time and provide the IP addresses at same time. For my example I am using 2 Machines here.

Subscription Used:

  • Compute Allocation
  • Network Configure

First Lets take a look at Blueprint’s Yaml where we define all custom properties.

formatVersion: 1
inputs:
  firstVM:
    type: string
    title: NewVMName1
  SecondVM:
    type: string
    title: NewVMName2
  VM1IP:
    type: string
    title: VM-1-IP
  VM2IP:
    title: VM-2-IP
    type: string
resources:
  vSphere_Machine:
    type: Cloud.Machine
    properties:
      firstVM: '${input.firstVM}'
      SecondVM: '${input.SecondVM}'
      VM1IP: '${input.VM1IP}'
      VM2IP: '${input.VM2IP}'
      abxaction: 'yes'
      count: 2
      image: VMwareCode-CentOS
      flavor: VMwareCode-small
      networks:
        - network: '${resource.vSphere_Network.id}'
          assignment: static
  vSphere_Network:
    type: Cloud.vSphere.Network
    properties:
      networkType: existing
      constraints:
        - tag: 'vsphere:network'

  • As we see above , I am using 4 Inputs as 2 VM names and 2 IP addresses in line 19-22
  • Line 23 we will use for condition in subscription
  • Also I am using static assignment in line 28-29
  • Line 35 is to Target the Network Profile where I have defined the Range

Once we are done with Blueprint, that is how it will look like when we click on Deploy

Since I am changing the name of VM and assigning the IP , I would need 2 ABX action
Below is the action is to change the VM Name as per Input


Below is the action Code in Python
def handler(context, inputs):
    firstVM = inputs['customProperties']['firstVM']
    secondVM = inputs['customProperties']['SecondVM']
    returnobj = inputs
    returnobj['resourceNames'][0] = firstVM
    returnobj['resourceNames'][1] = secondVM
    return returnobj

Here is the action for Assigning the IP addresses to correspond VMs.

Below is the python code for same
def handler(context, inputs):
    firstVMIP = inputs['customProperties']['VM1IP']
    SecondVMIP = inputs['customProperties']['VM2IP']
    outputs = {}
    addresses = [[]]
    outputs["addresses"] = addresses
    outputs["addresses"][0]=[str(firstVMIP)]
    outputs["addresses"].append([SecondVMIP])
    return outputs

If you have followed the article without missing any step, means you are done Python and Yaml code stuff.
Now all is left is Creation of the subscription If already not exist and Map to above created ABX python action.

To create the new Subscription follow below
Click on Cloud Assembly => Click Extensibility => Subscription = > Click New Subscription


Provide Name, enable Subscription and on Event Topic Choose Compute Allocation

If you noticed in YAML line number 23 I have specified the condition abxaction: yes

      abxaction: 'yes'

In subscription we are using that as condition to run and in action/workflow choose abx and above created action.


Click Save and we are done with Rename subscription.

Click New subscription once again and this time we will choose Network Configure subscription and network action , Rest all settings will be same.

so we have done all the coding and configuration , Now it is time to submit the VM provisioning request .

Once we submit this , You can check the outcome in action result or once vm allocation is done.


As we see the name as we submitted during provisioning, lets check the IP of each .


Both VMs got renamed and static IP which we entered has been applied to VMs.

Disclaimer: Indexing issue for multi Dimensional array has been fixed in 8.4.1, which was getting interchanged in 8.3 and 8.4