Nola eraiki PowerCLI scriptetarako suziri bultzatzailea 

Lehenago edo beranduago, edozein VMware sistemaren administratzaile ohiko zereginak automatizatzera dator. Dena komando-lerroarekin hasten da, gero PowerShell edo VMware PowerCLI dator.

Demagun PowerShell ISE abiarazi eta "magia motaren batengatik" funtzionatzen duten moduluetako cmdlet estandarrak erabiliz baino pixka bat gehiago menderatzen duzula. Makina birtualak ehunka zenbatzen hasten zarenean, eskala txikian laguntzen duten script-ak eskala handian nabarmen mantsoago ibiltzen direla ikusiko duzu. 

Egoera honetan, 2 tresnak lagunduko dizute:

  • PowerShell Runspaces – prozesuen exekuzioa hari bereizietan paralelizatzeko aukera ematen duen ikuspegia; 
  • Lortu-Ikusi – oinarrizko PowerCLI funtzio bat, Windows-en Get-WMIObject-en analogoa. Cmdlet honek ez ditu entitateekin batera datozen objektuak ateratzen, baina datu-mota sinpleak dituen objektu sinple baten moduan jasotzen du informazioa. Kasu askotan azkarrago ateratzen da.

Jarraian, tresna bakoitzari buruz laburki hitz egingo dut eta erabilera-adibideak erakutsiko ditut. Azter ditzagun gidoi zehatzak eta ea noiz funtzionatzen duen batak bestea baino hobeto. Joan!

Nola eraiki PowerCLI scriptetarako suziri bultzatzailea

Lehen fasea: Runspace

Beraz, Runspace modulu nagusitik kanpoko zereginak paraleloki prozesatzeko diseinatuta dago. Jakina, memoria, prozesadorea, etab apur bat jango duen beste prozesu bat abiarazi dezakezu. Zure script-a minutu pare batean exekutatzen bada eta gigabyte memoria kontsumitzen badu, ziurrenik ez duzu Runspace beharko. Baina milaka objekturen gidoietarako beharrezkoa da.

Hemen has zaitezke ikasten: 
PowerShell Runspaces erabiltzen hastea: 1. zatia

Zer ematen du Runspace erabiltzeak:

  • abiadura exekutatutako komandoen zerrenda mugatuz,
  • zereginen exekuzio paraleloa,
  • segurtasuna.

Hona hemen Interneteko adibide bat Runspace-k laguntzen duenean:

"Biltegiratze gatazka vSphere-n jarraitzeko neurketa zailenetako bat da. vCenter-en barruan, ezin duzu ikusi zein VM biltegiratze baliabide gehiago kontsumitzen duen. Zorionez, datu hauek minutu gutxitan bil ditzakezu PowerShell-i esker.
VMware sistema-administratzaileei vCenter-en zehar azkar bilatzeko eta beren batez besteko kontsumoari buruzko datuak dituzten VM zerrenda bat jasotzeko aukera emango dien script bat partekatuko dut.  
Script-ak PowerShell exekuzio-espazioak erabiltzen ditu ESXi ostalari bakoitzak bere VM-etatik kontsumo-informazioa biltzeko aukera emateko, exekuzio-espazio bereizi batean eta berehala amaitutakoaren berri emateko. Horri esker, PowerShelli lanak berehala ixteko aukera ematen du, ostalariak errepikatu eta bakoitzak bere eskaera bete arte itxaron beharrean".

Iturria: Nola erakutsi Makina Birtuala I/O ESXi Arbel batean

Beheko kasuan, Runspace jada ez da erabilgarria:

β€œMakila virtual batetik datu asko biltzen dituen eta beharrezkoa denean datu berriak idazten dituen script bat idazten saiatzen ari naiz. Arazoa da VM dezente daudela eta 5-8 segundo pasatzen direla makina batean". 

Iturria: Multithreading PowerCLI RunspacePool-ekin

Hemen Get-View beharko duzu, joan gaitezen. 

Bigarren etapa: Get-View

Get-View zergatik den erabilgarria ulertzeko, komeni da cmdlet-ek orokorrean nola funtzionatzen duten gogoratzea. 

Cmdlet-ak behar dira informazioa eroso lortzeko APIko erreferentzia liburuak aztertu eta hurrengo gurpila berrasmatu beharrik gabe. Antzina ehun edo bi kode lerro hartzen zituena, PowerShell-ek komando batekin egiteko aukera ematen du. Erosotasun hori abiadurarekin ordaintzen dugu. Cmdlet-en barruan ez dago magiarik: gidoi bera, baina maila baxuagoan, India eguzkitsuko maisu baten esku trebeek idatzia.

