Hvernig á að búa til eldflaugaforrit fyrir PowerCLI forskriftir 

Fyrr eða síðar kemur hvaða VMware kerfisstjóri sem er til að gera sjálfvirkan venjubundin verkefni. Þetta byrjar allt með skipanalínunni, svo kemur PowerShell eða VMware PowerCLI.

Segjum að þú hafir náð tökum á PowerShell aðeins lengra en að ræsa ISE og nota staðlaða cmdlets úr einingum sem virka vegna „einhvers konar töfra“. Þegar þú byrjar að telja sýndarvélar í hundruðum muntu komast að því að forskriftir sem hjálpa til í litlum mæli keyra áberandi hægar í stórum stíl. 

Í þessum aðstæðum munu 2 verkfæri hjálpa:

  • PowerShell Runspaces - nálgun sem gerir þér kleift að samsíða framkvæmd ferla í aðskildum þráðum; 
  • Get-View – grunn PowerCLI aðgerð, hliðstæða Get-WMIObject í Windows. Þetta cmdlet dregur ekki hluti sem fylgja einingum, heldur fær upplýsingar í formi einfalds hlutar með einföldum gagnagerðum. Í mörgum tilfellum kemur það hraðar út.

Næst mun ég tala stuttlega um hvert tól og sýna dæmi um notkun. Við skulum greina ákveðin handrit og sjá hvenær eitt virkar betur en hitt. Farðu!

Hvernig á að búa til eldflaugaforrit fyrir PowerCLI forskriftir

Fyrsta stig: Runspace

Svo, Runspace er hannað fyrir samhliða vinnslu verkefna utan aðaleiningarinnar. Auðvitað geturðu ræst annað ferli sem mun éta upp eitthvað minni, örgjörva osfrv. Ef handritið þitt keyrir eftir nokkrar mínútur og eyðir gígabæta af minni, þá þarftu líklega ekki Runspace. En fyrir forskriftir fyrir tugþúsundir hluta þarf það.

Þú getur byrjað að læra hér: 
Upphafsnotkun PowerShell Runspaces: Part 1

Hvað gefur notkun Runspace:

  • hraða með því að takmarka lista yfir framkvæmdar skipanir,
  • samhliða framkvæmd verkefna,
  • öryggi.

Hér er dæmi af netinu þegar Runspace hjálpar:

„Geymsludeilur er ein erfiðasta mælikvarðinn til að rekja í vSphere. Inni í vCenter geturðu ekki bara farið og séð hvaða VM eyðir meira geymsluauðlindum. Sem betur fer geturðu safnað þessum gögnum á nokkrum mínútum þökk sé PowerShell.
Ég mun deila skriftu sem gerir VMware kerfisstjórum kleift að leita fljótt í vCenter og fá lista yfir VM með gögnum um meðalnotkun þeirra.  
Handritið notar PowerShell keyrslurými til að leyfa hverjum ESXi hýsingaraðila að safna neysluupplýsingum frá eigin VMs í sérstöku Runspace og tilkynna strax um lokun. Þetta gerir PowerShell kleift að loka verkum strax, frekar en að endurtaka í gegnum vélar og bíða eftir að hver og einn ljúki beiðni sinni.

Heimild: Hvernig á að sýna sýndarvél I/O á ESXi mælaborði

Í tilvikinu hér að neðan er Runspace ekki lengur gagnlegt:

„Ég er að reyna að skrifa handrit sem safnar miklum gögnum úr VM og skrifar ný gögn þegar þörf krefur. Vandamálið er að það eru töluvert mikið af VM og 5-8 sekúndum er eytt í einni vél.“ 

Heimild: Multithreading PowerCLI með RunspacePool

Hér þarftu Get-View, við skulum halda áfram að því. 

Annað stig: Get-View

Til að skilja hvers vegna Get-View er gagnlegt er þess virði að muna hvernig cmdlets virka almennt. 

Cmdlets eru nauðsynlegar til að fá upplýsingar á þægilegan hátt án þess að þurfa að rannsaka API uppflettibækur og finna upp næsta hjól. Það sem í gamla daga tók hundrað eða tvær línur af kóða, PowerShell gerir þér kleift að gera með einni skipun. Við borgum fyrir þessi þægindi með hraða. Það er enginn galdur inni í cmdletunum sjálfum: sama handritið, en á lægra stigi, skrifað af færum höndum meistara frá sólríkum Indlandi.

Nú, til samanburðar við Get-View, skulum við taka Get-VM cmdlet: það opnar sýndarvélina og skilar samsettum hlut, það er að segja, það tengir aðra tengda hluti við það: VMHost, Datastore, osfrv.  

Get-View í staðinn bætir engu óþarfa við hlutinn sem skilað er. Þar að auki gerir það okkur kleift að tilgreina nákvæmlega hvaða upplýsingar við þurfum, sem mun gera úttakshlutinn auðveldari. Í Windows Server almennt og í Hyper-V sérstaklega, er Get-WMIObject cmdlet bein hliðstæða - hugmyndin er nákvæmlega sú sama.

Get-View er óþægilegt fyrir venjulegar aðgerðir á punkthlutum. En þegar um þúsundir og tugþúsundir hluta er að ræða hefur það ekkert verð.

Þú getur lesið meira á VMware blogginu: Kynning á Get-View

Nú skal ég sýna þér allt með því að nota alvöru mál. 

Að skrifa skriftu til að afferma VM

Dag einn bað kollegi minn mig um að fínstilla handritið sitt. Verkefnið er algeng rútína: finndu allar VMs með afrita cloud.uuid færibreytu (já, þetta er mögulegt þegar VM er klónað í vCloud Director). 

