In my case I needed to be able to change Memory Reservation settings. The thing is that all NSX appliances are deployed with 100% of memory reservation. My home lab grew up to almost 200Gb of RAM, but I still struggle with lack of memory especially when I run few nested deployments, each with its own NSX.
I am a big fan on PowerCLI so I tried to use Set-VMResourceConfiguration command let, but that attempt wasn't successful.
as you can see in the screenshot this method is disabled.
You can check all the methods disabled for VMs using this command
(get-vm VMname).ExtensionData.disabledmethod

As you can see the ReconfigVM_Task is in the list of disabled methods, which prevents any changes to the VM config.
There is a way to enable this method, but it can only be done through vSphere MOB, but I personally find it really confusing and not user friendly. And I had no clue how to automate this process. So, I gave up on this.
Then I thought there should be a way to change NSX appliances config through NSX RestAPI. And actually there is.
Here is how you can change the memory reservation of NSX edges using curl. Update the values in bold before using.
1. Grab the NSX edge config and save it in XML file
curl -k -u 'username:password' -H "Content-Type: application/xml" -X GET https://nsxFQDN:443/api/4.0/edges/Edge-ID/appliances/highAvailabilityIndex > XXX.xml
2. Update the memory reservation in xml file.
<limit>-1</limit>
<reservation>YYY</reservation>
</memoryReservation>
3. Update the edge config
curl -k -u 'username:password' -H "Content-Type:application/xml" PUT https://nsxFQDN:443/api/4.0/edges/Edge-ID/appliances/highAvailabilityIndex -d "@XXX.xml"
As you can see you can change some settings of the Edge, but you cannot do the same with controllers. At least I couldn't find anything similar for controllers in NSX RestAPI guide.
Also, it is not easy to automate.
Here is an example of how you can use PowerCLI to automate RestAPI calls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Get-AuthHeader function - used to collect vRO credentials and produce authorization header | |
function Get-AuthHeader($string) { | |
$bytes = [System.Text.Encoding]::UTF8.GetBytes($string); | |
$encoded = [System.Convert]::ToBase64String($bytes); | |
$cred = "Basic $($encoded)" | |
return $cred; | |
} | |
Function Get-NSXRestAPI{ | |
Param( | |
[string]$usr, | |
[string]$pwd, | |
[string]$NSXServer | |
[string]$apiFormat = 'xml', # either xml or json | |
) | |
add-type @" | |
using System.Net; | |
using System.Security.Cryptography.X509Certificates; | |
public class TrustAllCertsPolicy : ICertificatePolicy { | |
public bool CheckValidationResult( | |
ServicePoint srvPoint, X509Certificate certificate, | |
WebRequest request, int certificateProblem) { | |
return true; | |
} | |
} | |
"@ | |
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy | |
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | |
$auth= Get-AuthHeader("$($usr):$($pwd)") | |
$headers = @{"Authorization"=$auth;"Content-Type"="application/$($apiFormat)"} | |
$URLpost = "https://$($NSXServer)/api/4.0/edges/edge-6/appliances" | |
$ret = Invoke-WebRequest -Method get -uri $URLpost -Headers $headers | |
[xml]$rxml = $ret.content | |
return $rxml | |
} | |
$result = Get-NSXRestAPI -usr Username -pwd Password -NSXServer NSXmanagerFQDN |
From here you can update anything you need and change the config using similar PowerCLI function.
As you can see it is more time consuming way of doing things. and again, this is not applicable for NSX controllers.
So I thought I should go back to the original idea of enabling ReconfigVM_task method and started searching for instructions when I found out (once again) that William Lam has already done this. In this post he explains how you can disable vMotion for some of the VMs by disabling MigrateVM_task method. But the most amazing part of that post was that he created PowerCLI functions to enable/disable any methods without using vSphere MOB.
From here it was really easy to create the following script which changes the memory reservation on any VMs - whether they are deployed by NSX or not.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Created by Askar Kopbayev | |
# Description: Changes VM Memory reservations on all VMs to 99%, including NSX Edges and Controllers where ReconfigureVM_Task method is disabled. | |
# Credit to William Lam for amazing functions to Enable and Disable Methods http://www.virtuallyghetto.com/2016/07/how-to-easily-disable-vmotion-cross-vcenter-vmotion-for-a-particular-virtual-machine.html | |
Function Enable-vSphereMethod { | |
param( | |
[Parameter( | |
Position=0, | |
Mandatory=$true, | |
ValueFromPipeline=$true, | |
ValueFromPipelineByPropertyName=$true) | |
] | |
[String]$vmmoref, | |
[string]$vc_server, | |
[String]$vc_username, | |
[String]$vc_password, | |
[String]$enable_method | |
) | |
$secpasswd = ConvertTo-SecureString $vc_password -AsPlainText -Force | |
$credential = New-Object System.Management.Automation.PSCredential($vc_username, $secpasswd) | |
# vSphere MOB URL to private enableMethods | |
$mob_url = "https://$vc_server/mob/?moid=AuthorizationManager&method=enableMethods" | |
# Ingore SSL Warnings | |
add-type -TypeDefinition @" | |
using System.Net; | |
using System.Security.Cryptography.X509Certificates; | |
public class TrustAllCertsPolicy : ICertificatePolicy { | |
public bool CheckValidationResult( | |
ServicePoint srvPoint, X509Certificate certificate, | |
WebRequest request, int certificateProblem) { | |
return true; | |
} | |
} | |
"@ | |
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy | |
# Initial login to vSphere MOB using GET and store session using $vmware variable | |
$results = Invoke-WebRequest -Uri $mob_url -SessionVariable vmware -Credential $credential -Method GET | |
# Extract hidden vmware-session-nonce which must be included in future requests to prevent CSRF error | |
# Credit to https://blog.netnerds.net/2013/07/use-powershell-to-keep-a-cookiejar-and-post-to-a-web-form/ for parsing vmware-session-nonce via Powershell | |
if($results.StatusCode -eq 200) { | |
$null = $results -match 'name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"' | |
$sessionnonce = $matches[1] | |
} else { | |
Write-host "Failed to login to vSphere MOB" | |
exit 1 | |
} | |
# The POST data payload must include the vmware-session-nonce variable + URL-encoded | |
$body = @" | |
vmware-session-nonce=$sessionnonce&entity=%3Centity+type%3D%22ManagedEntity%22+xsi%3Atype%3D%22ManagedObjectReference%22%3E$vmmoref%3C%2Fentity%3E%0D%0A&method=%3Cmethod%3E$enable_method%3C%2Fmethod%3E | |
"@ | |
# Second request using a POST and specifying our session from initial login + body request | |
$results = Invoke-WebRequest -Uri $mob_url -WebSession $vmware -Method POST -Body $body | |
# Logout out of vSphere MOB | |
$mob_logout_url = "https://$vc_server/mob/logout" | |
Invoke-WebRequest -Uri $mob_logout_url -WebSession $vmware -Method GET | |
} | |
Function Disable-vSphereMethod { | |
param( | |
[Parameter( | |
Position=0, | |
Mandatory=$true, | |
ValueFromPipeline=$true, | |
ValueFromPipelineByPropertyName=$true) | |
] | |
[String]$vmmoref, | |
[string]$vc_server, | |
[String]$vc_username, | |
[String]$vc_password, | |
[String]$disable_method | |
) | |
$secpasswd = ConvertTo-SecureString $vc_password -AsPlainText -Force | |
$credential = New-Object System.Management.Automation.PSCredential($vc_username, $secpasswd) | |
# vSphere MOB URL to private disableMethods | |
$mob_url = "https://$vc_server/mob/?moid=AuthorizationManager&method=disableMethods" | |
# Ingore SSL Warnings | |
add-type -ErrorAction Ignore -TypeDefinition @" | |
using System.Net; | |
using System.Security.Cryptography.X509Certificates; | |
public class TrustAllCertsPolicy : ICertificatePolicy { | |
public bool CheckValidationResult( | |
ServicePoint srvPoint, X509Certificate certificate, | |
WebRequest request, int certificateProblem) { | |
return true; | |
} | |
} | |
"@ | |
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy | |
# Initial login to vSphere MOB using GET and store session using $vmware variable | |
$results = Invoke-WebRequest -Uri $mob_url -SessionVariable vmware -Credential $credential -Method GET | |
# Extract hidden vmware-session-nonce which must be included in future requests to prevent CSRF error | |
# Credit to https://blog.netnerds.net/2013/07/use-powershell-to-keep-a-cookiejar-and-post-to-a-web-form/ for parsing vmware-session-nonce via Powershell | |
if($results.StatusCode -eq 200) { | |
$null = $results -match 'name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"' | |
$sessionnonce = $matches[1] | |
} else { | |
Write-host "Failed to login to vSphere MOB" | |
exit 1 | |
} | |
# The POST data payload must include the vmware-session-nonce variable + URL-encoded | |
$body = @" | |
vmware-session-nonce=$sessionnonce&entity=%3Centity+type%3D%22ManagedEntity%22+xsi%3Atype%3D%22ManagedObjectReference%22%3E$vmmoref%3C%2Fentity%3E%0D%0A%0D%0A&method=%3CDisabledMethodRequest%3E%0D%0A+++%3Cmethod%3E$disable_method%3C%2Fmethod%3E%0D%0A%3C%2FDisabledMethodRequest%3E%0D%0A%0D%0A&sourceId=self | |
"@ | |
# Second request using a POST and specifying our session from initial login + body request | |
$results = Invoke-WebRequest -Uri $mob_url -WebSession $vmware -Method POST -Body $body | |
} | |
### Update this section ### | |
$vc_server = "vcenter.home.local" | |
$vc_username = "administrator@vsphere.local" | |
$vc_password = "Password" | |
$method_name = "ReconfigVM_Task" | |
# Connect to vCenter Server | |
$server = Connect-VIServer -Server $vc_server -User $vc_username -Password $vc_password | |
# Get all VMs with 100% of RAM reservation | |
$VMs = get-vm | ?{$_.MemoryGB -eq (Get-VMResourceConfiguration -vm $_).MemReservationGB} | |
# Split them into 2 arrays | |
$NsxVMs = $VMs | ?{$_.extensiondata.disabledmethod -contains "ReconfigVM_Task"} | |
$regularVMs = $VMs | ?{$_.extensiondata.disabledmethod -notcontains "ReconfigVM_Task"} | |
# Change mem reservations for VM where ReconfigVM_Task methdod is not disabled | |
foreach($vm in $regularVMs){ | |
Get-VMResourceConfiguration -vm $vm.name | Set-VMResourceConfiguration -MemReservationGB $($vm.MemoryGB*0.99) | Out-Null | |
Write-host "$VM has"$vm.MemoryMB "MB assigned and" $((Get-VMResourceConfiguration -vm $vm.name).MemReservationMB)"MB reserved" | |
} | |
# Enabled ReconfigVM_Task method for the second array | |
foreach($vm in $NsxVMs){ | |
Enable-vSphereMethod -vc_server $vc_server -vc_username $vc_username -vc_password $vc_password -vmmoref $vm.ExtensionData.MoRef.Value -enable_method $method_name | out-null | |
} | |
sleep 5 | |
# Change mem reservations | |
foreach($vm in $NsxVMs){ | |
Get-VMResourceConfiguration -vm $vm.name | Set-VMResourceConfiguration -MemReservationGB $($vm.MemoryGB*0.99) | Out-Null | |
Write-host "$VM has"$vm.MemoryMB "MB assigned and" $((Get-VMResourceConfiguration -vm $vm.name).MemReservationMB)"MB reserved" | |
} | |
# Disable ReconfigVM_Task method | |
foreach($vm in $NsxVMs){ | |
Disable-vSphereMethod -vc_server $vc_server -vc_username $vc_username -vc_password $vc_password -vmmoref $vm.ExtensionData.MoRef.Value -disable_method $method_name | out-null | |
} | |
# Get all VMs with 100% of RAM reservation | |
$NewVMs = get-vm | ?{$_.MemoryGB -eq (Get-VMResourceConfiguration -vm $_).MemReservationGB} | |
If($newVMs){ | |
Write-host -Fore:red "The following VMs still have 100% of memory reservations" | |
$newVMs | |
} | |
else{ | |
Write-host -Fore:green "No VMs with 100% of RAM reservations were detected" | |
} | |
# Disconnect from vCenter Server | |
Disconnect-viserver $server -confirm:$false |
The script grabs all VMs with 100% of memory reservations and changes this value to 99%. You can change this value to whatever you prefer. If ReconfigureVM method is disabled the script will re-enable it first. After the memory reservation is updated the script will change the ReconfigVM method back to disabled.
All you need to do is to update the vCenter name and credentials before you run the script.
A word of caution - this is not officially supported way of changing the settings of NSX appliances. It works but it's at your own risk.