Ki jan yo bati yon fize fize pou scripts PowerCLI 

Pi bonè oswa pita, nenpòt administratè sistèm VMware vin otomatize travay woutin yo. Li tout kòmanse ak liy lòd la, Lè sa a, vini PowerShell oswa VMware PowerCLI.

Ann di ou te metrize PowerShell yon ti kras pi lwen pase lanse ISE ak lè l sèvi avèk cmdlets estanda soti nan modil ki travay akòz "kèk kalite majik". Lè ou kòmanse konte machin vityèl nan dè santèn yo, w ap jwenn ke scripts ki ede soti nan yon ti echèl kouri notables pi dousman sou yon gwo echèl. 

Nan sitiyasyon sa a, 2 zouti pral ede:

  • PowerShell Runspaces - yon apwòch ki pèmèt ou paralelize ekzekisyon an nan pwosesis nan fil separe; 
  • Jwenn-View – yon fonksyon PowerCLI debaz, yon analogue Get-WMIObject nan Windows. Cmdlet sa a pa rale objè ki akonpaye antite, men li resevwa enfòmasyon sou fòm yon objè senp ak kalite done senp. Nan anpil ka li soti pi vit.

Apre sa, mwen pral yon ti tan pale sou chak zouti epi montre egzanp itilizasyon. Ann analize script espesifik yo epi wè lè youn ap travay pi byen pase lòt la. Ale!

Ki jan yo bati yon fize fize pou scripts PowerCLI

Premye etap: Runspace

Se konsa, Runspace fèt pou pwosesis paralèl nan travay deyò modil prensipal la. Natirèlman, ou ka lanse yon lòt pwosesis ki pral manje kèk memwa, processeur, elatriye. Si script ou a kouri nan yon koup de minit epi konsome yon gigabyte nan memwa, gen plis chans ou pa pral bezwen Runspace. Men, pou scripts pou dè dizèn de milye de objè li nesesè.

Ou ka kòmanse aprann isit la: 
Kòmanse Itilizasyon PowerShell Runspaces: Pati 1

Kisa w ap itilize Runspace bay:

  • vitès pa limite lis kòmandman egzekite,
  • ekzekisyon paralèl nan travay,
  • sekirite.

Men yon egzanp sou entènèt la lè Runspace ede:

"Depo depo se youn nan mezi ki pi difisil pou swiv nan vSphere. Anndan vCenter, ou pa ka jis ale epi wè ki VM ap konsome plis resous depo. Erezman, ou ka kolekte done sa yo nan kèk minit gras a PowerShell.
Mwen pral pataje yon script ki pral pèmèt administratè sistèm VMware fè rechèch rapid nan tout vCenter epi resevwa yon lis VM ak done sou konsomasyon mwayèn yo.  
Script la itilize PowerShell runspaces pou pèmèt chak lame ESXi kolekte enfòmasyon sou konsomasyon nan pwòp VM pa yo nan yon Runspace separe epi imedyatman rapòte fini. Sa pèmèt PowerShell fèmen djòb imedyatman, olye ke iterasyon atravè tout lame yo epi tann pou chak moun ranpli demann li yo.

Sous: Ki jan yo montre Virtual Machine I/O sou yon tablodbò ESXi

Nan ka ki anba a, Runspace pa itil ankò:

“Mwen ap eseye ekri yon script ki kolekte anpil done ki sòti nan yon VM epi ekri nouvo done lè sa nesesè. Pwoblèm lan se ke gen anpil VM, epi yo pase 5-8 segonn sou yon sèl machin. 

Sous: Multithreading PowerCLI ak RunspacePool

La a ou pral bezwen Get-View, ann deplase sou li. 

Dezyèm etap: Jwenn-View

Pou konprann poukisa Get-View itil, li vo sonje kijan cmdlets travay an jeneral. 

Cmdlets yo bezwen pou jwenn enfòmasyon fasilman san yo pa bezwen etidye liv referans API ak reenvante pwochen wou a. Ki sa ki nan ansyen tan yo te pran yon santèn oswa de liy nan kòd, PowerShell pèmèt ou fè ak yon sèl lòd. Nou peye pou konvenyans sa a ak vitès. Pa gen okenn maji andedan cmdlets yo tèt yo: script la menm, men nan yon nivo pi ba, ekri pa men yo ladrès nan yon mèt ki soti nan solèy peyi Zend.

Koulye a, pou konparezon ak Get-View, ann pran cmdlet Get-VM: li jwenn aksè nan machin vityèl la epi li retounen yon objè konpoze, se sa ki, li tache lòt objè ki gen rapò ak li: VMHost, Datastore, elatriye.  

Get-View nan plas li pa ajoute anyen ki pa nesesè nan objè a retounen. Anplis, li pèmèt nou entèdi presize enfòmasyon nou bezwen, ki pral fè objè pwodiksyon an pi fasil. Nan Windows Server an jeneral ak nan Hyper-V an patikilye, cmdlet Get-WMIObject se yon analogu dirèk - lide a se egzakteman menm bagay la.

Get-View se enkonvenyan pou operasyon woutin sou objè pwen. Men, lè li rive dè milye ak dè dizèn de milye de objè, li pa gen okenn pri.

Ou ka li plis sou blog VMware: Entwodiksyon Get-View

Koulye a, mwen pral montre w tout bagay lè l sèvi avèk yon ka reyèl. 

Ekri yon script pou dechaje yon VM

Yon jou, kòlèg mwen an te mande m 'optimize script li a. Travay la se yon woutin komen: jwenn tout VM ki gen yon paramèt cloud.uuid kopi (wi, sa posib lè klonaj yon VM nan vCloud Director). 

