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

  1. Fixed the code to work for me – I couldn’t get it working initially under vra 8.4
  2. Added support for CredSSP
  3. 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[0])[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)

The Setup

Action Constants

I create 4 action constants to hold sensitive information that I did not want exposed in the code. Example values can be found below

NameValue
domain_usernameadministrator
domain_passwordT0ps3cr3t!
dns_serverdc1.automationpro.lan
domain_nameautomationpro.lan

Action Setup

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]

 

Event Subscriptions

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!

Photo by Jan Kopřiva from Pexels

paul_davey

CIO at Sonar, Automation Practice Lead at Xtravirt and guitarist in The Waders. Loves IT, automation, programming, music