Orain, Get-View-rekin alderatzeko, har dezagun Get-VM cmdlet-a: makina birtualera sartzen da eta objektu konposatu bat itzultzen du, hau da, hari lotutako beste objektu batzuk eransten dizkio: VMHost, Datastore, etab.  

Get-View bere lekuan ez dio alferrikako ezer gehitzen itzulitako objektuari. Gainera, zer informazio behar dugun zorrotz zehaztea ahalbidetzen digu, eta horrek irteerako objektua erraztuko du. Windows Server-en orokorrean eta Hyper-V-en bereziki, Get-WMIObject cmdlet-a analogo zuzena da - ideia berdina da.

Get-View deserosoa da puntu-objektuetan ohiko eragiketak egiteko. Baina milaka eta dozenaka milaka objekturi dagokionez, ez du preziorik.

Gehiago irakur dezakezu VMware blogean: Get-View-ren sarrera

Orain dena erakutsiko dizut benetako kasu bat erabiliz. 

VM bat deskargatzeko script bat idazten

Egun batean nire lankideak bere gidoia optimizatzeko eskatu zidan. Zeregin ohiko errutina da: aurkitu cloud.uuid parametro bikoiztua duten VM guztiak (bai, hori posible da VM bat vCloud Director-en klonatzean). 

Burura datorkidan irtenbide argia hau da:

  1. Lortu VM guztien zerrenda.
  2. Aztertu zerrenda nolabait.

Jatorrizko bertsioa script sinple hau zen:

function Get-CloudUUID1 {
   # ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ список всСх Π’Πœ
   $vms = Get-VM
   $report = @()

   # ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, получая ΠΈΠ· Π½Π΅Π³ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ 2 свойства: Имя Π’Πœ ΠΈ Cloud UUID.
   # Заносим Π΄Π°Π½Π½Ρ‹Π΅ Π² Π½ΠΎΠ²Ρ‹ΠΉ PS-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с полями VM ΠΈ UUID
   foreach ($vm in $vms)
   {
       $table = "" | select VM,UUID

       $table.VM = $vm.name
       $table.UUID = ($vm | Get-AdvancedSetting -Name cloud.uuid).Value
          
       $report += $table
   }
# Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ всС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹
   $report
}
# Π”Π°Π»Π΅Π΅ РУКАМИ парсим ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚

Dena oso sinplea eta argia da. Minutu pare batean idatz daiteke kafe atsedenarekin. Iragazkia torlojua eta listo.

Baina neur dezagun denbora:

Nola eraiki PowerCLI scriptetarako suziri bultzatzailea

Nola eraiki PowerCLI scriptetarako suziri bultzatzailea

2 minutu 47 segundo ia 10k VM prozesatzen dituzunean. Hobari bat iragazkirik eza eta emaitzak eskuz ordenatu beharra da. Jakina, gidoiak optimizazioa eskatzen du.

Runspaces dira erreskatera etortzen diren lehenak, aldi berean vCenter-en ostalari-neurriak lortu behar dituzunean edo dozenaka mila objektu prozesatu behar dituzunean. Ikus dezagun zer ekartzen duen planteamendu honek.

Aktibatu lehen abiadura: PowerShell Runspaces

Script honetarako burura etortzen zaion lehenengo gauza begizta ez sekuentzialki exekutatu da, hari paraleloetan baizik, datu guztiak objektu bakarrean bildu eta iragazi. 

Baina arazo bat dago: PowerCLI-k ez digu utziko vCenter saio independente asko irekitzen eta errore dibertigarri bat botako du:

You have modified the global:DefaultVIServer and global:DefaultVIServers system variables. This is not allowed. Please reset them to $null and reconnect to the vSphere server.

Hori konpontzeko, lehenik eta behin saioaren informazioa korrontearen barruan pasatu behar duzu. Gogora dezagun PowerShell-ek funtzio bati edo ScriptBlock batera parametro gisa pasa daitezkeen objektuekin funtzionatzen duela. Pasa dezagun saioa halako objektu baten moduan, $global:DefaultVIServers saihestuz (Konektatu-VIServer -NotDefault gakoarekin):

$ConnectionString = @()
foreach ($vCenter in $vCenters)
   {
       try {
           $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -AllLinked -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
       }
       catch {
           if ($er.Message -like "*not part of a linked mode*")
           {
               try {
                   $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
               }
               catch {
                   throw $_
               }
              
           }
           else {
               throw $_
           }
       }
   }

Orain inplementatu dezagun multithreading Runspace Pools bidez.  

