VCF Automation Blog

from Stefan Schnell


This Python source code shows how to call any VCF Automation action from Python runtime environment. This approach is of interest, because it allows us to ensure the seamless use of existing developments of the other execution environments, like JavaScript, PowerShell or Node.js.

Call Action from Python


The code contains a few functions. One is callAction, which bundles all necessary function calls. The sequence is then getActionId, executeAction and getActionLog. Each of them makes an API call to the orchestrator using the request function. The following sequence diagram shows this process.

sequence diagram of an action call from python

Now the source code, in which examples are inserted as comments in the handler function.

"""
 * @module de.stschnell
 *
 * @version 0.1.0
 *
 * @runtime python:3.10
 *
 * @memoryLimit 128000000
 *
 * @outputType Properties
"""


import json
import ssl
import time
import urllib.request


def request(url, bearerToken, method = "GET", body = {}):
    """ Executes a REST request

    @param {string} url - URL to execute the REST request
    @param {string} bearerToken
    @param {string} method - Method of REST request, e.g. GET, POST, etc.
    @param {dictionary} body - Body of REST request
    @returns {dictionary}
    """

    returnValue = {}

    try:

        request = urllib.request.Request(
            url = url,
            method = method,
            data = bytes(json.dumps(body).encode("utf-8"))
        )
        request.add_header(
            "Authorization", "Bearer " + bearerToken
        )
        request.add_header(
            "Content-Type", "application/json"
        )

        response = urllib.request.urlopen(
            request,
            context = ssl._create_unverified_context()
        )
        if response.getcode() == 200:
            returnValue = json.loads(response.read())

    except Exception as err:
        raise Exception(f"An error occurred at request - {err}") \
          from err

    return returnValue


def getActionId(vcoUrl, bearerToken, actionModule, actionName):
    """ Gets the ID of an action.

    @param {string} vcoUrl - URL of Aria orchestrator
    @param {string} bearerToken
    @param {string} actionModule - Module of the action
    @param {string} actionName - Name of the action
    @returns {string}
    """

    returnValue = ""

    try:

        actions = request(
            vcoUrl + "/api/actions",
            bearerToken
        )

        found = False
        for action in actions["link"]:
            for attribute in action["attributes"]:
                if attribute["name"] == "fqn" and \
                attribute["value"] == actionModule + "/" + actionName:
                    for attribute in action["attributes"]:
                        if attribute["name"] == "id":
                            returnValue = attribute["value"]
                            found = True
            if found:
                break

    except Exception as err:
        raise ValueError(f"An error occurred at get Action ID - {err}") \
            from err

    return returnValue


def executeAction(vcoUrl, bearerToken, actionId, parameters = {}):
    """ Executes an action.

    @param {string} vcoUrl - URL of Aria orchestrator
    @param {string} bearerToken
    @param {string} actionId - ID of the action
    @param {string} method - Method of REST request, e.g. GET, POST, etc.
    @param {dictionary} parameters - Parameters of the action
    @returns {dictionary}
    """

    returnValue = {}

    try:

        returnValue = request(
            vcoUrl + "/api/actions/" + actionId + "/executions",
            bearerToken,
            "POST",
            parameters
        )

    except Exception as err:
        raise ValueError(f"An error occurred at action executing - {err}") \
            from err

    return returnValue


def getActionLog(vcoUrl, bearerToken, executionId):
    """ Delivers the action log.

    @param {string} vcoUrl - URL of Aria orchestrator
    @param {string} bearerToken
    @param {string} executionId - ID of the execution, comes from executeAction
    @returns {dictionary}
    """
    returnValue = {}

    try:

        returnValue = request(
            vcoUrl + "/api/actions/" + executionId + \
            "/logs?maxResult=2147483647",
            bearerToken
        )

    except Exception as err:
        raise ValueError(f"An error occurred at get action log - {err}") \
            from err

    return returnValue


def callAction(vcoUrl, bearerToken, actionModule, actionName, parameters):
    """ Calls an action

    @param {string} vcoUrl - URL of Aria orchestrator
    @param {string} bearerToken
    @param {string} actionModule - Module of the action
    @param {string} actionName - Name of the action
    @param {dictionary} parameters - Parameters of the action
    @returns {dictionary}
    """

    returnValue = {}

    try:

        actionID = getActionId(
            vcoUrl,
            bearerToken,
            actionModule,
            actionName
        )

        _parameters = {
            "async-execution": False,
            "parameters": parameters
        }

        executionResult = executeAction(
            vcoUrl,
            bearerToken,
            actionID,
            _parameters
        )

        returnValue["executionResult"] = executionResult

        executionId = executionResult["execution-id"]

        time.sleep(2.5)

        actionLog = getActionLog(vcoUrl, bearerToken, executionId)

        returnValue["actionLog"] = actionLog

    except Exception as err:
        raise ValueError(f"An error occurred at call action - {err}") \
            from err

    return returnValue


def handler(context, inputs):
    """ Aria Automation standard handler, the main function.
    """

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

    output = {}

    try:

        # Begin of action call -----------------------------------------

        # The setting of the parameters is described in the
        # REST API Calling Conventions.

        # @example
        # actionName = "getDefaultCompanyName"
        # actionModule = "com.vmware.constants"
        # parameters = []

        # @example
        actionName = "getFileName"
        actionModule = "com.vmware.basic"
        parameters = [
            {
                "name": "fileName",
                "type": "Path",
                "value": {
                    "string": {
                        "value": "/stefan/test/bambi"
                    }
                }
            }
        ]

        output = callAction(
            vcoUrl, bearerToken, actionModule, actionName, parameters
        )

        # print(output["executionResult"]["value"]["string"]["value"])
        # delivers VMware Inc. with the first example and
        # bambi with the second example

        # End of action call -------------------------------------------

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

    except Exception as err:

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

    return outputs