Augljósa lausnin sem kemur upp í hugann er:

  1. Fáðu lista yfir alla VM.
  2. Skoðaðu listann einhvern veginn.

Upprunalega útgáfan var þetta einfalda handrit:

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

Allt er einstaklega einfalt og skýrt. Það er hægt að skrifa hana á nokkrum mínútum með kaffihléi. Skrúfaðu á síunina og það er búið.

En við skulum mæla tímann:

Hvernig á að búa til eldflaugaforrit fyrir PowerCLI forskriftir

Hvernig á að búa til eldflaugaforrit fyrir PowerCLI forskriftir

2 mínútur 47 sekúndur við vinnslu næstum 10 VM. Bónus er skortur á síum og nauðsyn þess að raða niðurstöðunum handvirkt. Augljóslega þarf handritið hagræðingu.

Runspaces eru þeir fyrstu sem koma til bjargar þegar þú þarft samtímis að fá hýsilmælingar frá vCenter eða þarft að vinna úr tugþúsundum hluta. Við skulum sjá hvað þessi nálgun hefur í för með sér.

Kveiktu á fyrsta hraðanum: PowerShell Runspaces

Það fyrsta sem kemur upp í hugann fyrir þetta handrit er að keyra lykkjuna ekki í röð, heldur samhliða þræði, safna öllum gögnum í einn hlut og sía þau. 

En það er vandamál: PowerCLI mun ekki leyfa okkur að opna margar sjálfstæðar lotur í vCenter og mun henda skemmtilegri villu:

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.

Til að leysa þetta þarftu fyrst að senda upplýsingar um lotuna inn í strauminn. Við skulum muna að PowerShell vinnur með hlutum sem hægt er að senda sem færibreytu annaðhvort til falls eða ScriptBlock. Við skulum fara framhjá lotunni í formi slíks hlutar, framhjá $global:DefaultVIServers (Tengdu-VIServer með -NotDefault lyklinum):

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

Nú skulum við innleiða multithreading í gegnum Runspace Pools.  

Reikniritið er sem hér segir:

  1. Við fáum lista yfir alla VM.
  2. Samhliða straumum fáum við cloud.uuid.
  3. Við söfnum gögnum úr straumum í einn hlut.
  4. Við síum hlutinn með því að flokka hann eftir gildi CloudUUID reitsins: þau þar sem fjöldi einstakra gilda er meiri en 1 eru VM sem við erum að leita að.

Fyrir vikið fáum við handritið:


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
}

Fegurðin við þetta handrit er að það er hægt að nota það í öðrum svipuðum tilvikum með því einfaldlega að skipta um ScriptBlock og færibreyturnar sem verða sendar til straumsins. Nýttu þér það!

Við mælum tíma:

Hvernig á að búa til eldflaugaforrit fyrir PowerCLI forskriftir

55 sekúndur. Það er betra, en það getur samt verið hraðari. 

Við skulum fara á annan hraðann: GetView

Við skulum komast að því hvað er að.
Fyrst og fremst tekur Get-VM cmdlet langan tíma að keyra.
Í öðru lagi tekur Get-AdvancedOptions cmdletið enn lengri tíma að klára.
Við skulum takast á við seinni fyrst. 

Get-AdvancedOptions er þægilegt fyrir einstaka VM hluti, en mjög klaufalegt þegar unnið er með marga hluti. Við getum fengið sömu upplýsingar frá sýndarvélarhlutnum sjálfum (Get-VM). Það er bara grafið vel í ExtensionData hlutnum. Vopnuð síun flýtum við ferlinu við að afla nauðsynlegra gagna.

Með smá hreyfingu á hendi er þetta:


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

Breytist í þetta:


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

Úttakið er það sama og Get-AdvancedOptions, en það virkar margfalt hraðar. 

Nú til Get-VM. Það er ekki hratt vegna þess að það fjallar um flókna hluti. Rökrétt spurning vaknar: hvers vegna þurfum við aukaupplýsingar og voðalegt PSO-efni í þessu tilfelli, þegar við þurfum bara nafn VM, ástand þess og gildi erfiðrar eigindar?  

Að auki hefur hindrunin í formi Get-AdvancedOptions verið fjarlægð úr handritinu. Að nota Runspace Pools virðist nú vera of mikið þar sem það er ekki lengur þörf á að samhliða hægu verkefni yfir digurþræði þegar lotu er afhent. Tólið er gott, en ekki fyrir þetta tilfelli. 

Við skulum líta á úttak ExtensionData: það er ekkert annað en Get-View hlutur. 

Við skulum kalla á hina fornu tækni PowerShell meistaranna: ein lína með síum, flokkun og flokkun. Allur fyrri hryllingurinn er glæsilegur hrundið saman í eina línu og framkvæmd í einni lotu:


$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

Við mælum tíma:

Hvernig á að búa til eldflaugaforrit fyrir PowerCLI forskriftir

9 sekúndur fyrir næstum 10k hluti með síun eftir æskilegu ástandi. Frábært!

Í stað þess að niðurstöðu

Ásættanleg niðurstaða fer beint eftir vali á tóli. Það er oft erfitt að segja með vissu hvað nákvæmlega ætti að velja til að ná því. Hver af aðferðunum sem taldar eru upp til að flýta fyrir forskriftum er góð innan takmarka þess. Ég vona að þessi grein muni hjálpa þér í því erfiða verkefni að skilja grunnatriði sjálfvirkni ferla og hagræðingu í innviðum þínum.

PS: Höfundur þakkar öllum meðlimum samfélagsins fyrir hjálpina og stuðninginn við gerð greinarinnar. Jafnvel þeir sem eru með loppur. Og jafnvel þeir sem ekki eru með fætur, eins og bóaþröng.

Heimild: www.habr.com

Bæta við athugasemd