Algoritmoa hau da:

  1. VM guztien zerrenda jasoko dugu.
  2. Korronte paraleloetan cloud.uuid lortzen dugu.
  3. Korronteetako datuak objektu bakarrean biltzen ditugu.
  4. Objektua iragazten dugu CloudUUID eremuaren balioaren arabera taldekatuz: balio esklusiboen kopurua 1 baino handiagoa den horiek bilatzen ari garen VM-ak dira.

Ondorioz, gidoia lortuko dugu:


function Get-VMCloudUUID {
   param (
       [string[]]
       [ValidateNotNullOrEmpty()]
       $vCenters = @(),
       [int]$MaxThreads,
       [System.Management.Automation.PSCredential]
       [System.Management.Automation.Credential()]
       $Credential
   )

   $ConnectionString = @()

   # Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с сСссионным ΠΊΠ»ΡŽΡ‡ΠΎΠΌ
   foreach ($vCenter in $vCenters)
   {
       try {
           $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -AllLinked -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
       }
       catch {
           if ($er.Message -like "*not part of a linked mode*")
           {
               try {
                   $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
               }
               catch {
                   throw $_
               }
              
           }
           else {
               throw $_
           }
       }
   }

   # ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ список всСх Π’Πœ
   $Global:AllVMs = Get-VM -Server $ConnectionString

   # ΠŸΠΎΠ΅Ρ…Π°Π»ΠΈ!
   $ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
   $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host)
   $RunspacePool.ApartmentState = "MTA"
   $RunspacePool.Open()
   $Jobs = @()

# ScriptBlock с магиСй!)))
# ИмСнно ΠΎΠ½ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ Π² ΠΏΠΎΡ‚ΠΎΠΊΠ΅
   $scriptblock = {
       Param (
       $ConnectionString,
       $VM
       )

       $Data = $VM | Get-AdvancedSetting -Name Cloud.uuid -Server $ConnectionString | Select-Object @{N="VMName";E={$_.Entity.Name}},@{N="CloudUUID";E={$_.Value}},@{N="PowerState";E={$_.Entity.PowerState}}

       return $Data
   }
# Π“Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠΈ

   foreach($VM in $AllVMs)
   {
       $PowershellThread = [PowerShell]::Create()
# ДобавляСм скрипт
       $null = $PowershellThread.AddScript($scriptblock)
# И ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΄ΠΈΠΌ Π² качСствС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² скрипту
       $null = $PowershellThread.AddArgument($ConnectionString)
       $null = $PowershellThread.AddArgument($VM)
       $PowershellThread.RunspacePool = $RunspacePool
       $Handle = $PowershellThread.BeginInvoke()
       $Job = "" | Select-Object Handle, Thread, object
       $Job.Handle = $Handle
       $Job.Thread = $PowershellThread
       $Job.Object = $VM.ToString()
       $Jobs += $Job
   }

# Π‘Ρ‚Π°Π²ΠΈΠΌ градусник, Ρ‡Ρ‚ΠΎΠ±Ρ‹ наглядно ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΠΉ
# И здСсь ΠΆΠ΅ ΠΏΡ€ΠΈΠ±ΠΈΠ²Π°Π΅ΠΌ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π²ΡˆΠΈΠ΅ задания
   While (@($Jobs | Where-Object {$_.Handle -ne $Null}).count -gt 0)
   {
       $Remaining = "$($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).object)"

       If ($Remaining.Length -gt 60) {
           $Remaining = $Remaining.Substring(0,60) + "..."
       }

       Write-Progress -Activity "Waiting for Jobs - $($MaxThreads - $($RunspacePool.GetAvailableRunspaces())) of $MaxThreads threads running" -PercentComplete (($Jobs.count - $($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).count)) / $Jobs.Count * 100) -Status "$(@($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False})).count) remaining - $remaining"

       ForEach ($Job in $($Jobs | Where-Object {$_.Handle.IsCompleted -eq $True})){
           $Job.Thread.EndInvoke($Job.Handle)     
           $Job.Thread.Dispose()
           $Job.Thread = $Null
           $Job.Handle = $Null
       }
   }

   $RunspacePool.Close() | Out-Null
   $RunspacePool.Dispose() | Out-Null
}


function Get-CloudUUID2
{
   [CmdletBinding()]
   param(
   [string[]]
   [ValidateNotNullOrEmpty()]
   $vCenters = @(),
   [int]$MaxThreads = 50,
   [System.Management.Automation.PSCredential]
   [System.Management.Automation.Credential()]
   $Credential)

   if(!$Credential)
   {
       $Credential = Get-Credential -Message "Please enter vCenter credentials."
   }

   # Π’Ρ‹Π·ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Get-VMCloudUUID, Π³Π΄Π΅ ΠΌΡ‹ распараллСливаСм ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ
   $AllCloudVMs = Get-VMCloudUUID -vCenters $vCenters -MaxThreads $MaxThreads -Credential $Credential
   $Result = $AllCloudVMs | Sort-Object Value | Group-Object -Property CloudUUID | Where-Object -FilterScript {$_.Count -gt 1} | Select-Object -ExpandProperty Group
   $Result
}