Solisyon evidan ki vin nan tèt ou se:

  1. Jwenn yon lis tout VM yo.
  2. Analize lis la yon jan kanmenm.

Vèsyon orijinal la te script senp sa a:

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
}
# Далее РУКАМИ парсим полученный результат

Tout bagay trè senp ak klè. Li ka ekri nan yon koup de minit ak yon ti repo kafe. Vise filtraj la epi li fini.

Men, ann mezire tan an:

Ki jan yo bati yon fize fize pou scripts PowerCLI

Ki jan yo bati yon fize fize pou scripts PowerCLI

2 minit 47 segonn lè w ap trete prèske 10k VM. Yon bonis se absans la nan filtè ak bezwen nan manyèlman sòt rezilta yo. Li evidan, script la mande pou optimize.

Runspaces yo se premye moun ki vin pote sekou lè ou bezwen an menm tan jwenn mezi lame nan vCenter oswa bezwen trete plizyè dizèn de milye objè. Ann wè sa apwòch sa a pote.

Limen premye vitès la: PowerShell Runspaces

Premye bagay ki vin nan tèt ou pou script sa a se egzekite bouk la pa sekans, men nan fil paralèl, kolekte tout done yo nan yon sèl objè epi filtre li. 

Men, gen yon pwoblèm: PowerCLI pa pral pèmèt nou louvri anpil sesyon endepandan nan vCenter epi li pral voye yon erè komik:

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.

Pou rezoud sa a, ou dwe premye pase enfòmasyon sesyon andedan kouran an. Se pou nou sonje ke PowerShell travay ak objè ki ka pase kòm yon paramèt swa nan yon fonksyon oswa nan yon ScriptBlock. Ann pase sesyon an sou fòm yon objè konsa, contourner $global:DefaultVIServers (Konekte-VIServer ak kle a -NotDefault):

$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 $_
           }
       }
   }

Koulye a, ann aplike multithreading atravè Runspace Pools.  

Algoritm lan se jan sa a:

  1. Nou jwenn yon lis tout VM yo.
  2. Nan kouran paralèl nou jwenn cloud.uuid.
  3. Nou kolekte done ki soti nan kouran nan yon sèl objè.
  4. Nou filtre objè a pa gwoupe li pa valè jaden CloudUUID la: moun ki kote kantite valè inik pi gran pase 1 se VM n ap chèche.

Kòm yon rezilta, nou jwenn script la:


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
}

Bote nan script sa a se ke li ka itilize nan lòt ka ki sanble pa tou senpleman ranplase ScriptBlock la ak paramèt yo ki pral pase nan kouran an. Eksplwate li!

Nou mezire tan:

Ki jan yo bati yon fize fize pou scripts PowerCLI

55 segonn. Li pi bon, men li ka toujou pi vit. 

Ann ale nan dezyèm vitès la: GetView

Ann chèche konnen sa ki mal.
Premye ak premye, cmdlet Get-VM pran anpil tan pou egzekite.
Dezyèmman, cmdlet Get-AdvancedOptions pran menm plis tan pou konplete.
Ann fè fas ak dezyèm lan an premye. 

Get-AdvancedOptions se pratik pou objè VM endividyèl, men trè maladwa lè w ap travay ak anpil objè. Nou ka jwenn menm enfòmasyon an nan objè machin vityèl tèt li (Get-VM). Li jis antere l byen nan objè ExtensionData. Ame ak filtraj, nou akselere pwosesis pou jwenn done ki nesesè yo.

Avèk yon ti mouvman nan men an sa a se:


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

Li vire nan sa a:


$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}}

Pwodiksyon an se menm jan ak Get-AdvancedOptions, men li travay anpil fwa pi vit. 

Koulye a, jwenn-VM. Li pa vit paske li fè fas ak objè konplèks. Yon kesyon lojik rive: poukisa nou bezwen enfòmasyon siplemantè ak yon PSObject kolosal nan ka sa a, lè nou jis bezwen non an nan VM a, eta li yo ak valè a nan yon atribi difisil?  

Anplis de sa, obstak la nan fòm Get-AdvancedOptions yo te retire nan script la. Sèvi ak Runspace Pools kounye a sanble twòp paske pa gen okenn nesesite ankò pou paralelize yon travay dousman atravè fil koupi byen lè w ap remèt yon sesyon. Zouti a bon, men se pa pou ka sa a. 

Ann gade nan pwodiksyon ExtensionData: li pa gen anyen plis pase yon objè Get-View. 

Ann rele sou ansyen teknik mèt PowerShell yo: yon liy lè l sèvi avèk filtè, klasman ak gwoupman. Tout laterè anvan an se elegant tonbe nan yon sèl liy epi egzekite nan yon sèl sesyon:


$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

Nou mezire tan:

Ki jan yo bati yon fize fize pou scripts PowerCLI

9 segonn pou prèske 10k objè ak filtraj pa kondisyon an vle. Gwo!

Olye pou yo yon konklizyon

Yon rezilta akseptab depann dirèkteman sou chwa zouti yo. Li souvan difisil pou di pou asire w ki sa egzakteman yo ta dwe chwazi reyalize li. Chak nan metòd ki nan lis yo pou akselere scripts bon nan limit aplikab li yo. Mwen espere atik sa a pral ede w nan travay la difisil pou konprann Basics yo nan automatisation pwosesis ak optimize nan enfrastrikti ou.

PS: Otè a remèsye tout manm kominote a pou èd ak sipò yo nan prepare atik la. Menm moun ki gen grif. E menm moun ki pa gen janm, tankou yon boa constrictor.

Sous: www.habr.com

Add nouvo kòmantè