As you’ve seen from my recent blog posts, I’ve been doing a lot of NSX work recently. One of my customers has been working on a distributed firewall redesign and, as part of this effort, we determined that we needed to change the “AppliedTo” field for all of their existing firewall rules. Because they have hundreds of rules, we knew that we’d need some sort of automated solution, lest we introduce unknown errors through our attempts at making these changes by hand. Given my past experiences with PowerNSX (and the fact that it’s my primary NSX management interface), I figured that this would be super easy, barely an inconvenience. Whoops!
PowerNSX is great, but it’s a community tool at its core. This means that the feature set that it has is limited to the intersection of features that the community has needed and those that the community has spent the time developing. So, 99.999% of what I need is already there and I usually don’t even need to think about it… but it turns out that this was one of those 0.001% issues. PowerNSX already had the ability to create NSX Firewall rules with an AppliedTo value, but it didn’t have the ability to change the AppliedTo field for existing rules.
Since that functionality was there for New-NSXFirewallRule, I figured that I could try my hand at implementing it in Set-NSXFirewallRule. In the end, it didn’t require much (really, just 3 lines of code), but it took me quite a while to get there! My biggest challenge was that I had to work with PowerShell XML objects (since they were getting passed to the NSX API to make the actual changes), and XML objects don’t always behave the way normal objects do!
XML objects come in 2 flavors: Documents and Extensions. I’m not super clear on the distinctions between the two, but a summary seems to be that Extensions get nested into Documents. The nesting structure for an Extension is super important and ultimately goes back to the Document object, so that Document object is super important.
So, what happens when you use the Set-NSXFirewallRule cmdlet? Well, in short, it gets the specified Firewall Rule ID from NSX as an XML Extension, then changes whatever needs to be changed in that XML, then pushes it back into NSX. If you’re changing things like the rule Name or Action, that’s super easy, because those are literally just strings that get updated; they don’t modify the XML structure at all.
AppliedTo, on the other hand, has the potential to modify the XML file a little bit. What happens if the rule was originally AppliedTo a single object, but now it needs to be AppliedTo several? You’re going to need new nodes in the XML to support that. Fortunately, there’s a private function in PowerNSX (meaning that you can’t just execute it like you would a cmdlet) called New-NsxAppliedToListNode. That’s the function that the New-NSXFirewallRule cmdlet uses when it wants to build out the AppliedTo list for a new firewall rule. That function will return a chunk of XML that’s formatted with everything that AppliedTo needs in order to be built out correctly, but there was a catch.
The function needs an XML Document for the Firewall Rule so that it’ll build the AppliedTo list with the correct context. When building a new firewall rule, the cmdlet builds a new XML Document as part of that process, so it just uses that document and everything’s good. Set-NSXFirewallRule gets the rule back as an XML Extension though, so the New-NsxAppliedToListNode couldn’t just take it and use it for the context.
Fortunately, a bit of poking around revealed an easy solution (after a whole lot of other, fruitless poking around)! The firewall rule XML Extension has a property: .SchemaInfo.OwnerDocument which is the actual XML Document! So, I passed that to the New-NsxAppliedToListNode function and got back a perfectly usable AppliedTo list! So, I just delete the existing AppliedToList node and replace it with the new one (using Powershell’s magic XML functions instead of normal PowerShell object assignments, because XML), and everything looks great!
I don’t really understand Git or, for that matter, GitHub. I’ve tried, and I think that I understand the basics, but I’m not 100% clear on the whole pull request process. I think that I’ve got everything in place so that my change can get folded back into PowerNSX proper, but you can find my fork on GitHub if you need access to this feature while I work through any issues with the pull request.