jbowdre / site-comments

0 stars 0 forks source link

vRA8 Custom Provisioning: Part Four - Virtually Potato #9

Closed utterances-bot closed 11 months ago

utterances-bot commented 3 years ago

vRA8 Custom Provisioning: Part Four - Virtually Potato

My last post in this series marked the completion of the vRealize Orchestrator workflow that I use for pre-provisioning tasks, namely generating a unique sequential hostname which complies with a defined naming standard and doesn’t conflict with any existing records in vSphere, Active Directory, or DNS. That takes care of many of the “back-end” tasks for a simple deployment.

https://virtuallypotato.com/vra8-custom-provisioning-part-four

jessiewestlake commented 3 years ago

Hey, John! Thanks for putting together so many notes on your journey with vRA 8.

At the beginning of your blog posts for the requirements you had for vRA 8 deployments, you listed:

Were you ever able to figure this out? I have tried many "script" execution tasks, like running a vRO action to copy a script file, and execute it, and to "execute a program on guest" and have it run PowerShell with a command, and trying to use ABX actions to try and do PSRemoting to run a command on the guest to add the user. But the only ones that work, are EXTREMELY complex. Have you found a simple way to do this?

jbowdre commented 3 years ago

Hi Jessie!

I'm glad you've found my notes to be helpful!

Yes, I did figure out how to add users to a guest's Administrators group post-deployment... I just haven't finished writing a post about it. It's coming soon though, I promise!

The short version is that I'm using a PowerShell ABX Action to do the things. It's able to leverage PowerCLI stuff so I use Connect-ViServer to connect to the appropriate vCenter, find the VM with the right name, and use Invoke-VmScript to run whatever commands I want inside the guest OS using the VM Tools interface (avoiding all the messy PSRemoting stuff).

You can check out the script I'm using here if you want to see the details before I get the ABX article posted; I'm sincerely hoping to get that posted either later today or early next week.

Thanks for keeping me honest! 😁

jbowdre commented 3 years ago

Hi Jessie,

I finally got that post up: https://virtuallypotato.com/run-scripts-in-guest-os-with-vra-abx-actions

Hope it helps!

jessiewestlake commented 3 years ago

Awesome! Can't wait to check it out. I never thought about connecting through vCenter using PowerCLI, even though I have used it before from my desktop. I had figured there would be a native, built-in method for executing commands on guests using vRA, but it would likely have to use vCenter anyway. So PowerCLI makes perfect sense.

Connecting to the VMs using PSRemoting (WSMAN/WinRM, CIM, etc.) was giving me massive headaches because of credentialing and authentication issues, but using PowerCLI avoids that altogether.

Thanks for the solution and I'll read the full post as soon as I can.

huynhr6510 commented 2 years ago

Hi John, I am running into a couple of issues when trying to do the Per-Site Network Selection. Issue jbowdre/site-comments#2:
Getting the error "Cannot read property "value" from undefined " when tried to debug the Action "getNetworksForSite".
I tried to use the Site name (i.e HQ), tags as the siteCode, all getting the same error.

Issue jbowdre/site-comments#3 In the Customize Request Form, I am not able to select the Action “getNetworksForSite” from the Values tab of the Network field. I believe it was looking for string rather than array.

After I changed the input type from string to array for the network in the Cloud Template, I was able add the action to the Request Form. Inputs: […] network: type: array title: Network

However, I am still getting the error that complains about the undefined field. {"message":"920002: Invoked action completed with error. Error : Action 'getNetworksForSite' in module 'com.xxxx' failed : TypeError: Cannot read property \"value\" from undefined (com.xxxx/getNetworksForSite#20).","messageId":0,"stackTrace":null,"statusCode":400,"errorCode":920002};

Any help would be greatly appreciate.

Raymond

jbowdre commented 2 years ago

Hi Raymond,

Issue 1

The bit about Cannot read property "value" from undefined makes me think that the action isn't able to find the networksPerSite configuration element. Can you double-check that the script correctly reflects the configuration?

This tells vRO to look for the configuration named networksPerSite inside the CustomProvisioning folder:

var category = Server.getConfigurationElementCategoryWithPath("CustomProvisioning")
var elements = category.configurationElements
for (var i in elements) {
    if (elements[i].name == "networksPerSite") {
        var networksPerSite = elements[i]
    }
}
...

image

Issue 2

The vRO getNetworksForSite action returns an array of strings because it populates the dropdown with the network options available for a selected site. Site 1 might have networks A, B, and C; each network is represented by a string ('A') but vRO needs to return ['A', 'B', 'C'] as an array so that all the options can be displayed. Once the user selects which network to use that choice gets stored and processed as a string ('A').

