What do you do when you have over 100 Nutanix nodes scattered across multiple datacenters and need to audit the configurations, or record the configurations for documentation?
Write a powershell script that queries the REST API of course!
In this instance I needed a known starting point. I didn’t have all of the IP addresses of the CVMs, hosts, etc in a format that I could query. What I did have was all of the hosts in vCenter along with all of their CVMs. So this script starts by connecting to all of the vCenters in the Datacenters and getting a list of all of the CVMs and their IP addresses. It then runs REST API queries against the CVM IPs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
#This script requires the VMware PowerCLI modules as well at least Powershell 3.0 for the Invoke-RestMethod #Connect to all of the vCenters connect-viserver datacenter01-vc01.example.com -force connect-viserver datacenter02-vc01.example.com -force connect-viserver datacenter03-vc01.example.com -force connect-viserver datacenter04-vc01.example.com -force connect-viserver datacenter05-vc01.example.com -force #Accept self signed certs 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 #Create the call to the REST API and pass authentication $username = "admin" $password = "admin" $Header = @{"Authorization" = "Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($username+":"+$password ))} #Query the connected viservers and get all of the CVMs, their IP addreses, vSphere Clusters, and vSphere Datacenters $cvms = get-VM -Name NTNX* | Select Name, @{N="cvmIP";E={@($_.guest.IPAddress[0])}}, @{N="vCluster";E={($_ | Get-Cluster)}}, @{N="vDatacenter";E={($_ | Get-Datacenter)}} #Create a node hash table, assign properties to a node and create one node for each CVM $nodes = @() for ($i=0; $i -lt $cvms.cvmIP.count; $i++) { $node = New-Object PSObject -Property @{ block = @{} position = @{} model = @{} cvmName = $cvms[$i].Name hostname = @{} cvmIP = $cvms[$i].cvmIP hostIP = @{} ipmiIP = @{} vSphereCluster = $cvms[$i].vCluster datacenter = $cvms[$i].vDatacenter datastores = @{} containers = @{} storagePool = @{} nutanixCluster = @{} nosVersion = @{} } $nodes += $node } #Querying the REST API returns a hash table (array). Instantiate hash tables for hosts, clusters, containers, and storage pools. #In a future version hopefully Nutanix publishes the filterCritera for REST API calls so we don't have to iterate through these #arrays, but can retrieve the specific objects that we want. $hosts = @{} $clusters = @{} $containers = @{} $storagePools = @{} for ($i=0; $i -lt $cvms.cvmIP.count; $i++) { $hosts[$i] = (Invoke-RestMethod -Method Get -Uri "https://$($cvms.cvmIP[$i]):9440/PrismGateway/services/rest/v1/hosts/" -Headers $Header) for ($j=0;$j -lt $hosts[$i].entities.count; $j++) { if ($hosts[$i].entities[$j].serviceVMExternalIP -eq $cvms.cvmIP[$i]) { $nodes[$i].block = $hosts[$i].entities[$j].blockSerial $nodes[$i].model = $hosts[$i].entities[$j].blockModel $nodes[$i].position = $hosts[$i].entities[$j].position.name $nodes[$i].hostIP = $hosts[$i].entities[$j].hypervisorAddress $nodes[$i].ipmiIP = $hosts[$i].entities[$j].ipmiAddress $nodes[$i].hostname = $hosts[$i].entities[$j].name } } $clusters[$i] = (Invoke-RestMethod -Method Get -Uri "https://$($cvms.cvmIP[$i]):9440/PrismGateway/services/rest/v1/cluster/" -Headers $Header) for ($j=0;$j -lt $hosts[$i].entities.count; $j++) { if ($hosts[$i].entities[$j].serviceVMExternalIP -eq $cvms.cvmIP[$i]) { $nodes[$i].nutanixCluster = $clusters[$i].name $nodes[$i].nosVersion = $clusters[$i].version } } $containers[$i] = (Invoke-RestMethod -Method Get -Uri "https://$($cvms.cvmIP[$i]):9440/PrismGateway/services/rest/v1/containers/" -Headers $Header) for ($j=0;$j -lt $hosts[$i].entities.count; $j++) { if ($hosts[$i].entities[$j].serviceVMExternalIP -eq $cvms.cvmIP[$i]) { $nodes[$i].containers = $containers[$i].entities.name $nodes[$i].datastores = $containers[$i].entities.vstoreNameList } } $storagePools[$i] = (Invoke-RestMethod -Method Get -Uri "https://$($cvms.cvmIP[$i]):9440/PrismGateway/services/rest/v1/storage_pools/" -Headers $Header) for ($j=0;$j -lt $hosts[$i].entities.count; $j++) { if ($hosts[$i].entities[$j].serviceVMExternalIP -eq $cvms.cvmIP[$i]) { $nodes[$i].storagePool = $storagePools[$i].entities.name } } } #Export the node objects to CSV $nodes | Select ( @{Expression={$_.hostname};Label="hostname"}, @{Expression={$_.hostIP};Label="hostIP"}, @{Expression={$_.cvmIP};Label="CVMIP"}, @{Expression={$_.ipmiIP};Label="IPMI"}, @{Expression={$_.cvmName};Label="CVM Name"}, @{Expression={$_.nutanixCluster};Label="Nutanix Cluster"}, @{Expression={$_.storagePool};Label="Storage Pool"}, @{Expression={$_.containers};Label="Containers"}, @{Expression={$_.datacenter};Label="Datacenter"}, @{Expression={$_.vSphereCluster};Label="vSphereCluster"}, @{Expression={$_.datastores};Label="Datastores"}, @{Expression={$_.model};Label="Model"}, @{Expression={$_.block};Label="Block"}, @{Expression={$_.position};Label="Position"}, @{Expression={$_.nosVersion};Label="NOS Version"} ) | Sort hostname, CVMIP | Export-CSV Nutanix_info.csv -NoTypeInformation |
Here’s what the output looks like when opened in Excel (and scrubbed of proprietary information):
Any blocks that are not configured yet, or are not running a version of NOS that has the REST API, or do not have network connectivity will return System.Collections.Hashtable values as you can see below.
Hi Josh
Great script, very useful!
Sam