I have been playing around with vra8 actions for a while now and whilst it is a handy function, I have found some issues with the PowerShell implementation. However, Python based actions seem to execute just fine. Whilst playing around I came across what looked like a really useful action by @rhjensen. The action creates an A record in a specified DNS zone on a Microsoft based DNS server, using the name and IP address assigned at deployment. I pulled down the code and started to make it work for me, changing a few bits around. Kudos to Robert as he paved the way for me to adapt from his code.
What I have done
- Fixed the code to work for me – I couldn’t get it working initially under vra 8.4
- Added support for CredSSP
- Updated the action code so that credentials and DNS server information is pulled from Action Constants, to keep the ‘data’ private and abstracted from the code
My code can be seen below. Obviously to be used, you can create your own action and copy and paste the raw code below into your action.
""" The purpose of this script, is to take VM input, and using WinRM connect to a Windows DNS server, and update/remove the DNS record, using the dnscmd.exe command. Original author of this script is Robert -- @rhjensen and can be downloaded from https://code.vmware.com/samples/7271/DNS-Update- PD: updated to use credssp; you must set a dependency to pywinrm[credssp] on your windows dns server/dc you must enable winRM and enable CREDSSP support PD: updated to pull data from Action Constants to avoid having sensitive data visible in the action code """ import winrm #Global Variables event = "" # Provision or remove. ipadress = "" # Cleaned up IP hostname = "" # Cleaned up Hostname DNS_Server = "" DNS_Domain = "" Username = "" Password = "" #Get inputs from deployment def get_vm_input(context, inputs): global event global ipaddress global hostname # context.getSecret() event = str(inputs["__metadata"]["eventTopicId"]) # Provision or remove. ip_raw = inputs["addresses"] # Raw IP input ipaddress = str(ip_raw)[2:-2] # Cleaned up IP hostname_raw = inputs["resourceNames"] # Raw Hostname hostname = str(hostname_raw)[2:-2] # Cleaned up Hostname def handler(context, inputs): get_vm_input(context, inputs) DNS_Server = context.getSecret(inputs["dns_server"]) # DNS server where the command will be executed DNS_Domain = context.getSecret(inputs["domain_name"]) # DNS Domain to be updated Username = context.getSecret(inputs["domain_username"]) # Username with right to do the operation Password = context.getSecret(inputs["domain_password"]) # Password for the account" #Open session session = winrm.Session(DNS_Server, auth=(Username,Password), transport='credssp') #Check for provision result = event.startswith('compute.provision') if result == True : dns_command = "dnscmd.exe "+DNS_Server+" /RecordAdd "+DNS_Domain+" "+hostname+" 10 A "+ipaddress+"" result = session.run_ps(dns_command) print(result.std_out) #Check for removal result = event.startswith('compute.removal') if result == True : dns_command = "dnscmd.exe /RecordDelete "+DNS_Domain+" "+hostname+" a /f" result = session.run_ps(dns_command) print(result.std_out)
I create 4 action constants to hold sensitive information that I did not want exposed in the code. Example values can be found below
The action requires the Action Constants to be added as inputs. Add a new input and select the ‘Secret’ checkbox. This will enable you to select the Action Constraints you created in the previous step. There is also a dependency on the pywinrm library. Because we want to use credssp, add a dependency as shown, for pywinrm[credssp]
I set up the action to be triggered on two different event subscriptions, Compute post provision and Compute post removal.
Note: I found that any earlier in the provision side wouldn’t work as an IP address was not yet allocated (I am using vRA IP management in this environment).
Once again, thanks to Robert for getting me started with this!