NSX LoadBalancer – character “/” is not permitted in server name

lberr

This was an odd error that a colleague brought to me while testing automation around the configuration of an NSX Edge.

He had created the Edge successfully, and configured the Load Balancer, but on trying to enable it, it was erroring. When he tried enabling it through the Web Client, the above error was displayed, and the change was automatically reverted.

After a lot of digging, I discovered that the configuration for the Load Balancer had a Pool where the “IP Address / VC Container” object was a Service Group, and one of the members of that Service Group was an IPSet for the CIDR block that NSX was trying to include in the server name.

I’m not sure whether that is even a supported configuration, but I changed it to point to a Service Group that included the members of the target web farm, and the Load Balancer could then be configured successfully.

NSX Ninjas course, week 1

After just over a year of trying, I finally managed to get on the VMware NSX Ninjas course. I was first offered it last April (2015) in Palo Alto, but with a small baby at home, and the fact that it was straight after our company conference in Orlando, I had to decline.
I then missed out on it a number of times, due to only finding out about sessions while they were happening.

Anyway, our UK TAM, Liam Farrell, managed to get places for 3 of us (me, @MrCNeale and @BlobbieH) on a course running from VMware’s UK HQ in Staines, which is slightly more travel friendly than Palo Alto. Our instructor for the week was Red1 Bali (@tredwitter), who is actually a freelance consultant, rather than a VMware employee.

For those who haven’t come across the NSX Ninjas course before, my understanding is, that it is provided to VMware Partners (at zero cost other than their own travel and accommodation), and the aim of it is to get people who’ve done the NSX ICM course up through VCIX-NV (week 1) and prepare them for VCDX-NV (week 2).

The course ran from Monday lunchtime, to Friday lunchtime, with days 1-3 billed as NSX 401 Troubleshooting, day 4 NSX Operations, and day 5 NSX Automation.

Maybe because we’d been trying to get on this course for so long, I suspect we had insanely high expectations, and the first day or so felt a little disappointing – a little slow going and not very “deep”. Possibly this was because some people on the course had failed to do the *mandatory* prerequisites of taking the NSX ICM course and passing the VCP-NV, so Red1 was having to take things a little slower. I know people have busy working lives, but attending a deeply technical course without having completed the prereqs just isn’t on in my opinion.

Anyway, the pace soon ramped up, and we were working through the labs, including fixing all the problems caused by them starting with expired licenses. As we progressed through the course presentations, Red1 started introducing faults into our lab environments for us to fix. Some of these were straightforward to find, but some were definitely not so easy, and were an excellent way of getting you into the command lines, debug tools, and logs, to find what had gone wrong.

The course ended with content on Operationalizing NSX, based on the use of LogInsight and vROPS, the latter being of less interest to us at the moment, as it’s not part of the product suite that we use. However, the breaking of the lab environments and subsequent troubleshooting, continued, with Red1 delivering a seemingly inexhaustible supply of failure scenarios. These were what I enjoyed most about the week, as digging into a gnarly technical fault is something I relish (maybe less so if there’s a production outage on the back of it though!).

All in all, I definitely recommend the course if you can get on it, and a big thanks to VMware for providing it, our UK TAM Liam Farrell for getting us the places, and Red1 for being an excellent instructor.

Stay tuned for week 2, scheduled for the middle of June.

 

Automating NSX from PowerCLI

I’ve been working on an NSX-based project recently, and given the task of automating the addition of new DLR Logical Switches and Edge devices.

After a discussion around the alternatives with colleagues, we decided the best way forward (for now) was to do it in PowerShell/PowerCLI, and a quick google found Chris Wahl’s post here

This was a great basis to work from (Thanks Chris!), but lacked a number of things I needed: Creating DHCP Pools, attaching a Logical Switch to an existing Edge device, and some relatively minor amendments to DLR/Edge configurations.

Of these the attachment of a new LS to an existing Edge proved the most intellectually taxing, as Chris’ scripts work with building new raw XML to PUT/POST with the REST API, and I soon discovered that the only way to amend an Edge configuration through the REST API is to pull the existing config as an XML, amend it, and PUT it back.

On top of this, the XML retrieved through the “Invoke-WebRequest” PowerShell cmdlet is of type “System.Xml.XmlElement” whereas to do things like “CreateElement” – which we need to do to add new entries into the configuration –  it needs to be of type “System.Xml.XmlDocument”.

After a number of failed workarounds, I found that dumping the XML to a file, and reimporting, gave me the XML in the correct object type – this is a little ugly though, and while the automation is for something that would only be used occasionally, I don’t like ugly hacks in my code!

A little more effort, and I had a suitable alternative – casting the XML to a string object and back to an XML object yielded the result I was looking for.

$edge = Invoke-WebRequest -Uri “$uri/api/4.0/edges/$routerid” -Headers $head -ContentType “application/xml” -ErrorAction:Stop
 [xml]$edgexml = $edge.Content
 $textxml = $edgexml.innerxml
 [xml]$body = $textxml

I could then work with $body as a normal XmlDocument object in PowerShell.

The next issue I had was making the amendments to the XML.

First – make sure the new Logical Switch is not already attached, and then find the first unused interface:

foreach ($vnic in $body.edge.vnics.vnic) {
     if ($vnic.name -match $config.newLS.name) {
          $attached = "true"
          Write-Host -BackgroundColor:Black -ForegroundColor:Red "Warning: $($config.newLS.name) already attached. Skipping."
          break
     if ($vnic.isConnected -match "false") {

Second – setting values for XML entities that were already in the XML. Easy:

$vnic.name = $config.newLS.name
$vnic.isConnected = "true"

Third – adding a new XML entity that wasn’t already there:

$elem = $body.CreateElement("portgroupId")
$vnic.AppendChild($elem)
$vnic.portgroupId = $switchvwire.get_Item($config.newLS.name)

Finally – adding entities to an empty node “<addressGroups />”. Not so easy! This took some considerable time, including many false starts! In the end I discovered that to “find” the empty node using SelectSingleNode I had to set up a namespace. Then I could find it and remove it (this seemed easier than trying to attach entries to the empty node). Then I could create some raw XML and attach it into the Edge configuration XML using ImportNode and AppendChild.

$ns = New-Object -TypeName System.Xml.XmlNamespaceManager -ArgumentList $body.NameTable
$ns.AddNamespace("ns",$body.DocumentElement.NamespaceURI)
$oldAddressGroups = $vnic.SelectSingleNode("//vnic[index=$inf]/addressGroups")
$vnic.RemoveChild($oldAddressGroups)
[xml] $addr = "<addressGroups>
  <addressGroup>
    <primaryAddress>$($config.newLS.edgeip)</primaryAddress>
    <subnetMask>$($config.newLS.mask)</subnetMask>
  </addressGroup>
</addressGroups>"
$vnic.AppendChild($body.ImportNode($addr.addressGroups, $true))

Once that was done all I had to do was send the XML back using Invoke-WebRequest

# Attach new logical switch to existing Edge
try {$r = Invoke-WebRequest -Uri "$uri/api/4.0/edges/$routerid" -Body $body -Method:Put -Headers $head -ContentType "application/xml" -ErrorAction:Stop -TimeoutSec 30} catch {Failure}
if ($r.StatusCode -match "204") {Write-Host -BackgroundColor:Black -ForegroundColor:Green "Status: Successfully attached new Logical Switch to $($config.edge.name)."}
else {
$body
throw "Was not able to add new Logical Switch to existing Edge. API status code was not 204."
}
break}

I’ve no doubt that there are probably some better ways of achieving some of what I’ve done here, but I thought I would post it up in case anyone is looking to do something similar.