Czernobog
Expert
Expert

vRO 8.8 / vRA 8.8 - Python action - referencing other vRO actions?

Jump to solution

I have a bundle of Python actions in vRO and would like for a few of them to reference other (mostly also Python) vRO actions from different vRO modules.

What would be the best way to do this? At the moment the only way I can think of to accomplish this task, is to execute a REST query to launch the action, there does not seem a more "native" way to do it, like with System.getModule....

1 Solution

Accepted Solutions
bsaxe
VMware Employee
VMware Employee

I'm downloading Python code into the container from other action scripts using the API and then adding them to the Python path so I can import them on the fly. Here's the bootstrap code.

onboardingUtils is just a plain Python module, i.e. no module.handler and not even called directly in vRO. vacfg_constants is a set of constants in another Python module that is imported by onboardingUtils. I.e. onboardingUtils depends on vacfg_constants. As long as you have the other Python action bits inside the container, you should be able to load them into your main action.

onboardingUtils = None

_vcoUrl_ = None
_vcoToken_ = None
_headers_ = None

def handler(context, inputs):
    global onboardingUtils
    global _vcoUrl_
    global _vcoToken_
    global _headers_

    _vcoUrl_ = context['vcoUrl']
    _vcoToken_ = context['getToken']()

    _headers_ = {
        'accept': 'application/json',
        'authorization': "Bearer " + _vcoToken_
    }

    os.chdir(inputs['workdir'])
    sys.path.append(inputs['workdir'])

    downloadAction('com.client.vmware.vra.onboarding','onboardingUtils', 'onboardingUtils.py')
    downloadAction('com.client.vmware.vra.onboarding', 'vacfg_constants', 'vacfg_constants.py')

    import onboardingUtils
    onboardingUtils = sys.modules['onboardingUtils']

def downloadAction(module, action, file_path):

    url = f'{_vcoUrl_}/api/actions/{module}/{action}'
    response = requests.get(url, headers=_headers_)
    print(response.status_code)
    response.raise_for_status()

    r = json.loads(response.text)
    open(file_path, 'w').write(r['script'])

 

View solution in original post

6 Replies
xian_
Expert
Expert

If it is a workflow, I'd simply add actions as steps to it.

In an action, you can create python modules within the zip bundle, and import them in your script.

0 Kudos
Czernobog
Expert
Expert

But this would not work for a custom python environment. If I have to use some popular modules like requests, I would have to bundle my own modules and those I would normally add as a dependency in a custom env, which mean I'd have to update them all manually somewhere in the future.

This is an approach I was looking for though - create you own modules from python functions, and upload them into the custom environment, so every action that runs in that env can use it. 

I think I will settle for a "wrapper" function written in js for now, that would load all configuration elements and resource elements in the first step, and pass the values on to python actions, which would be referenced by the traditional System.getModule("my.py.actions") method.

0 Kudos
bsaxe
VMware Employee
VMware Employee

I'm downloading Python code into the container from other action scripts using the API and then adding them to the Python path so I can import them on the fly. Here's the bootstrap code.

onboardingUtils is just a plain Python module, i.e. no module.handler and not even called directly in vRO. vacfg_constants is a set of constants in another Python module that is imported by onboardingUtils. I.e. onboardingUtils depends on vacfg_constants. As long as you have the other Python action bits inside the container, you should be able to load them into your main action.

onboardingUtils = None

_vcoUrl_ = None
_vcoToken_ = None
_headers_ = None

def handler(context, inputs):
    global onboardingUtils
    global _vcoUrl_
    global _vcoToken_
    global _headers_

    _vcoUrl_ = context['vcoUrl']
    _vcoToken_ = context['getToken']()

    _headers_ = {
        'accept': 'application/json',
        'authorization': "Bearer " + _vcoToken_
    }

    os.chdir(inputs['workdir'])
    sys.path.append(inputs['workdir'])

    downloadAction('com.client.vmware.vra.onboarding','onboardingUtils', 'onboardingUtils.py')
    downloadAction('com.client.vmware.vra.onboarding', 'vacfg_constants', 'vacfg_constants.py')

    import onboardingUtils
    onboardingUtils = sys.modules['onboardingUtils']

def downloadAction(module, action, file_path):

    url = f'{_vcoUrl_}/api/actions/{module}/{action}'
    response = requests.get(url, headers=_headers_)
    print(response.status_code)
    response.raise_for_status()

    r = json.loads(response.text)
    open(file_path, 'w').write(r['script'])

 

Czernobog
Expert
Expert

Thank you for answering! This is a really interesting solution, I will definitely try this out soon.

What are the 'workdir' inputs used for? Are those paths to python within the container? 

0 Kudos
bsaxe
VMware Employee
VMware Employee

The input workdir is the directory inside the container where the action is doing all of its work that needs file system write access. I think by default, the container logs into the /root or / (forget) directory, which is read-only. I think my input is just /tmp directory. I didn't feel like using absolute paths in all my functions, so I do all the work in /tmp.

0 Kudos
Czernobog
Expert
Expert

Thanks!

I hope a similar solution will be developed for configuring a python environment in vRO, so you'll be able to load custom modules from a folder or maybe gitlab directly into the environment, so that a workaround with the additional actions and functions is not needed.

0 Kudos