VI-DB db-base-data-sub-v2.9.ps1
Jump to navigation
Jump to search
<# ========================================================================================================================================
Database Base Data Getter - Sub-script
=========================================================================================================================================
Simon Strutt Apr 2011
=========================================================================================================================================
Version 2
- Initial creation !
Version 2.1 - July 2011
- Performance improvements (reduce's runtime by about 60%)
-- Improved VM Cluster get to use lookup table
-- Changed VM Guest OS get to use existing VM object
- Bugfix: Lab Manager VM's not being removed after deletion (include checking of Persistent ID)
Version 2.2
- Minor improvements to error messages
- Performance improvements
-- Caching of Get-VMHostNetworkAdapter during ESX info gather
- Added VMTools state and VM version
Version 2.3
- Added ESX NIC firmware version
Version 2.4
- Bugfix: VM's not in cluster don't get added to db (introduced in v2.1)
- Bugfix: "Couldn't find ESX ID for VM" error catch not working
- Added VM custom attributes
- Added vApps
Version 2.4.1
- Bugfix: vm2ip can get populated with incorrect IP when VM is shutdown
- Bugfix: vApps with no VM's not handled (causing invalid SQL statement, and so script crash)
Version 2.5
- Bugfix: Remove old VMDK's for VMs didn't work (SQL query incorrect)
- Bugfix: VM NICs with multiple IPs not handled correctly
- Improved error logging (DS inaccessible, VMs not in cluster)
- Added sev0 error log at completion to signal parent script that script exited cleanly
Version 2.6
- Bugfix: Networks not being removed from ESX's when they no longer exist / no longer configured on ESX
- Bugfix: Datastores not being removed from ESX's when they no longer exist / no longer configured on ESX
- Change VC last updated field update to end of run
- Prevent VM IP address being overwritten / blanked by 0.0.0.0
Version 2.7
- Bugfix: VM's showing with incorrect Cluster (affecting duplicate name VMs)
- Bugfix: Handle foreign (eg French) names for VM hard disk and network adapte
- Improved IP address handling (filter out non-IPv4, blank addresses)
- Get NAT's from Vyatta router
Version 2.8
- Bugfix: PS Exceptions thrown when determining network types
- Bugfix: Unable to get NIC number for some VI3 VM's (introduced by foreign name handling)
- Changed Vyatta NATing to so that NAT NIC has NwId that matches NAT'ed IP range
- Add datastore block size and canonical name
- Add ESX - LUN multipathing policy
Version 2.9
- Add VM disk rdm yes/no (need to add LUN info etc)
- Add VM resource limits / shares
- Bugfix: Networks not being added and removed properly (multiple probs)
TO DO
- Show ESX's in clusters with inconsistent datastores
- Add VM RDM disk LUN ID (use UK-B-SQL-103 as example)
- Add VM disk usage
- Add DRS groups
- Add VM Templates
- Improve removed VM clearup (vmdk, vm_nic)
- Add basic process perf stats
========================================================================================================================================#>
# Get/handle job parameters
$var = $Input.‘<>4__this’.Read()
$VC_name = $var[0]
$VC_vcid = $var[1]
$cred = $var[2]
$DBuser = $var[3]
$DBpass = $var[4]
$database = $var[5]
$MySQLHost = $var[6]
$runid = $var[7]
Set-Location $var[8]
# Include library files
. .\lib\Standard-v4.ps1
. .\lib\PowerCLI-helper-v1.1.ps1
. .\temp\DS-LUN-v4.ps1
. .\lib\getsnapshotsize-1.ps1
. .\lib\MySQL-v1.ps1
$start = Get-Date
$LogStamp = "Time" # Log timestamp format (Duration or Time (stamp))
Log "Started sub-script run at $start"
# Load VMware PS Snapin
Log("Loading VMware PowerShell Snapin...")
Add-PsSnapin *VMware*
$ScriptVer = [regex]::matches(($MyInvocation.MyCommand.Name), "(?<=v)[0-9]+(\.[0-9])+(?=.)")
Log ("Script version is $ScriptVer (" + (Get-PowerCLIversion).UserFriendlyVersion + " / Powershell " + (get-host).Version.ToString() + ")")
# Flags
$UpdateScriptRun = 1 # Update script runs log in database
$LogNonQueries = 1 # Non Query (insert/update etc) logging (gets forced if in debug mode)
$UpdateCL = 1 # Clusters
$UpdateESX = 1 # ESXs
$UpdateDS = 1 # Datastores
$UpdateNW = 1 # Networks
$UpdateVApp = 1 # vApps
$UpdateVM = 1 # Virtual Machines
$UpdateVyNAT = 1 # Vyatta NATs (requires $UpdateVM)
$VyattaUser = "vi-db"
$VyattaPass = "syndrome"
if (!$runid) {
$UpdateScriptRun = 0
}
# Connect to MySQL database
$SQLconn = ConnectMySQL $DBuser $DBpass $MySQLHost $database
#if (!$UpdateCL -or !$UpdateESX -or !$UpdateDS -or !$UpdateNW -or !$UpdateVM) {
# $UpdateScriptRun = 0
# Log("Updating of script run info in db disabled (performing partial run)")
#}
function Log-Error($text, $vcid=$VC_vcid, $sev=3) {
$script:ErrorLog += $text
Log ("ERROR: " + $text)
Log ("Error count now " + $ErrorLog.Length)
if ($UpdateScriptRun) {
ExecuteMySQLNonQuery("INSERT INTO script_run_error (runid, sev, vcid, text) VALUES ($runid, $sev, $vcid, '" + (EscQuote $text) + "');")
}
}
function Log-Perf {
Log ("Perf CPU(sec): " + [Math]::Round($proc.cpu, 0) + ", Paged Mem (MB): " + [Math]::Round(($proc.pm/1024), 0) + ", WrkSet Mem (MB): " + [Math]::Round(($proc.ws/1024), 0))
}
# Connect to vCentre
try {
Log("Connecting to " + $VC_name)
$VCconn = Connect-VIServer -Server $VC_name -Credential $cred -WarningAction SilentlyContinue -ErrorAction "Stop"
} catch [VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.InvalidLogin] {
Log("Unable to connect to vCentre, invalid logon error !!")
Log("Abandoning further script processing in order to prevent potential account lockout.")
Log-Error -text "vCentre invalid login error, script halt to prevent potential account lockout." -sev 2
$Major_Error = 99
Break
} catch {
Log-Error -text ("Unable to connect to vCentre - " + $_) -sev 2
$Major_Error += 1
Continue
}
$vcinfo = (Get-View ServiceInstance).Content.About
if ($vcinfo.Version -lt 4) {
$UpdateVApp = 0
Log("Updating of vApp info disabled (this is a v3 vCentre!)")
}
# Clusters ------------------------------------------------------------------------------------------------------------------------------
if ($UpdateCL) {
Log ("Getting CLUSTERS....")
# Get existing clusters from VC
$vcClusters = Get-Cluster
foreach ($cl in $vcClusters) {
# Add/update cluster
if ($cl.DrsEnabled) {
$query = "INSERT INTO cluster (vcid, name, ha, drs, exist) VALUES ('$VC_vcid', '" + $cl.Name + "', '" + $cl.HAEnabled.GetHashCode() + "', '" + $cl.DrsAutomationLevel + "', 1) "
$query += "ON DUPLICATE KEY UPDATE ha=" + $cl.HAEnabled.GetHashCode() + ", drs='" + $cl.DrsAutomationLevel + "', exist=1;"
} else {
$query = "INSERT INTO cluster (vcid, name, ha, drs, exist) VALUES ('$VC_vcid', '" + $cl.Name + "', '" + $cl.HAEnabled.GetHashCode() + "', '" + $cl.DrsEnabled.GetHashCode() + "', 1) "
$query += "ON DUPLICATE KEY UPDATE ha=" + $cl.HAEnabled.GetHashCode() + ", drs='" + $cl.DrsEnabled.GetHashCode() + "', exist=1;"
}
ExecuteMySQLNonQuery($query)
}
# Mark clusters that no longer exist
$dbClusters = ExecuteMySQLQuery("SELECT clid, name FROM cluster WHERE vcid=$VC_vcid AND exist=1;")
foreach ($cl in $dbClusters) {
if (!($vcClusters |?{$_.Name -eq $cl.name})) {
if (!$cl.clid) {
Continue
}
Log ("HIDE: " + $cl.name)
ExecuteMySQLNonQuery("UPDATE cluster SET exist=0 WHERE clid=" + $cl.clid + ";")
}
}
}
# ESX --------------------------------------------------------------------------------------------------------------------------------
if ($UpdateESX) {
Log ("Getting ESXs....")
$vcESXs = Get-VMHost
# Get clusters and ESXs from db
$dbClusters = ExecuteMySQLQuery("SELECT clid, name FROM cluster WHERE vcid = " + $VC_vcid + " AND exist=1;")
# Add/update info in db
foreach ($esx in $vcESXs) {
$clid = $dbClusters |?{$_.name -eq $esx.Parent} | Select -ExpandProperty clid
if (!$clid) {
$clid = "NULL"
}
$name = [regex]::matches($esx.Name, "(^\b((25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\b)|(\A(\w|-)+)")
$query = "INSERT INTO esx (vcid, clid, name, exist, ver, build, model, cpu_core, cpu_sock, mem, cpu_model) "
$query += "VALUES (" + $VC_vcid + ", $clid, '" + $name + "', 1"
$query += ", '" + $esx.Version + "', " + $esx.Build + ", '" + ($esx.Model -replace ' {2,}',' ') + "', " + $esx.NumCpu + ", " + $esx.ExtensionData.Hardware.CpuPkg.Count + ", " + $esx.MemoryTotalMB
$query += ", '" + $esx.ExtensionData.Summary.Hardware.CpuModel + "') ON DUPLICATE KEY UPDATE esxid=LAST_INSERT_ID(esxid), clid=$clid"
$query += ", exist=1, ver='" + $esx.Version + "', build=" + $esx.Build + ", model='" + ($esx.Model -replace ' {2,}',' ')
$query += "', cpu_core=" + $esx.NumCpu + ", cpu_sock=" + $esx.ExtensionData.Hardware.CpuPkg.Count + ", mem=" + $esx.MemoryTotalMB + ", cpu_model='" + $esx.ExtensionData.Summary.Hardware.CpuModel + "';"
ExecuteMySQLNonQuery($query)
# Get esxid from last query
$esxid = ExecuteMySQLScalar("SELECT LAST_INSERT_ID();")
#Debug($esx.Name.Split(".")[0] + " esxid is $esxid")
$query = "INSERT INTO esx_state (esxid, state) VALUES (" + $esxid + ", '" + $esx.ConnectionState + "') ON DUPLICATE KEY UPDATE state='" + $esx.ConnectionState + "';"
ExecuteMySQLNonQuery($query)
# Add/update info in extended db tables
if ($esx.ConnectionState.ToString() -notmatch "Connected" -and $esx.ConnectionState.ToString() -notmatch "Maintenance") {
Log-Error ("ESX $name not connected so unable to get NIC / HBA info")
Continue
}
# Store objects which get re-used for efficiency
$ESXview = Get-View -VIObject $ESX
$VMHostNetworkAdapter = Get-VMHostNetworkAdapter -VMHost $esx
# Extended data
$ip = ($VMHostNetworkAdapter | Where {$_.ManagementTrafficEnabled -eq "True" -or $_.DeviceName -like "vswif*" -or $_.Name -eq "vmk0"}).IP
$syslogSvr = $esx.ExtensionData.Config.Option.GetEnumerator() | ?{$_.Key -eq "Syslog.Remote.Hostname"} | Select -ExpandProperty Value
if ($ESXView.Hardware.BiosInfo) { # Works on some systems
$BiosVer = $ESXview.Hardware.BiosInfo.BiosVersion + " " + $ESXview.Hardware.BiosInfo.ReleaseDate.ToString("yyyy-MM-dd") # Need date for HP servers as they use same version no for diff versions!
} else {
$BiosVer = ($ESXview.Runtime.HealthSystemRuntime.SystemHealthInfo.NumericSensorInfo | Where {$_.Name -like "*BIOS*"}).Name
$BiosVer = ([regex]::Matches($BiosVer, "[A-Z]\d{2} 20\d{2}-\d{2}-\d{2}"))[0].Value # HP regex to extract "A19 2010-09-30" for example
}
$dns1 = $esx.ExtensionData.Config.Network.DnsConfig.Address[0]
$dns2 = $esx.ExtensionData.Config.Network.DnsConfig.Address[1]
$query = "INSERT INTO esx_ext (esxid, ip, domain, dns_svr1, dns_svr2, syslog, bios_ver) VALUES ($esxid, INET_ATON('$ip'), '" + $esx.ExtensionData.Config.Network.DnsConfig.DomainName
$query += "', INET_ATON('$dns1'), INET_ATON('$dns2'), '$syslogSvr', '$BiosVer') "
$query += "ON DUPLICATE KEY UPDATE ip=INET_ATON('$ip'), domain='" + $esx.ExtensionData.Config.Network.DnsConfig.DomainName + "', dns_svr1=INET_ATON('$dns1'), "
$query += "dns_svr2=INET_ATON('$dns2'), syslog='$syslogSvr', bios_ver='$BiosVer';"
ExecuteMySQLNonQuery($query)
# NTP data
$idx=0
$ntp_svrs = $esx.ExtensionData.Config.DateTimeInfo.NtpConfig.Server
foreach ($ntp in $ntp_svrs) {
ExecuteMySQLNonQuery("INSERT INTO esx_ntp (esxid, idx, svr) VALUES ($esxid, $idx, '$ntp') ON DUPLICATE KEY UPDATE svr='$ntp';")
$idx += 1
}
# Remove NTP entires that no longer exist
$dbESXntps = ExecuteMySQLQuery("SELECT svr FROM esx_ntp WHERE esxid=$esxid;")
foreach ($dbESXntp in $dbESXntps) {
if (!$dbESXntp.svr -or ($ntp_svrs |?{$_ -eq $dbESXntp.svr})) {
Continue
}
Log("REMOVE: " + $esx.name + " " + $dbESXntp.svr)
ExecuteMySQLNonQuery("DELETE FROM esx_ntp WHERE esxid=$esxid AND svr='" + $dbESXntp.svr + "';")
}
# HBA data
$vmhbas = $esx.ExtensionData.Config.StorageDevice.HostBusAdapter | Where {$_.Key -like "*FibreChannel*"}
foreach ($vmhba in $vmhbas) {
$ver = ($ESXview.Runtime.HealthSystemRuntime.SystemHealthInfo.NumericSensorInfo | Where {$_.Name -like "*" + $vmhba.Driver + "*"}).Name
$ver = ([regex]::Matches($ver, "(\b\d)(.*?)(?=\s)"))[0].Value
$query = "INSERT INTO esx_hba (esxid, device, model, driver, drv_ver) VALUES ($esxid, '" + $vmhba.Device + "', '" + $vmhba.Model + "', '" + $vmhba.Driver + "', '$ver') "
$query += "ON DUPLICATE KEY UPDATE device='" + $vmhba.Device + "', model='" + $vmhba.Model + "', driver='" + $vmhba.Driver + "', drv_ver='$ver';"
ExecuteMySQLNonQuery($query)
}
# Remove HBA's that no longer exist
$dbESXhbas = ExecuteMySQLQuery("SELECT device FROM esx_hba WHERE esxid=$esxid;")
foreach ($dbESXhba in $dbESXhbas) {
if (!$dbESXhba.device -or ($vmhbas |?{$_.Device -eq $dbESXhba.device})) {
Continue
}
Log("REMOVE: " + $esx.name + " " + $dbESXhba.device)
ExecuteMySQLNonQuery("DELETE FROM esx_hba WHERE esxid=$esxid AND device='" + $dbESXhba.device + "';")
}
# NIC data
$vmnics = $VMHostNetworkAdapter | Where {$_.Id -like "*.PhysicalNic*"}
$nicDevices = $esxView.Hardware.PciDevice | Where {$_.ClassId -eq 512}
foreach ($vmnic in $vmnics) {
$ver = ($ESXview.Runtime.HealthSystemRuntime.SystemHealthInfo.NumericSensorInfo | Where {$_.Name -like $vmnic.ExtensionData.Driver + " driver*"} | Get-Unique).Name
$ver = ([regex]::Matches($ver, "(\b\d)(.*)(?=\s)"))[0].Value # Strips out any superfluous text (or rather, matches a version number)
$fware = ($ESXview.Runtime.HealthSystemRuntime.SystemHealthInfo.NumericSensorInfo | Where {$_.Name -like $vmnic.ExtensionData.Driver + " device firmware*"} | Get-Unique).Name
$fware = ([regex]::Matches($fware, "(\b\d)(.*)(?=\s)"))[0].Value # Strips out any superfluous text (or rather, matches a version number)
$nicDev = $nicDevices | Where {$_.Id -eq $vmnic.ExtensionData.Pci} | Select VendorName, DeviceName
#Log ("Device : " + $vmnic.DeviceName)
#Log ("Speed : " + $vmnic.BitRatePerSec + " MB")
#Log ("Driver : " + $vmnic.ExtensionData.Driver)
#Log ("Version : " + )
#Log ("PCI : " + $vmnic.ExtensionData.Pci)
#Log ("Model : " + $nicDev.VendorName + " " + $nicDev.DeviceName)
$query = "INSERT INTO esx_nic (esxid, device, speed, model, driver, drv_ver, fware) VALUES ($esxid, '" + $vmnic.DeviceName + "', " + $vmnic.BitRatePerSec
$query += ", '" + $nicDev.VendorName + " " + $nicDev.DeviceName + "', '" + $vmnic.ExtensionData.Driver + "', '$ver', '$fware') ON DUPLICATE KEY UPDATE "
$query += "speed=" + $vmnic.BitRatePerSec + ", model='" + $nicDev.VendorName + " " + $nicDev.DeviceName + "', driver='" + $vmnic.ExtensionData.Driver + "', drv_ver='$ver', fware='$fware';"
ExecuteMySQLNonQuery($query)
}
# Remove NIC's that no longer exist
$dbESXnics = ExecuteMySQLQuery("SELECT device FROM esx_nic WHERE esxid=$esxid;")
foreach ($dbESXnic in $dbESXnics) {
if (!$dbESXnic.device -or ($vmnics |?{$_.DeviceName -eq $dbESXnic.device})) {
Continue
}
Log("REMOVE: " + $esx.name + " " + $dbESXnic.device)
ExecuteMySQLNonQuery("DELETE FROM esx_nic WHERE esxid=$esxid AND device='" + $dbESXnic.device + "';")
}
}
# Mark ESX's that no longer exist
$dbESXs = ExecuteMySQLQuery("SELECT esxid, name FROM esx WHERE vcid = " + $VC_vcid + " AND exist=1;")
foreach ($esx in $dbESXs) {
if (!$esx.esxid -or ($vcESXs |?{$_.Name.Split(".")[0] -eq $esx.name})) {
Continue
}
Log("HIDE: " + $esx.name)
ExecuteMySQLNonQuery("UPDATE esx SET exist=0 WHERE esxid=" + $esx.esxid + ";")
}
# Check for ESX's that have moved cluster
$dbESXs = ExecuteMySQLQuery("SELECT esxid, name, COUNT(*) AS count, clid FROM esx WHERE vcid=" + $VC_vcid + " AND exist=1 GROUP BY name;")
foreach ($esx in $dbESXs) {
if ($esx.count -gt 1) {
Log("HIDE dupe: " + $esx.name)
# First esxid will be old, SELECT provides the first ID, so easy to remove
ExecuteMySQLNonQuery("UPDATE esx SET exist=0 WHERE esxid=" + $esx.esxid + ";")
}
}
}
# Datastores ------------------------------------------------------------------------------------------------------------------------------
if ($UpdateDS) {
Log ("Getting DATASTORES....")
$vcDSs = Get-Datastore
# Get SAN model(s) and LUN ID's
if ($vcinfo.version -lt 4) {
Log("Getting v3 LUN info...")
$luns = Get-DS-LUNs-v3 (Get-VMHost)
} else {
Log("Getting v4 LUN info...")
$luns = Get-DS-LUNs-v4
}
Log("...got " + $luns.count + " LUNs")
foreach ($ds in $vcDSs) {
if (!$ds.Accessible) {
Log-Error ("Datastore is inaccessible/down: " + $ds.Name)
Continue
}
$lun = $luns |?{$_.Datastore -eq $ds.Name}
if (!$lun) {
Log-Error ("Couldn't find LUN ID for datastore " + $ds.Name)
Continue
}
# Workaround for occassional duplicate LUNs retruned by Get-DS-LUN
if ($lun.count) {
$lun = $lun[0]
}
if ($ds.ExtensionData.Info.Vmfs.Extent.Count -ne 1) {
$canonical = "NULL"
Log-Error ("Can't get canonical name for datastore " + $ds.Name + " (extents=" + $ds.ExtensionData.Info.Vmfs.Extent.Count + ")")
} else {
$canonical = "'" + $ds.ExtensionData.Info.Vmfs.Extent[0].DiskName + "'"
}
$query = "INSERT INTO ds (vcid, name, exist, size, used, san_model, lun, block, canonical) VALUES ('" + $VC_vcid + "', '" + $ds.Name + "', 1, " + $ds.CapacityMB + ", " + ($ds.CapacityMB - $ds.FreeSpaceMB)
$query += ", '" + $lun.Make + " " + $lun.Model + "', " + $lun.LUN + ", " + $ds.ExtensionData.Info.Vmfs.BlockSizeMB + ", $canonical) ON DUPLICATE KEY UPDATE "
$query += "exist=1, size=" + $ds.CapacityMB + ", used=" + ($ds.CapacityMB - $ds.FreeSpaceMB) + ", san_model='" + $lun.Make + " " + $lun.Model + "', lun=" + $lun.LUN + ", "
$query += "block=" + $ds.ExtensionData.Info.Vmfs.BlockSizeMB + ", canonical=$canonical;"
ExecuteMySQLNonQuery($query)
}
# Link ESX's to DS's
$dbESXs = ExecuteMySQLQuery("SELECT esxid, name FROM esx WHERE vcid = " + $VC_vcid + " AND exist=1;")
$dbDSs = ExecuteMySQLQuery("SELECT dsid, name, canonical FROM ds WHERE vcid = " + $VC_vcid + " AND exist=1;")
foreach ($esx in $dbESXs) {
if (!$esx.esxid) {
Continue
}
$vcESXDSs = Get-Datastore -VMHost (Get-VMHost ($esx.name + "*"))
$vcESXLuns = Get-ScsiLun -VMHost (Get-VMHost ($esx.name + "*"))
foreach ($esxds in $vcESXDSs) {
# Match ESX DS name to db dsid
$dsid = $dbDSs |?{$_.name -eq $esxds.Name}
if (!$dsid.dsid) {
Log-Error ("Couldn't find " + $esx.name + " datastore " + $esxds.Name + " in db")
Continue
}
# Get path policy
if ($dsid.canonical) {
$mpath = $vcESXLuns |?{$_.CanonicalName -eq $dsid.canonical} | Select -ExpandProperty MultipathPolicy
if (!$mpath) {
Log-Error ("Couldn't find multipath policy for " + $esx.name + " datastore " + $esxds.Name)
ExecuteMySQLNonQuery("INSERT IGNORE INTO esx2ds (esxid, dsid) VALUES (" + $esx.esxid + ", " + $dsid.dsid +");")
Continue
}
ExecuteMySQLNonQuery("INSERT INTO esx2ds (esxid, dsid, mpath) VALUES (" + $esx.esxid + ", " + $dsid.dsid +", '$mpath') ON DUPLICATE KEY UPDATE mpath='$mpath';")
} else {
ExecuteMySQLNonQuery("INSERT IGNORE INTO esx2ds (esxid, dsid) VALUES (" + $esx.esxid + ", " + $dsid.dsid +");")
}
}
# Unlink datastores that are no longer configured on ESX
$dbESXDSs = ExecuteMySQLQuery("SELECT dsid, ds.name FROM esx2ds JOIN ds USING (dsid) WHERE esxid = " + $esx.esxid + ";")
foreach ($esxds in $dbESXDSs) {
if (!$esxds.nwid) {
Continue
}
if (!($vcESXDSs|?{$_.Name -eq $esxds.Name})) {
Log ("UNLINK: " + $esx.name + " Datastore " + $esxds.Name)
#Log ("DELETE FROM esx2ds WHERE esxid=" + $esx.esxid+ " AND dsid=" + $esxds.dsid + ";")
ExecuteMySQLNonQuery("DELETE FROM esx2ds WHERE esxid=" + $esx.esxid + " AND dsid=" + $esxds.dsid + ";")
}
}
}
# Mark datastores that no longer exist
$dbDSs = ExecuteMySQLQuery("SELECT dsid, name FROM ds WHERE vcid = " + $VC_vcid + " AND exist=1;")
foreach ($ds in $dbDSs) {
if (!($vcDSs |?{$_.Name -eq $ds.name})) {
if (!$ds.dsid) {
Continue
}
Log ("HIDE: " + $ds.name)
ExecuteMySQLNonQuery("UPDATE ds SET exist=0 WHERE dsid=" + $ds.dsid + ";")
ExecuteMySQLNonQuery("DELETE FROM esx2ds WHERE dsid=" + $ds.dsid + ";")
}
}
}
# Networks ------------------------------------------------------------------------------------------------------------------------------
if ($UpdateNW) {
Log ("Getting NETWORKS....")
# Get special network types
$MgmtNWs = Get-VMHostNetworkAdapter -VMKernel -Console | Where {$_.ManagementTrafficEnabled -eq "True"} | Select -Property PortGroupName -Unique
$vMotNWs = Get-VMHostNetworkAdapter -VMKernel -Console | Where {$_.VMotionEnabled -eq "True"} | Select -Property PortGroupName -Unique
$FTolNWs = Get-VMHostNetworkAdapter -VMKernel -Console | Where {$_.FaultToleranceLoggingEnabled -eq "True"} | Select -Property PortGroupName -Unique
# Get standard (old school) port groups
$vcNWs = Get-VirtualPortGroup -Standard
foreach ($nw in $vcNWs) {
if (!$nw.VLanId) {
$vlan = "NULL"
} else {
$vlan = $nw.VLanId
}
if ($MgmtNWs |?{$_.PortGroupName -eq $nw.Name}) {$is_mgmt = 1} else {$is_mgmt = 0}
if ($vMotNW |?{$_.PortGroupName -eq $nw.Name}) {$is_vmk = 1} else {$is_vmk = 0}
if ($FTolNWs |?{$_.PortGroupName -eq $nw.Name}) {$is_ft = 1} else {$is_ft = 0}
$query = "INSERT INTO nw (vcid, name, vkey, exist, vlan, is_mgmt, is_vmk, is_ft, is_dv) VALUES ('" + $VC_vcid + "', '" + $nw.Name + "', '" + $nw.Key + "', 1, $vlan, $is_mgmt, $is_vmk, $is_ft, 0) "
$query += "ON DUPLICATE KEY UPDATE vkey='" + $nw.Key + "', exist=1, vlan=$vlan, is_mgmt=$is_mgmt, is_vmk=$is_vmk, is_ft=$is_ft, is_dv=0;"
ExecuteMySQLNonQuery($query)
}
if ($vcinfo.Version -ge 4) {
Log ("Getting dvSwitches....")
# Get distributed port groups
$vcNWs = Get-VirtualPortGroup -Distributed
foreach ($nw in $vcNWs) {
if ($nw.ExtensionData.Config.DefaultPortConfig.Vlan.VlanId.GetType().IsArray) {
$vlan= 9999
} elseif (!$nw.ExtensionData.Config.DefaultPortConfig.Vlan.VlanId) {
$vlan = "NULL"
} else {
$vlan = $nw.ExtensionData.Config.DefaultPortConfig.Vlan.VlanId
}
if ($MgmtNWs |?{$_.PortGroupName -eq $nw.Name}) {$is_mgmt = 1} else {$is_mgmt = 0}
if ($vMotNW |?{$_.PortGroupName -eq $nw.Name}) {$is_vmk = 1} else {$is_vmk = 0}
if ($FTolNWs |?{$_.PortGroupName -eq $nw.Name}) {$is_ft = 1} else {$is_ft = 0}
$query = "INSERT INTO nw (vcid, name, vkey, exist, vlan, is_mgmt, is_vmk, is_ft, is_dv) VALUES ('" + $VC_vcid + "', '" + $nw.Name + "', '" + $nw.Key + "', 1, $vlan, $is_mgmt, $is_vmk, $is_ft, 1) "
$query += "ON DUPLICATE KEY UPDATE vkey='" + $nw.Key + "', exist=1, vlan=$vlan, is_mgmt=$is_mgmt, is_vmk=$is_vmk, is_ft=$is_ft, is_dv=1;"
ExecuteMySQLNonQuery($query)
}
} else {
Log("Skipping dvSwitch gather (pre vSphere vCentre)")
}
# Link ESX's to NW's
$dbESXs = ExecuteMySQLQuery("SELECT esxid, name FROM esx WHERE vcid = " + $VC_vcid + " AND exist=1;")
$dbNWs = ExecuteMySQLQuery("SELECT nwid, vkey FROM nw WHERE vcid = " + $VC_vcid + " AND exist=1;")
foreach ($esx in $dbESXs) {
if (!$esx.esxid) {
Continue
}
$vcESXNWs = Get-VirtualPortGroup -VMHost (Get-VMHost ($esx.name + "*"))
foreach ($esxnw in $vcESXNWs) {
# Catch linking failure (prevents SQL query failure, allows script to continue)
$nwid = $dbNWs |?{$_.vkey -eq $esxnw.Key} | Select -ExpandProperty nwid
if (!$nwid) {
Log-Error ("Couldn't find network " + $esxnw.Name + " (vlan " + $esxnw.VLanId + ") in db for " + $esx.name)
Continue
}
ExecuteMySQLNonQuery("INSERT IGNORE INTO esx2nw (esxid, nwid) VALUES (" + $esx.esxid + ", $nwid);")
}
# Unlink networks that are no longer configured on ESX
$dbESXNWs = ExecuteMySQLQuery("SELECT nwid, nw.vkey FROM esx2nw JOIN nw USING (nwid) WHERE esxid = " + $esx.esxid + ";")
foreach ($esxnw in $dbESXNWs) {
if (!$esxnw.nwid) {
Continue
}
if (!($vcESXNWs|?{$_.Key -eq $esxnw.vkey})) {
Log ("UNLINK: " + $esx.name + " Network " + $esxnw.Name)
#Log ("DELETE FROM esx2nw WHERE esxid=" + $esx.esxid+ " AND nwid=" + $esxnw.nwid + ";")
ExecuteMySQLNonQuery("DELETE FROM esx2nw WHERE esxid=" + $esx.esxid + " AND nwid=" + $esxnw.nwid + ";")
}
}
}
# Mark networks that no longer exist (standard switch)
$vcNWs = Get-VirtualPortGroup -Standard
$dbNWs = ExecuteMySQLQuery("SELECT nwid, name, vkey FROM nw WHERE vcid = " + $VC_vcid + " AND is_dv=0 AND exist=1;")
foreach ($nw in $dbNWs) {
if (!($vcNWs |?{$_.Key -eq $nw.vkey})) {
if (!$nw.nwid) {
Continue
}
Log ("HIDE Standard: " + $nw.name)
ExecuteMySQLNonQuery("UPDATE nw SET exist=0 WHERE nwid=" + $nw.nwid + ";")
ExecuteMySQLNonQuery("DELETE FROM esx2nw WHERE nwid=" + $nw.nwid + ";")
}
}
# Mark networks that no longer exist (dvSwitch)
if ($vcinfo.Version -ge 4) {
$vcNWs = Get-VirtualPortGroup -Distributed
$dbNWs = ExecuteMySQLQuery("SELECT nwid, name, vkey FROM nw WHERE vcid = " + $VC_vcid + " AND is_dv=1 AND exist=1;")
foreach ($nw in $dbNWs) {
if (!($vcNWs |?{$_.Key -eq $nw.vkey})) {
if (!$nw.nwid) {
Continue
}
Log ("HIDE dV: " + $nw.name)
ExecuteMySQLNonQuery("UPDATE nw SET exist=0 WHERE nwid=" + $nw.nwid + ";")
ExecuteMySQLNonQuery("DELETE FROM esx2nw WHERE nwid=" + $nw.nwid + ";")
}
}
}
}
# vApps (part 1 of 2 - create vapp) --------------------------------------------------------------------------------------------------------------------
if ($UpdateVApp) {
Log ("Getting vAPPs (phase 1)....")
$vcVApps = Get-VApp
if ($vcVApps) {
# Create base vApp entry
$dbClusters = ExecuteMySQLQuery("SELECT clid, name FROM cluster WHERE vcid = " + $VC_vcid + ";")
foreach ($vApp in $vcVApps) {
$vappvcid = [regex]::replace($vApp.Id, "VirtualApp-resgroup-v", "")
$clid = $dbClusters |?{$_.name -eq (Get-Cluster -Id $vApp.ExtensionData.Owner)} | Select -ExpandProperty clid
$vcpath = [regex]::replace((Get-FolderPath (Get-Folder -Id $vApp.ExtensionData.ParentFolder)), "\\", "\\")
if (!$clid) {
Log-Error ("Couldn't find cluster for vApp: " + $vApp.Name + " in db")
$clid = "NULL"
}
if ($vApp.ExtensionData.VAppConfig.Product[0].Name) {
$prod_name = "'" + $vApp.ExtensionData.VAppConfig.Product[0].Name + "'"
} else {
$prod_name = "NULL"
}
if ($vApp.ExtensionData.VAppConfig.Product[0].Version) {
$prod_ver = "'" + $vApp.ExtensionData.VAppConfig.Product[0].Version + "'"
} else {
$prod_ver = "NULL"
}
if ($vApp.ExtensionData.VAppConfig.Product[0].FullVersion) {
$prod_fver = "'" + $vApp.ExtensionData.VAppConfig.Product[0].FullVersion + "'"
} else {
$prod_fver = "NULL"
}
if ($vApp.ExtensionData.VAppConfig.Product[0].Vendor) {
$prod_vend = "'" + $vApp.ExtensionData.VAppConfig.Product[0].Vendor + "'"
} else {
$prod_vend = "NULL"
}
$query = "INSERT INTO vapp (vcid, vappvcid, clid, name, vc_path, status, exist, prod_name, prod_ver, prod_fver, prod_vend) VALUES ($VC_vcid, $vappvcid, $clid, '" + $vApp.Name + "', '$vcpath', '" + $vApp.Status
$query += "', 1, $prod_name, $prod_ver, $prod_fver, $prod_vend) ON DUPLICATE KEY UPDATE vappvcid=$vappvcid, clid=$clid, vc_path='$vcpath', status='" + $vApp.Status + "', exist=1, prod_name=$prod_name, "
$query += "prod_ver=$prod_ver, prod_fver=$prod_fver, prod_vend=$prod_vend;"
ExecuteMySQLNonQuery($query)
}
# Mark vApps that no longer exist
$dbVApps = ExecuteMySQLQuery("SELECT vappid, name FROM vapp WHERE vcid=$VC_vcid AND exist=1;")
foreach ($vapp in $dbVApps) {
if (!($vcVApps |?{$_.Name -eq $vapp.name})) {
if (!$vapp.vappid) {
Continue
}
Log ("HIDE: " + $vapp.name + " vApp")
ExecuteMySQLNonQuery("UPDATE vapp SET exist=0 WHERE vappid=" + $vapp.vappid + ";")
ExecuteMySQLNonQuery("DELETE FROM vapp_vm WHERE vappid=" + $vapp.vappid + ";")
}
}
} else {
Log ("No vApps found")
}
}
# Virtual Machines --------------------------------------------------------------------------------------------------------------------------
if ($UpdateVM) {
Log ("Getting VMs....")
$vcVMs = Get-VM
$vcClusters = Get-Cluster
$dbClusters = ExecuteMySQLQuery("SELECT clid, name FROM cluster WHERE vcid = " + $VC_vcid + ";")
$dbESXs = ExecuteMySQLQuery("SELECT esxid, name FROM esx WHERE vcid = " + $VC_vcid + " AND exist=1;")
$dbVApps = ExecuteMySQLQuery("SELECT vappid, name FROM vapp WHERE vcid = " + $VC_vcid + " AND exist=1;")
$dbNWs = ExecuteMySQLQuery("SELECT nwid, vkey, name FROM nw WHERE vcid = " + $VC_vcid + " AND exist=1;")
$dbStdNWs = ExecuteMySQLQuery("SELECT nwid, vkey, name FROM nw WHERE vcid = " + $VC_vcid + " AND exist=1 AND is_dv=0;")
$dbDSs = ExecuteMySQLQuery("SELECT dsid, name FROM ds WHERE vcid = " + $VC_vcid + " AND exist=1;")
$dbOSs = ExecuteMySQLQuery("SELECT osid, guest_name FROM os;")
$VyattaVM = @()
# Create cluster lookup hash
Log("Building VM2clid lookup hash...")
$VM2clid = @{}
foreach ($vcCluster in $vcClusters) {
$clid = $dbClusters |?{$_.name -eq $vcCluster.Name} | Select -ExpandProperty clid
$clVMs = Get-VM -Location $vcCluster
foreach ($vm in $clVMs) {
$VM2clid[$vm.Id] = $clid
}
}
Log("...completed")
# Add/update VM's in database
foreach ($vm in $vcVMs) {
# Catch linking failure (prevents SQL query failure, allows script to continue)
$vmvcid = [regex]::replace($vm.Id, "VirtualMachine-vm-", "")
# Version 1 - Takes ages
#$cluster = (Get-Cluster -VM $vm).Name
#$clid = $dbClusters |?{$_.name -eq $cluster} | Select -ExpandProperty clid
# version 2 - Takes about half the time, but still 2+ secs
#$cluster = (Get-View -ID (Get-View -ViewType HostSystem -Filter @{"Name"=$vm.VMHost.Name} -Property Parent).Parent -Property Name).Name
#$clid = $dbClusters |?{$_.name -eq $cluster} | Select -ExpandProperty clid
# Version 3 - Uses pre-built lookup hash
$clid = $VM2clid[$vm.Id]
#$vmGuest = Get-VMGuest -VM $vm
if (!$clid) {
# No cluster found for VM in lookup - check this is OK
$clust = Get-Cluster -VM $vm
if ($clust) {
Log-Error ("Couldn't find cluster for VM: " + $vm.Name + " in db lookup (" + $clust.name + ")")
}
$clid = "NULL"
}
$esxid = $dbESXs |?{$_.name -eq $vm.VMHost.Name.Split(".")[0]} | Select -ExpandProperty esxid
if ($esxid.Count -gt 1) {
Log-Error ("Multiple ESX IDs (" + $esxid + ") found for VM: " + $vm.Name + " in db")
Continue
}
if (!$esxid) {
Log-Error ("Couldn't find ESX " + $vm.VMHost.Name.Split(".")[0] + " for VM: " + $vm.Name + " in db")
Continue
}
if ($vm.PowerState -eq "PoweredOn") {
$on = 1
} else {
$on = 0
}
# Get VM's containing folder and/or vApp info
if (!$vm.FolderId) {
$vApp = Get-VApp -Id $vm.ExtensionData.ParentVApp
$vAppName = $vApp.Name
$vappid = $dbVApps |?{$_.name -eq $vAppName} | Select -ExpandProperty vappid
if (!$vappid) {
Log-Error ("No vApp found for VM: " + $vm.Name + " in db")
$vAppName = ""
$vappid = "NULL"
}
if (!$vApp) {
Log-Error ("No folder Id or vApp specified for VM: " + $vm.Name)
$vmvcpath = ""
} else {
$vmvcpath = [regex]::replace((Get-FolderPath (Get-Folder -Id $vApp.ExtensionData.ParentFolder)), "\\", "\\")
}
} else {
$vmvcpath = [regex]::replace((Get-FolderPath (Get-Folder -Id $vm.FolderId)), "\\", "\\")
$vAppName = ""
$vappid = "NULL"
}
# Update base VM entry
$query = "INSERT INTO vm (uuid, vmvcid, pid, name, exist, is_on, vcid, clid, esxid, vappid, hostname) VALUES ('" + $vm.ExtensionData.Config.Uuid + "', $vmvcid, '" + $vm.PersistentId
$query += "', '" + $vm.Name + "', 1, $on, " + $VC_vcid + ", $clid, $esxid, $vappid, '" + $vm.ExtensionData.Guest.HostName + "') ON DUPLICATE KEY UPDATE vmid=LAST_INSERT_ID(vmid), "
$query += " vmvcid=$vmvcid, name='" + $vm.Name + "', exist=1, is_on=$on, clid=$clid, esxid=$esxid, vappid=$vappid, hostname='" + $vm.ExtensionData.Guest.HostName + "';"
ExecuteMySQLNonQuery($query)
# Get vmid from last query
$vmid = ExecuteMySQLScalar("SELECT LAST_INSERT_ID();")
# Update extended VM entry
$vmxpath = $vm.ExtensionData.Config.Files.VmPathName
$vmtools = $vm.ExtensionData.Guest.ToolsStatus.ToString()
$vmscsi = ($vm.ExtensionData.Config.Hardware.Device | where {$_.DeviceInfo.Label -match "SCSI Controller"}).DeviceInfo.Summary
$vm_ver = [regex]::replace($vm.Version.ToString(), "v", "")
$vmnotes = [regex]::replace($vm.Notes, "(\s?\bvRanger.*Repository \[.*\]\s?)|(\[vRanger.*Host \[.*\]\.\]\s?)", "")
$vmnotes = [regex]::replace($vmnotes, "'", "\'")
$vmnotes = [regex]::replace($vmnotes, "`n", "\\n")
$query = "INSERT INTO vm_ext (vmid, cpu, mem, vapp, vc_path, vmx_path, tools, scsi_hw, vm_ver, notes) VALUES ($vmid, " + $vm.NumCpu + ", " + $vm.MemoryMB + ", '$vAppName"
$query += "', '$vmvcpath" + "', '$vmxpath', '$vmtools', '$vmscsi', '$vm_ver', '$vmnotes') ON DUPLICATE KEY UPDATE cpu=" + $vm.NumCpu + ", mem=" + $vm.MemoryMB + ", vapp='$vAppName"
$query += "', vc_path='$vmvcpath', vmx_path='$vmxpath', tools='$vmtools', scsi_hw='$vmscsi', vm_ver='$vm_ver', notes='$vmnotes';"
ExecuteMySQLNonQuery($query)
$vcNICs = Get-NetworkAdapter -VM $vm #(VI3 doesn't return Network Adapter x info)
#$vcNICs = $vm.Guest.Nics
# Add NICs
foreach ($nic in $vcNICs) {
Clear-Variable nwid
if ($nic.ExtensionData.Backing.Port.PortgroupKey) {
$nwid = $dbNWs |?{$_.vkey -eq $nic.ExtensionData.Backing.Port.PortgroupKey} | Select -ExpandProperty nwid
if (!$nwid) {
Log ($vm.name + " failed to find/match nic network key")
}
}
if (!$nwid) {
Log ($vm.name + " using vnic network name against standard switches")
$nwid = $dbStdNWs |?{$_.name -eq $nic.NetworkName} | Select -ExpandProperty nwid
if (!$nwid) {
if ($nic.extensiondata.Connectable.Status -eq "untried") {
Log ("Ignoring " + $vm.Name + " - " + $nic.Name + " (assumed to be LabManager service VM)")
} else {
Log-Error ("Couldn't find network " + $nic.NetworkName + "(" + $nic.Name + ") for VM: " + $vm.Name + " in db")
}
Continue
}
}
if ($nwid.count -gt 1) {
Log-Error ("Too many network matches for VM: " + $vm.Name + " ($nwid)")
Continue
}
# Replaced in v2.7 with more generic (international) version below
#$nwno = [regex]::replace($nic.Name, "Network (?i:A)dapter ", "")
#if (!([regex]::matches($nwno, "\d").Count)) {
# if ($vm.NetworkAdapters.Count -eq 1) {
# $nwno = 1
# } else {
# Log-Error ("Couldn't get NIC number from " + $nic.Name + " for VM: " + $vm.Name)
# Continue
# }
#}
$res = [regex]::matches($nic.Name, "\d")
if ($res.count -gt 1) {
Log-Error ("Couldn't get NIC number from " + $nic.Name + " for VM: " + $vm.Name + " - too many numbers found")
Continue
} elseif ($res.count -lt 1) {
if ($vm.NetworkAdapters.Count -eq 1) {
$nwno = 1
} else {
Log-Error ("Couldn't get NIC number from " + $nic.Name + " for VM: " + $vm.Name + " - no number found")
Continue
}
} else {
$nwno = $res[0].Value
}
$query = "INSERT INTO vm_nic (vmid, num, nwid, type) VALUES ($vmid, $nwno, $nwid, '" + $nic.Type + "') "
$query += "ON DUPLICATE KEY UPDATE vnicid=LAST_INSERT_ID(vnicid), nwid=$nwid, type='" + $nic.Type + "';"
ExecuteMySQLNonQuery($query)
# Get vnicid from last query
$vnicid = ExecuteMySQLScalar("SELECT LAST_INSERT_ID();")
# Find related IP(s)
try {
# Failsafe - workaround for bug where $ips still populated from previous iteration and doesn't get updated
if ($ips) {
Clear-Variable ips
}
if ($vcinfo.Version -lt 4) {
#if ($vm.Guest.nics[0].NetworkName) {
# Works for VI3 hosted guests
$ips = $vm.Guest.Nics |?{$_.NetworkName -eq $nic.NetworkName} | Select -Property IPAddress
} else {
# Works for VI4 hosted guests
$ips = $vm.Guest.Nics |?{$_.Device.Name -eq $nic.Name} | Select -Property IPAddress
}
if (!$ips) {
Log-Error ("Couldn't match NICs to find IP for VM: " + $vm.Name + " NIC: " + $nic.Name + " in data from VC")
Continue
}
foreach ($ip in $ips.IPAddress) {
if (!$ip) {
Log ("VM: " + $vm.Name + " NIC: " + $nic.Name + " has no IP address in vCentre")
Continue
}
if (!([regex]::matches($ip, "^\b((25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\b"))[0].Success) {
Log ("VM: " + $vm.Name + " NIC: " + $nic.Name + " IP: $ip is not a valid IPv4 address")
Continue
}
if ($ip -eq "0.0.0.0") {
Log ("Ignoring " + $vm.Name + "'s IP of " + $ip)
Continue
}
$query = "INSERT INTO vm2ip (vmid, vnicid, ip) VALUES ($vmid, $vnicid, INET_ATON('$ip')) "
$query += "ON DUPLICATE KEY UPDATE ip=INET_ATON('$ip');"
ExecuteMySQLNonQuery($query)
}
} catch {
Log-Error("Unexpected error when trying to match NICs to find IP for VM: " + $vm.Name + " NIC: " + $nic.Name + " [" + $_.Exception.Message + "]")
}
}
# Remove old NICs
$dbNICs = ExecuteMySQLQuery("SELECT vnicid, num FROM vm_nic WHERE vmid=$vmid;")
foreach ($nic in $dbNICs) {
if (!$nic.vnicid) {
Continue
}
# Catch where num of NIC's is 1 (regex fails as NIC is called "Virtual Ethernet Adapter"
if (($vcNICs -and !$vcNICs.count) -and ($dbNICs.count -eq 2)) {
Log ("VM: " + $vm.Name + " NIC count of one matches db and vc (workaround)")
Continue
}
#if (!($vcNICs |?{[regex]::replace($_.Name, "Network (?i:A)dapter ", "") -eq $nic.num})) {
if (!($vcNICs |?{([regex]::matches($_.Name, "\d"))[0].Value -eq $nic.num})) {
Log ("DELETE: " + $vm.name + " NIC num " + $nic.num)
ExecuteMySQLNonQuery("DELETE FROM vm_nic WHERE vnicid=" + $nic.vnicid + ";")
ExecuteMySQLNonQuery("DELETE FROM vm2ip WHERE vnicid=" + $nic.vnicid + ";")
}
}
# Add VMDK record(s)
foreach ($vmdk in $vm.HardDisks) {
# Create VMDK record
$dsid = $dbDSs |?{$_.name -eq (([regex]::matches($vmdk.Filename, "(?<=\[)(.*?)(?=\])")).Item(0).Value)} | Select -ExpandProperty dsid
if (!$dsid) {
Log-Error ("Couldn't find datastore " + (([regex]::matches($vmdk.Filename, "(?<=\[)(.*?)(?=\])")).Item(0).Value) + " for VM: " + $vm.Name + " in db")
Continue
}
#$dkno = [regex]::replace($vmdk.Name, "Hard (?i:D)isk ", "")
$dkno = ([regex]::matches($vmdk.Name, "\d"))[0].Value
$dksize = [math]::Round(($vmdk.CapacityKB / 1024), 0)
if ($vmdk.StorageFormat -eq "Thin") {
$dkthin = 1
} else {
$dkthin = 0
}
if ($vmdk.DiskType -match "Raw") {
$dkrdm = 1
} else {
$dkrdm = 0
}
$query = "INSERT INTO vmdk (dsid, vmid, num, size, thin, rdm, path) VALUES ($dsid, $vmid, $dkno, $dksize, $dkthin, $dkrdm"
$query += ", '" + $vmdk.Filename + "') ON DUPLICATE KEY UPDATE dsid=$dsid, size=$dksize, thin=$dkthin, rdm=$dkrdm, path='" + $vmdk.Filename + "';"
ExecuteMySQLNonQuery($query)
}
# Remove old VMDK's
$dbVMDKs = ExecuteMySQLQuery("SELECT dkid, num FROM vmdk WHERE vmid=$vmid;")
foreach ($vmdk in $dbVMDKs) {
#if (!($vm.HardDisks |?{[regex]::replace($_.Name, "Hard (?i:D)isk ", "") -eq $vmdk.num})) {
if (!($vm.HardDisks |?{([regex]::matches($_.Name, "\d"))[0].value -eq $vmdk.num})) {
if (!$vmdk.dkid) {
Continue
}
Log ("DELETE: " + $vm.name + " VMDK num " + $vmdk.num)
ExecuteMySQLNonQuery("DELETE FROM vmdk WHERE dkid=" + $vmdk.dkid + ";")
}
}
# Work out OSID if VM is up
if ($vm.PowerState -eq "PoweredOn") {
#$osname = (Get-VMGuest -VM $vm).OSFullName
$osname = $vm.ExtensionData.Config.GuestFullName
if (!$osname) {
Log-Error ("Couldn't update OS for VM: " + $vm.Name + " in db")
Continue
}
$osid = $dbOSs |?{$_.guest_name -eq $osname} | Select -ExpandProperty osid
if (!$osid) {
# No existing db record for OS, add a new one
ExecuteMySQLNonQuery("INSERT INTO os (guest_name) VALUES ('$osname');")
$osid = ExecuteMySQLScalar("SELECT LAST_INSERT_ID();")
$dbOSs = ExecuteMySQLQuery("SELECT osid, guest_name FROM os;")
}
ExecuteMySQLNonQuery("UPDATE vm_ext SET osid=$osid WHERE vmid=$vmid;")
}
# Get VM's resource settings
$query = "INSERT INTO vm_res (vmid, cpu_resrv, cpu_limit, cpu_level, cpu_shares, mem_resrv, mem_limit, mem_level, mem_shares) VALUES ($vmid,"
$query += " " + $vm.ExtensionData.ResourceConfig.CpuAllocation.Reservation + ", " + $vm.ExtensionData.ResourceConfig.CpuAllocation.Limit
$query += ", '" + $vm.ExtensionData.ResourceConfig.CpuAllocation.Shares.Level + "', " + $vm.ExtensionData.ResourceConfig.CpuAllocation.Shares.Shares
$query += ", " + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Reservation + ", " + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Limit
$query += ", '" + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Shares.Level + "', " + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Shares.Shares
$query += ") ON DUPLICATE KEY UPDATE "
$query += "cpu_resrv=" + $vm.ExtensionData.ResourceConfig.CpuAllocation.Reservation + ", cpu_limit=" + $vm.ExtensionData.ResourceConfig.CpuAllocation.Limit + ", "
$query += "cpu_level='" + $vm.ExtensionData.ResourceConfig.CpuAllocation.Shares.Level + "', cpu_shares=" + $vm.ExtensionData.ResourceConfig.CpuAllocation.Shares.Shares + ", "
$query += "mem_resrv=" + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Reservation + ", mem_limit=" + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Limit + ", "
$query += "mem_level='" + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Shares.Level + "', mem_shares=" + $vm.ExtensionData.ResourceConfig.MemoryAllocation.Shares.Shares + ";"
ExecuteMySQLNonQuery($query)
# Get VM's custom attributes
$Attribs = Get-Annotation -Entity $vm
foreach ($attrib in $Attribs) {
if ($attrib.Value.Length) {
ExecuteMySQLNonQuery("INSERT into vm_attrib (vmid, name, data) VALUES ($vmid, '" + $attrib.Name + "', '" + $attrib.Value + "') ON DUPLICATE KEY UPDATE data='" + $attrib.Value + "';")
} else {
ExecuteMySQLNonQuery("INSERT into vm_attrib (vmid, name, data) VALUES ($vmid, '" + $attrib.Name + "', NULL) ON DUPLICATE KEY UPDATE data=NULL;")
}
}
# Detect if VM is Vyatta router
if ($vm.ExtensionData.Guest.Disk | Where {$_.DiskPath -eq "/opt/vyatta/etc/config"}) {
if ($vm.PowerState -ne "PoweredOn") {
Log("NAT router: " + $router.Name + " not powered on, skipping")
} else {
$router = "" | Select Name, Net1addr, Net1id, Net1name, Net2id, Net2name
$router.Name = $vm.Name
$RoNics = ExecuteMySQLQuery("SELECT num, nw.nwid, nw.name, CONVERT(INET_NTOA(MIN(ip)), CHAR) AS ip FROM vm_nic JOIN nw USING (nwid) JOIN vm2ip USING (vnicid) where vm_nic.vmid=$vmid GROUP BY num;")
foreach ($nic in $RoNics) {
if ($nic.num -eq 1) {
$router.Net1addr = $nic.ip
$router.Net1id = $nic.nwid
$router.Net1name = $nic.name
} elseif ($nic.num -eq 2) {
$router.Net2id = $nic.nwid
$router.Net2name = $nic.name
}
}
Log("NAT router: " + $router.Name + " (" + $router.Net1addr + ") [" + $router.Net1id + "] " + $router.Net1name + " -> [" + $router.Net2id + "] " + $router.Net2name)
$VyattaVM += $router
}
}
}
# Mark VM's that no longer exist
Log("Checking for VM's that no longer exist")
$dbVMs = ExecuteMySQLQuery("SELECT vmid, uuid, pid, vmvcid, name FROM vm WHERE vcid = " + $VC_vcid + " AND exist=1;")
foreach ($vm in $dbVMs) {
if ($vcVMs |?{($_.ExtensionData.Config.Uuid -eq $vm.uuid) -and ($_.PersistentId -eq $vm.pid)}) {
#Log ("Found " + $vm.vmid + " - " + $vm.name + " (" + $vm.uuid + ")")
} else {
if (!$vm.vmid) {
Continue
}
Log ("HIDE: " + $vm.vmid + " - " + $vm.name + " (UUID: " + $vm.uuid + " PersistID: " + $vm.pid + ")")
ExecuteMySQLNonQuery("UPDATE vm SET exist=0 WHERE vmid=" + $vm.vmid + ";")
}
}
# Snapshots - add/update, then remove old
Log ("Get snapshots from VC...")
#$vcSnaps = $vcVMs | Get-Snapshot <--- Get-Snapshot doesn't return accurate MB used info
# CalculateVMSnapshotsSizeMB returns property VirtualMachineID, Get-Snapshot returns VMId (swap below when reverting to Get-Snapshot)
$vcSnaps = @()
foreach ($vm in $vcVMs) {
$Snaps = CalculateVMSnapshotsSizeMB -VM $vm
if ($Snaps) {
$vcSnaps = $vcSnaps + $Snaps
}
}
if (!$vcSnaps) {
Log ("No snapshots found, removing any for this VC in db")
ExecuteMySQLNonQuery("DELETE FROM snap WHERE vcid=" + $VC_vcid + ";")
} else {
foreach ($snap in $vcSnaps) {
# Create/update entry (must convert size into integer)
$sid = [regex]::replace($snap.Id, "VirtualMachineSnapshot-snapshot-", "")
if (!$snap.ParentSnapshotId) {
$psid = "NULL"
} else {
$psid = [regex]::replace($snap.ParentSnapshotId, "VirtualMachineSnapshot-snapshot-", "")
}
$vmid = $dbVMs |?{$_.vmvcid -eq [regex]::replace($snap.VirtualMachineID, "VirtualMachine-vm-", "")} | Select -ExpandProperty vmid
if (!$vmid) {
Log-Error ("Couldn't find vmid for snapshot (" + $snap.Id + ", " + $snap.VirtualMachineID+ ")")
Continue
}
if (!$snap.Quiesced) { # Not returned by CalculateVMSnapshotsSizeMB
$quiesced = "NULL"
} else {
if ($snap.Quiesced -eq "True") {
$quiesced = 1
} else {
$quiesced = 0
}
}
if (!$snap.Created) { # CalculateVMSnapshotsSizeMB returns CreateTime not Created
$created = $snap.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
} else {
$created = $snap.Created.ToString("yyyy-MM-dd HH:mm:ss")
}
if ($snap.PowerState -eq "PoweredOn") {
$on = 1
} else {
$on = 1
}
if ($snap.Name.Contains("Created by vRanger")) {
$vrange = 1
} else {
$vrange = 0
}
$query = "INSERT into snap (vmid, sid, vcid, name, descr, created, quiesced, vrange, vm_on, size, parent_sid) VALUES ($vmid, $sid, " + $VC_vcid + ", '" + (EscQuote $snap.Name)
$query += "', '" + (EscQuote $snap.Description) + "', '$created', $quiesced, $vrange, $on, " + [math]::Round($snap.SizeMB, 0)
$query += ", $psid) ON DUPLICATE KEY UPDATE name='" + (EscQuote $snap.Name) + "', descr='" + (EscQuote $snap.Description) + "', size=" + [math]::Round($snap.SizeMB, 0) + ";"
ExecuteMySQLNonQuery($query)
}
# Remove old snapshots
$dbSnaps = ExecuteMySQLQuery("SELECT sid FROM snap WHERE vcid=" + $VC_vcid + ";")
foreach ($snap in $dbSnaps) {
if (!$snap.sid) {
Continue
}
if (!($vcSnaps |?{$_.Id -eq ("VirtualMachineSnapshot-snapshot-" + $snap.sid)})) {
Log ("REMOVE: VirtualMachineSnapshot-snapshot-" + $snap.sid)
ExecuteMySQLNonQuery("DELETE FROM snap WHERE sid=" + $snap.sid + " AND vcid= " + $VC_vcid + ";")
}
}
}
}
# vApps (part 2 of 2 - update VMs) -------------------------------------------------------------------------------------------------------------------------------
if ($UpdateVApp) {
Log ("Getting vAPPs (phase 2)....")
if ($vcVApps) {
# Create base vApp entry
$dbClusters = ExecuteMySQLQuery("SELECT clid, name FROM cluster WHERE vcid = " + $VC_vcid + ";")
foreach ($vApp in $vcVApps) {
$vappvcid = [regex]::replace($vApp.Id, "VirtualApp-resgroup-v", "")
$vappid = ExecuteMySQLScalar("SELECT vappid FROM vapp WHERE vappvcid=$vappvcid AND vcid=$VC_vcid;")
# Update vApp VM list
if ($vApp.ExtensionData.VAppConfig.EntityConfig) {
foreach ($vappvm in $vApp.ExtensionData.VAppConfig.EntityConfig) {
$vmvcid = [regex]::replace($vappvm.Key.ToString(), "VirtualMachine-vm-", "")
$vmid = ExecuteMySQLScalar("SELECT vmid FROM vm WHERE vcid=$VC_vcid AND vmvcid=$vmvcid;")
if (!$vmid) {
Log-Error("Failed to get vmid for " + $vappvm.Tag + " in vApp " + $vApp.Name)
Continue
}
$query = "INSERT INTO vapp_vm (vappid, vmid, vmvcid, ord, start_dly, start_wait, stop_dly, stop_act) VALUES ($vappid, $vmid, $vmvcid, " + $vappvm.StartOrder + ", " + $vappvm.StartDelay
$query += ", " + $vappvm.WaitingForGuest.GetHashCode() + ", " + $vappvm.StopDelay + ", '" + $vappvm.StopAction + "') ON DUPLICATE KEY UPDATE vmvcid=$vmvcid, ord=" + $vappvm.StartOrder
$query += ", start_dly=" + $vappvm.StartDelay + ", start_wait=" + $vappvm.WaitingForGuest.GetHashCode() +", stop_dly=" + $vappvm.StopDelay + ", stop_act='" + $vappvm.StopAction + "';"
ExecuteMySQLNonQuery($query)
}
}
# Remove VMs on longer in vApp
$dbVAppsVMs = ExecuteMySQLQuery("SELECT vmid, vmvcid FROM vapp_vm WHERE vappid=$vappid;")
foreach ($vappvm in $dbVAppsVMs) {
if (!($vApp.ExtensionData.VAppConfig.EntityConfig |?{[regex]::replace($_.Key.ToString(), "VirtualMachine-vm-", "") -eq $vappvm.vmvcid})) {
if (!$vappvm.vmid) {
Continue
}
Log ("DELETE: vmid " + $vappvm.vmid + " from vApp " + $vapp.name)
ExecuteMySQLNonQuery("DELETE FROM vapp_vm WHERE vmid=" + $vappvm.vmid + " AND vappid=$vappid;")
}
}
}
# Mark vApps that no longer exist
$dbVApps = ExecuteMySQLQuery("SELECT vappid, name FROM vapp WHERE vcid=$VC_vcid AND exist=1;")
foreach ($vapp in $dbVApps) {
if (!($vcVApps |?{$_.Name -eq $vapp.name})) {
if (!$vapp.vappid) {
Continue
}
Log ("HIDE: " + $vapp.name + " vApp")
ExecuteMySQLNonQuery("UPDATE vapp SET exist=0 WHERE vappid=" + $vapp.vappid + ";")
ExecuteMySQLNonQuery("DELETE FROM vapp_vm WHERE vappid=" + $vapp.vappid + ";")
}
}
}
}
# Vyatta NATs ---------------------------------------------------------------------------------------------------------------------------------
if ($UpdateVyNAT) {
if ($VyattaVM) {
# Load SSH library
. .\lib\Renci-SSH-v1.ps1
# $router = "" | Select Name, Net1addr, Net1id, Net1name, Net2id, Net2name
foreach ($router in $VyattaVM) {
Log("Get NATs from " + $router.Name + "...")
# Connect to router and get NAT rules
try {
$SshClient = New-SshSession -server $router.Net1addr -user $VyattaUser -pass $VyattaPass
$SshCommand = New-SshCommand -SshClient $SshClient -Command "exec vbash -i -c 'show nat rules'"
$NatText = $SshCommand.Result.Split("`n")
$SshCommand.Dispose()
$SshClient.Disconnect()
$SshClient.Dispose()
} catch {
Log-Error("SSH fail " + $router.Name + ": " + $_)
Continue
}
# Extract NATs from returned data
$nats = @()
foreach ($line in $NatText) {
if (!$line.length) {
Continue
}
#Write-Host ("Parsing line [$line]")
$text = ([regex]::matches($line, "^\d{2,4}\s+(SRC|DST)\s+eth\d\s+(s|d)addr\s\b((25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\b\sto\s\b((25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)\b"))[0].Value
$text = [regex]::replace($text, "\s{2,}", " ")
if ($text.length) {
$nat = "" | Select RealIP, NatIP
$words = $text.split(" ")
if ($words[1] -eq "DST") {
$nat.RealIP = $words[6]
$nat.NatIP = $words[4]
} elseif ($words[1] -eq "SRC") {
$nat.RealIP = $words[4]
$nat.NatIP = $words[6]
} else {
#Write-Host "Ignored invalid line [$text]"
Continue
}
#Write-Host ("Adding " + $nat.RealIP + " - " + $nat.NatIP)
$nats += $nat
}
}
$nats = $nats | Sort-Object -Property RealIP -Unique
# Get list of VM's on router's inside network
$query = "SELECT vm_nic.vmid, CONVERT(INET_NTOA(MIN(ip)), CHAR) AS ip FROM vm_nic JOIN vm USING (vmid) JOIN vm2ip USING (vnicid) WHERE nwid=" + $router.Net2id + " AND exist=1 GROUP BY vmid;"
$InsideVMs = ExecuteMySQLQuery($query)
# Match up NATs with VMs and add translated address to db
foreach ($nat in $nats) {
$NATedVmid = $InsideVMs |?{$_.ip -eq $nat.RealIP} | Select -ExpandProperty vmid
if (!$NATedVmid) {
Log ("No VM found for NAT " + $nat.RealIP + " -> " + $nat.NatIP)
Continue
}
if ($NATedVmid.length -gt 1) {
Log-Error ("Too many VM's found for NAT " + $nat.RealIP + " -> " + $nat.NatIP + ", VMID's $NATedVmid")
Continue
}
# Create dummy VM NIC
ExecuteMySQLNonQuery("INSERT INTO vm_nic (vmid, num, nwid, type) VALUES ($NATedVmid, 0, " + $router.Net1id + ", 'Vyatta NAT') ON DUPLICATE KEY UPDATE nwid=" + $router.Net1id + ", vnicid=LAST_INSERT_ID(vnicid);")
# Get vnicid from last query
$vnicid = ExecuteMySQLScalar("SELECT LAST_INSERT_ID();")
$query = "INSERT INTO vm2ip (vmid, vnicid, ip) VALUES ($NATedVmid, $vnicid, INET_ATON('" + $nat.NatIP + "')) "
$query += "ON DUPLICATE KEY UPDATE ip=INET_ATON('" + $nat.NatIP + "');"
ExecuteMySQLNonQuery($query)
}
}
} else {
Log("No Vyatta VM's found to process for NATs")
}
}
# Sanity checks -------------------------------------------------------------------------------------------------------------------------------
Log ("Perfoming sanity checks for " + $VC_name)
$SanityOK = 1
if ($UpdateCL) {
$dbCLs = ExecuteMySQLScalar("SELECT COUNT(*) AS total FROM cluster WHERE vcid=" + $VC_vcid + " AND exist=1;")
if ($vcClusters -and -not $vcClusters.Count) {
$vcClusterCount = 1
} else {
$vcClusterCount = $vcClusters.Count
}
if ($dbCLs -ne $vcClusterCount) {
Log-Error("Sanity check fail " + $VC_name + " - inconsistent number of Clusters [VC: " + $vcClusterCount + " DB: " + $dbCLs + "]")
$SanityOK = 0
}
}
if ($UpdateESX) {
$dbESXs = ExecuteMySQLScalar("SELECT COUNT(*) AS total FROM esx WHERE vcid=" + $VC_vcid + " AND exist=1;")
if ($dbESXs -ne $vcESXs.Count) {
Log-Error("Sanity check fail " + $VC_name + " - inconsistent number of ESXs [VC: " + $vcESXs.Count + " DB: " + $dbESXs + "]")
$SanityOK = 0
}
}
if ($UpdateVM) {
$dbVMs = ExecuteMySQLQuery("SELECT COUNT(*) AS total, SUM(IF(is_on=1,1,0)) AS is_on FROM vm WHERE vcid=" + $VC_vcid + " AND exist=1;")
if ($dbVMs[1].total -ne $vcVMs.Count) {
Log-Error("Sanity check fail " + $VC_name + " - inconsistent number of VMs [VC: " + $vcVMs.Count + " DB: " + $dbVMs[1].total + "]")
$SanityOK = 0
}
if ($dbVMs[1].is_on -ne ($vcVMs | Where {$_.PowerState -eq "PoweredOn"}).Count) {
Log-Error("Sanity check fail " + $VC_name + " - inconsistent number of powered on VMs [VC: " + ($vcVMs | Where {$_.PowerState -eq "PoweredOn"}).Count + " DB: " + $dbVMs[1].is_on + "]")
$SanityOK = 0
}
}
if ($SanityOK) {
Log ("Sanity checks completed, no errors found")
} else {
Log-Error -text ("Sanity check problems found with data for " + $VC_name) -sev 2
}
# Add finished record to db so parent script knows all completed (didn't bomb out)
Log-Error -text ($VC_name + " - completed") -sev 0
if ($UpdateScriptRun) {
# Update VC info
ExecuteMySQLNonQuery("UPDATE vc SET ver='" + $vcinfo.Version + "', build=" + $vcinfo.Build + ", last_pass=NOW() WHERE vcid=$VC_vcid;")
}
Log("Diconnecting from " + $VC_name)
Disconnect-VIServer -Server $VCconn -Confirm:$false
Log("Disconnecting from database")
DisconnectMySQL
Log("Elvis has left the building")