Script honen edertasuna antzeko beste kasu batzuetan erabil daitekeela da, ScriptBlock eta korrontera pasatuko diren parametroak ordezkatuz. Ustiatu ezazu!

Denbora neurtzen dugu:

Nola eraiki PowerCLI scriptetarako suziri bultzatzailea

55 segundo. Hobe da, baina oraindik azkarragoa izan daiteke. 

Joan gaitezen bigarren abiadurara: GetView

Jakin dezagun zer dagoen gaizki.
Lehenik eta behin, Get-VM cmdlet-ak denbora asko behar du exekutatzeko.
Bigarrenik, Get-AdvancedOptions cmdlet-ak are gehiago behar du osatzeko.
Lehenik eta behin bigarrenari aurre egin diezaiogun. 

Get-AdvancedOptions erosoa da VM objektu indibidualentzat, baina oso traketsa objektu askorekin lan egiten denean. Informazio bera lor dezakegu makina birtualeko objektutik bertatik (Get-VM). ExtensionData objektuan ondo lurperatuta dago. Iragazkiz armatuta, beharrezko datuak lortzeko prozesua bizkortzen dugu.

Eskuaren mugimendu apur batekin hauxe da:


VM | Get-AdvancedSetting -Name Cloud.uuid -Server $ConnectionString | Select-Object @{N="VMName";E={$_.Entity.Name}},@{N="CloudUUID";E={$_.Value}},@{N="PowerState";E={$_.Entity.PowerState}}

Honetan bihurtzen da:


$VM | Where-Object {($_.ExtensionData.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value -ne $null} | Select-Object @{N="VMName";E={$_.Name}},@{N="CloudUUID";E={($_.ExtensionData.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value}},@{N="PowerState";E={$_.summary.runtime.powerstate}}

Irteera Get-AdvancedOptions-en berdina da, baina askotan azkarrago funtzionatzen du. 

Orain Get-VM-ra. Ez da azkarra objektu konplexuekin lan egiten duelako. Galdera logiko bat sortzen da: zergatik behar dugu informazio gehigarria eta PSObject munstro bat kasu honetan, VMren izena, bere egoera eta atributu delikatuaren balioa besterik ez dugunean behar?  

Horrez gain, Get-AdvancedOptions formako oztopoa gidoitik kendu da. Runspace Pools erabiltzeak gehiegizkoa dirudi, jada ez dagoelako zeregin motel bat hari squat bidez paralelizatu beharrik saio bat ematean. Tresna ona da, baina ez kasu honetarako. 

Ikus dezagun ExtensionData-ren irteera: Get-View objektu bat baino ez da. 

Dei diezaiogun PowerShell maisuen antzinako teknikari: lerro bat iragazkiak, ordenatzea eta taldekatzea erabiliz. Aurreko beldurre guztia lerro batean dotore bildu eta saio batean gauzatzen da:


$AllVMs = Get-View -viewtype VirtualMachine -Property Name,Config.ExtraConfig,summary.runtime.powerstate | Where-Object {($_.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value -ne $null} | Select-Object @{N="VMName";E={$_.Name}},@{N="CloudUUID";E={($_.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value}},@{N="PowerState";E={$_.summary.runtime.powerstate}} | Sort-Object CloudUUID | Group-Object -Property CloudUUID | Where-Object -FilterScript {$_.Count -gt 1} | Select-Object -ExpandProperty Group

Denbora neurtzen dugu:

Nola eraiki PowerCLI scriptetarako suziri bultzatzailea

9 segundo nahi den baldintzaren arabera iragazten duten ia 10k objekturentzat. Bikaina!

Horren ordez Ondorio baten

Emaitza onargarria tresna aukeratzearen araberakoa da zuzenean. Askotan zaila da ziur esatea zer aukeratu behar den hori lortzeko. Scriptak bizkortzeko zerrendatutako metodo bakoitza ona da bere aplikagarritasunaren mugen barruan. Artikulu honek zure azpiegiturako prozesuen automatizazioaren eta optimizazioaren oinarriak ulertzeko lan zailean lagunduko dizula espero dut.

PS: Egileak eskerrak ematen dizkie komunitateko kide guztiei artikulua prestatzeko emandako laguntzagatik. Baita hankak dituztenak ere. Eta hankarik ez dutenek ere, boa bat bezala.

Iturria: www.habr.com

Gehitu iruzkin berria