Cloud Assembly lets us explicitly specify the variable type in the template, and input.network must be a string since we want to connect the VM's NIC to a single network. That's the data that vRA will eventually use on the back end for doing the provisioning.

When modifying the Custom Form in Service Broker, though, things get a bit fuzzier. We'll want the Network field to be displayed as an array so that the user can pick from that dropdown, but Service Broker doesn't let use say that explicitly. So instead you'll need to select the Network field and set the Display Type option on the Appearance tab to DropDown. image

That should tell SB to treat the field as an array, and then let you select the getNetworksForSite action (which returns an array of strings) as the External Source on the Values tab. image

Hopefully that will resolve the issues you're experiencing but please let me know if it still doesn't work and I can dig deeper!

Cheers, John

huynhr6510 commented 2 years ago

Hi John,

Thanks for your explanation. Found the issue was due to the typo of the Configuration element name. All is good.

Enjoy your article very much! and thanks again for your assistance.

jbowdre commented 2 years ago

Awesome, I'm glad I could help!

ferdinandosimonetti commented 2 years ago

Hello, first of all thank you a lot for this (and other) articles. I'm using vRA8.8 (and its Embedded vRO), wrote a couple of vRO Actions, packaged them... but when I try to use them from within a Service Broker's custom form, I can't find them when searching via External source, I've already tried your suggestion about starting vRO data collection (from within Cloud Assembly / Infrastructure / Integrations / Embedded-vRO, as well as from within Service Broker / Infrastructure / Integrations / Embedded-vRO) to no avail. These actions are part of a "custom module" com.mycustomer.customactions, I've already tried to package them, export the package, delete it from within vRO, reimport, relaunch data collection... but nothing seems helping. I've already added in the past a custom package to vRO (built by another person)... and this one has been found from the start, when trying to use it from within a custom form. Help... :-( Thanks in advance!

jessiewestlake commented 2 years ago

@ferdinandosimonetti, one thing you will want to check is that the output type of the vRO action is of the same type as the field in your custom form. Further, there might be a restriction to only strings or arrays of strings, but I cannot remember for sure off hand.

jbowdre commented 2 years ago

Yeah @ferdinandosimonetti, @jessiewestlake's suggestion to make sure the output type matches the input type is exactly what I was going to recommend.

ferdinandosimonetti commented 2 years ago

Thanks for your suggestions! I'm trying to populate a Dropdown of Strings (on vRA side), and I'm taking a two-script approach here (because, alas, my JS skills are negligible):

A "wrapper" Javascript action to:

The "real" Python action (I know, it's crude too, forgive me) that returns the names of all defined Cloud Accounts: actually it returns a single string with a concatenation of CloudAccount's names (extracted from a list), separated by commas


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

def vraLogin(vraHost,vraUser,vraPassword):
    refreshtokenurl = f"https://{vraHost}/csp/gateway/am/api/login?access_token"
    iaasUrl = f"https://{vraHost}/iaas/api/login"
    headers = {
        'accept': "application/json",
        'content-type': "application/json"
    }
    payload = f'{{"username":"{vraUser}","password":"{vraPassword}"}}'
    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']
    vraToken = "Bearer " + iaasApiOutput
    return vraToken

def getCloudAccounts(vraHost,vraToken):
    calledUrl = f"https://{vraHost}/iaas/api/cloud-accounts"
    headers = {
        'accept': "application/json",
        'content-type': "application/json",
        'authorization': vraToken
    }
    ca = requests.get(calledUrl, headers=headers, verify=False)
    caJson = ca.json()
    caContent = caJson['content']
    return ca.status_code,caContent

def handler(context,inputs):
    #jsonOut=json.dumps(inputs, separators=(',', ':'))
    ## Print out the whole inputs map
    #print("Inputs were {0}".format(jsonOut))

    vraHost =     inputs['vraHost']
    vraUser =     inputs['vraUser']
    vraPassword = inputs['vraPassword']

    vraToken = vraLogin(vraHost,vraUser,vraPassword)

    scode,cloudaccounts = getCloudAccounts(vraHost,vraToken)
    if scode == 200:
        cal = [x['name'] for x in cloudaccounts]
        can = ",".join(cal)
        return can
    else:
        return ''```
ferdinandosimonetti commented 2 years ago

Yay, your suggestions definitely worked, thanks @jessiewestlake @jbowdre !!! Basically, hoping to help someone else having this kind of problem:

    scode,cloudaccounts = getCloudAccounts(vraHost,vraToken)
    if scode == 200:
        cal = [x['name'] for x in cloudaccounts]
        return cal
    else:
        cal = []
        return cal