In my lab, I leverage Aria Automation to deploy Linux, Windows, and nested ESXi VMs. This is my primary interface for requesting new systems and covers most of the common resources I need for testing. However, I sometimes deploy one off appliances and such, at a scale where automation hasn’t been built. These appliances typically require an IP Address and DNS record. I had previously created a Jenkins job that accepted parameters, making these easy enough to create, but the cleanup is where I would fall down. I also wasn’t a huge fan of switching between the Aria Automation & Jenkins consoles to submit these requests.
My ideal solution to both of these problems was an Aria Automation request form that would create a deployment tracking these one-off IP requests. To not re-invent the wheel, this Aria Automation request could simply call Jenkins. When testing is complete, I’d have a deployment remaining in Aria Automation to serve as a reminder to properly clean up IPAM and DNS. This article will cover the process of creating this action, resource, and template to front end the Jenkins request with Aria Automation.
Custom Action – Create
In Aria Automation Assembler > Extensibility > Actions, we can create a new action. I named mine IPAM Next Address Create
and selected only the project where my test deployments live.
For the action, I’m writing everything in PowerShell, since I already know that language and Aria Automation supports it. This code sample lacks robust error handling, and probably could be cleaned up a fair amount, but it got the job done for what I was hoping for. In a production environment, adding some logic after each step to ensure the task completed would be prudent. In the event that the IPAM service is down or Jenkins isn’t responding, we’d want the request to behave in a predictable way.
The create section has more code as it connects to phpIPAM to get the next address then requests a DNS record be created by Jenkins. I directly obtain the IP address, so that I have it to return as part of the deployment, so that the IP obtained is clearly visible in the deployment.
function handler($context, $inputs) {
$subnet = $inputs.subnet
$hostname = $inputs.name
write-host "We've received a $($inputs.'__metadata'.operation) request for subnet $subnet"
$ipamServer = 'ipam.apps.example.com'
$ipamUser = 'svc-vra'
$ipamPass = 'VMware1!'
$ipamBaseURL = 'https://'+$ipamServer+'/api/'+$ipamUser+'/'
# Login to the API with username/password provided. Create header to be used in next requests.
write-host "IPAM Login"
$ipamLogin = (Invoke-RestMethod -Uri "$($ipamBaseURL)user" -Method Post -SkipCertificateCheck -Headers @{'Authorization'='Basic '+[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($ipamUser+':'+$ipamPass))}).data.token
$nextHeader = @{'phpipam-token'=$ipamLogin}
# Get the subnet ID of the specified CIDR
write-host "IPAM Get Subnet ID"
$subnetID = (Invoke-RestMethod -URI "$($ipamBaseURL)subnets/cidr/$subnet" -SkipCertificateCheck -Headers $nextHeader).data.id
# Make a reservation and provide name/description
write-host "IPAM Reserve Next"
$postBody = @{hostname="$($hostname).lab.enterpriseadmins.org"; description='Requested via Automation Extensibility'}
$myIPrequest = (Invoke-RestMethod -URI "$($ipamBaseURL)addresses/first_free/$subnetID" -SkipCertificateCheck -Method Post -Headers $nextHeader -Body $postBody).data
# Send a DNS Request to Jenkins
write-host "Jenkins DNS Request"
$dnsBody = @{reqtype='add'; reqhostname=$hostname; reqipaddress = $myIPrequest; reqzonename='lab.enterpriseadmins.org'} | ConvertTo-Json
Invoke-RestMethod -URI 'http://jenkins.example.com:8080/generic-webhook-trigger/invoke?token=VRA-dnsRecord' -Method Post -Body $dnsBody -ContentType 'application/json'
# Return detail to vRA
$outputs = @{
address = $myIPrequest
resourceName = $hostname
}
return $outputs
}
The IP address obtained from IPAM as well as the hostname are returned when this task completes.
Custom Action – Read
For our custom resource, we will also need to specify an action to read / check status of our resource. For my purposes, I really don’t need anything specific to be checked, so I simply return all the input parameters. This is the default function / template loaded when creating the action.
function handler($context, $inputs) {
return $inputs
}
Custom Action – Delete
When we are finished with our deployment and ready to delete, the custom resource needs a ‘delete’ action to call. Again this is written in PowerShell and calls Jenkins to request the actual delete. Jenkins will then connect to DNS and IPAM to process the cleanup.
function handler($context, $inputs) {
$ipAddress = $inputs.address
$hostname = $inputs.name
write-host "We've received a $($inputs.'__metadata'.operation) request for IP address $ipAddress and hostname $hostname"
$removeBody = @{reqzonename='lab.enterpriseadmins.org'; operationType='remove'; reqhostname=$hostname; subnetOrIp = $ipAddress} | ConvertTo-Json
Invoke-RestMethod -URI 'http://jenkins.example.com:8080/generic-webhook-trigger/invoke?token=RequestIpAndDnsRecord' -Method Post -Body $removeBody -ContentType 'application/json'
}
This code could easily have contacted IPAM and DNS as separate requests, but since the Jenkins job already existed with webhook support, I choose to follow that path for simplicity.
Create Custom Resource
In Aria Automation Assembler > Design > Custom Resources we can create a new resource which will run our above actions. I named my resource IPAM Next Address
, set the resource type to Custom.IPAM.Request
, and based the resource on an ABX user-defined schema. For lifecycle actions, I selected the above IPAM Next Address action for all three required types: create, read, and destroy. For starters I set the scope to only be available for my test project, and finally togged the ‘activate’ switch to make the resource available in blueprints.


Create Template
In Aria Automation Assembler > Design > Custom Template, the design for this request is super simple. There are three inputs: issueNumber
, Name
, and Subnet
. The issue number is used for tracking and becomes part of the host name. The name is the unique part of the hostname, and the subnet is which network to use when finding the next address. My hostname ends up being h<issue-number-padded-3-digits>-<name-entered>
(h is a prefix I use for test systems in my homelab). The subnet is a drop-down list with the networks I typically use for testing, defaulting to the selection I use most often.
formatVersion: 1
inputs:
issueNumber:
type: integer
title: Issue Number
Name:
type: string
minLength: 1
maxLength: 25
default: ip-01
Subnet:
type: string
title: Subnet
default: 192.168.10.0/24
enum:
- 192.168.10.0/24
- 192.168.40.0/24
resources:
IPAddress:
type: Custom.IPAM.Request
properties:
name: h${format("%03d",input.issueNumber)}-${input.Name}
subnet: ${input.Subnet}
address: ''
git-issue-number: ${input.issueNumber}
Deploy
Once I published a version of this design, I can now make a request from the service broker catalog. My request form only has a few required fields:

I added some functionality into the ‘create’ action to post a comment to my issue tracker letting me know that a new resource has been created. It is created with a task list check box, so that I can see there is an open item to review with this issue, as well as a link to the deployment.

When I look at the deployment, I can see when it was created, if it expires, and can use the actions drop down to delete the deployment. This delete action calls the Jenkins job mentioned above to remove the DNS record and release the IP address from IPAM.
Conclusion
Aria Automation can provide an interface to leverage existing workflows. This example shows how to create a deployment to track the lifecycle of a created resource, while leveraging an existing system to handle the actual task. This solves my cleanup / tracking issue for one off IP requests as well as getting all the requests submitted from a single console. Hopefully you can use pieces of this workflow in your own environment.