VCF Automation Blog

from Stefan Schnell

VCF Automation offers different runtime environments, Node.js, PowerShell and Python. Each of them has its own handler routine, more or less. This is a wrapper that contains the commands to be executed within a defined frame. This frame specifically defines the input and output interface. This blog post describes how these handler routines can be emulated locally. This gives the opportunity to test a development as if it were being executed in the context of VCF Automation.

Emulation Templates
for the Runtime Environments


The handler routines are structured equivalently. The original handler code from VCF Automation is included between the Begin and End comments. The variables Context and Inputs of the handler are defined below. The variable context contains dummy values and inputs can be set as desired. Then the handler function is executed. Finally the return values are output.

Node.js

Node.js works exactly as described above, except that the return is done via a callback routine, which is also part of the VCF Automation frame.

/**
 * Aria Automation handler emulation for Node.js.
 */

// Begin ---------------------------------------------------------------

exports.handler = (context, inputs, callback) => {

  console.log('Inputs were ' + JSON.stringify(inputs));
  console.log(inputs.name);



  callback(undefined, {status: "done", result: "Result"});

}

// End -----------------------------------------------------------------

var context = {
  executionId: '5c281fc2-d380-41a1-814a-c63a06ac8522',
  returnType: 'Properties',
  vcoUrl: 'http://localhost:8280/vco',
  getToken: function() {}
}

var inputs = {
  name: "Stefan Schnell",
  city: "Oberirsen"
}

callback = (parameter1, outputs) => {
  // Output is from type JSON object.
  //console.log(JSON.stringify(outputs));
  console.log(outputs.status);
  console.log(outputs.result);
}

exports.handler(context, inputs, callback);

// console.log('\nPress any key to continue...');
// process.stdin.setRawMode(true);
// process.stdin.resume();
// process.stdin.on('data', process.exit.bind(process, 0));


Python

The approaches shown here can also be used directly in VCF Automation without modifications. VCF Automation only executes the handler function and ignores the call of the main function. On the one hand this generates dead code, because it is never executed in the context of VCF Automation, but on the other hand we have code that we can also use immediately outside of Aria Automation.

"""
Aria Automation handler emulation for Python.
"""

# Begin ----------------------------------------------------------------

import json

def handler(context, inputs):
    """ Standard Aria Automation handler function """

    json_out = json.dumps(inputs, separators=(',', ':'))
    print(f"Inputs were {json_out}")



    outputs = {
        "status": "done",
        "result": "Result"
    }

    return outputs

# End ------------------------------------------------------------------

def main():
    """ Main function """

    context = {
        "executionId": "274cd8fb-39b5-4c5c-8c20-db2d6fc9cc02",
        "returnType": "Properties",
        "vcoUrl": "http://localhost:8280/vco",
        "getToken": lambda: None
    }

    inputs = {
        "name": "Stefan Schnell",
        "city": "Oberirsen"
    }

    outputs = handler(context, inputs)

    # Output is from type Dictionary and stores the data in key:value pairs.
    print(outputs["status"])
    print(outputs["result"])

    # print("\nPress any key to continue...")
    # input()

if __name__ == "__main__":
    main()

"""
Aria Automation handler emulation for Python with the use of the bearer
token.
Hint: All inputs are prepared for the HOL.

@author Stefan Schnell <mail@stefan-schnell.de>
@license MIT
@version 0.2.0
"""

import getpass
import ssl
import urllib.request

# Begin-----------------------------------------------------------------

import json

def handler(context, inputs):
    """ Standard Aria Automation handler function """

    result = {}

    try:

        vcoUrl = context["vcoUrl"]
        bearerToken = context['getToken']()

        jsonOut = json.dumps(inputs, separators=(',', ':'))
        print("Inputs were {0}".format(jsonOut))



        outputs = {
            "status": "done",
            "error": None,
            "result": result
        }

    except Exception as err:

        outputs = {
            "status": "incomplete",
            "error": repr(err),
            "result": result
        }

    return outputs

# End-------------------------------------------------------------------

def getBearerToken(url, userName, userPassword):
    """ Delivers the bearer token """

    try:

        data = { 'username': userName, 'password': userPassword }
        data = json.dumps(data)
        data = str(data)
        data = data.encode('utf-8')

        # Gets refresh token
        requestRefreshToken = urllib.request.Request(
            url = url + "/csp/gateway/am/api/login?access_token",
            method = "POST",
            data = data
        )

        requestRefreshToken.add_header(
            "Content-Type", "application/json"
        )

        responseRefreshToken = urllib.request.urlopen(
            requestRefreshToken,
            context = ssl._create_unverified_context()
        )

        if responseRefreshToken.getcode() == 200:
            refreshToken = json.loads(responseRefreshToken.read())

            data = { 'refreshToken': refreshToken["refresh_token"] }
            data = json.dumps(data)
            data = str(data)
            data = data.encode('utf-8')

            # Gets bearer token
            requestBearerToken = urllib.request.Request(
                url = url + "/iaas/api/login",
                method = "POST",
                data = data
            )

            requestBearerToken.add_header(
                "Content-Type", "application/json"
            )

            responseBearerToken = urllib.request.urlopen(
               requestBearerToken,
               context = ssl._create_unverified_context()
            )

            if responseBearerToken.getcode() == 200:
                bearerToken = json.loads(responseBearerToken.read())
                return bearerToken["token"]

    except Exception as err:
        raise Exception("An error occurred at receiving Bearer token") \
            from err

def getToken():
    """ Delivers the bearer token at the handler context parameter """

    userName = input("User name [holadmin@vcf.holo.lab]: ").strip() \
        or "holadmin@vcf.holo.lab"
    userPassword = getpass.getpass(prompt = "Password [VMware123!]: ") \
        or "VMware123!"

    return getBearerToken(url, userName, userPassword)

def main():
    """ Main function """

    global url
    url = input("URL [https://rainpole.auto.vcf.sddc.lab]: ").strip() \
        or "https://rainpole.auto.vcf.sddc.lab"

    context = {
        "executionId": "a92e5e2b-7e8e-4c83-ad16-34f4c4f68528",
        "returnType": "Properties",
        "vcoUrl": url + "/vco",
        "getToken": getToken
    }

    inputs = {
    }

    outputs = handler(context, inputs)

    print(outputs["status"])
    print(outputs["error"])
    print(outputs["result"])

# Main
if __name__ == "__main__" :
    main()


PowerShell

<#
 # Aria Automation handler emulation for PowerShell.
 #>

# Begin ----------------------------------------------------------------

function Handler($context, $inputs) {

  $inputsString = $inputs | ConvertTo-Json -Compress
  Write-Host "Inputs were $($inputsString)"



  $output = @{
    status = "done"
    result = "Result"
  }
  return $output

}

# End ------------------------------------------------------------------

$context = @{
  executionId = "975d8462-ecc1-4d5e-aa1f-b8a7ca5ef214"
  returnType = "Properties"
  vcoUrl = "http://localhost:8280/vco"
}

$inputs = @{
  name = "Stefan Schnell"
  city = "Oberirsen"
}

$outputs = Handler -context $context -inputs $inputs

# Output is from type System.Collections.Hashtable
# Write-Host $outputs
Write-Host $outputs.status
Write-Host $outputs.result

# [Void][Console]::WriteLine("Press any key to continue...")
# [Void][Console]::ReadKey("NoEcho,IncludeKeyDown")

Conclusion

The routines presented here can especially support us when testing code that is integrated into VCF Automation via import as zip type. That can simplify development.