Kaip sukurti „PowerCLI“ scenarijų raketų stiprintuvą 

Anksčiau ar vėliau bet kuris VMware sistemos administratorius ateina automatizuoti įprastas užduotis. Viskas prasideda nuo komandinės eilutės, tada ateina PowerShell arba VMware PowerCLI.

Tarkime, kad įvaldėte „PowerShell“ šiek tiek toliau nei paleidžiate ISE ir naudojate standartines cmdlet iš modulių, kurie veikia dėl „tam tikros magijos“. Kai pradėsite skaičiuoti virtualias mašinas šimtais, pamatysite, kad scenarijai, padedantys nedideliu mastu, veikia pastebimai lėčiau dideliu mastu. 

Šioje situacijoje padės 2 įrankiai:

  • PowerShell Runspaces – metodas, leidžiantis lygiagretinti procesų vykdymą atskirose gijose; 
  • Gaukite peržiūrą – pagrindinė PowerCLI funkcija, Get-WMIObject analogas sistemoje Windows. Ši cmdlet netraukia objektų, lydinčių esybes, bet gauna informaciją kaip paprastą objektą su paprastais duomenų tipais. Daugeliu atvejų tai išeina greičiau.

Toliau trumpai pakalbėsiu apie kiekvieną priemonę ir parodysiu naudojimo pavyzdžius. Išanalizuokime konkrečius scenarijus ir pažiūrėkime, kada vienas veikia geriau už kitą. Pirmyn!

Kaip sukurti „PowerCLI“ scenarijų raketų stiprintuvą

Pirmas etapas: Runspace

Taigi, „Runspace“ skirta lygiagrečiam užduočių apdorojimui už pagrindinio modulio ribų. Žinoma, galite paleisti kitą procesą, kuris sunaudos šiek tiek atminties, procesoriaus ir pan. Jei jūsų scenarijus paleidžiamas per kelias minutes ir užima gigabaitą atminties, greičiausiai jums nereikės Runspace. Tačiau to reikia dešimčių tūkstančių objektų scenarijams.

Mokytis galite pradėti čia: 
„PowerShell Runspaces“ naudojimo pradžia: 1 dalis

Ką duoda Runspace naudojimas:

  • greitį apribojant vykdomų komandų sąrašą,
  • lygiagretus užduočių vykdymas,
  • saugumas.

Štai pavyzdys iš interneto, kai „Runspace“ padeda:

„Konkursas dėl saugyklos yra viena iš sunkiausių „vSphere“ metrikų. „vCenter“ viduje negalite tiesiog eiti ir pamatyti, kuri VM sunaudoja daugiau saugyklos išteklių. Laimei, „PowerShell“ dėka šiuos duomenis galite surinkti per kelias minutes.
Pasidalinsiu scenarijumi, kuris leis VMware sistemos administratoriams greitai ieškoti visame vCenter ir gauti VM sąrašą su duomenimis apie jų vidutinį suvartojimą.  
Scenarijus naudoja „PowerShell“ vykdymo sritis, kad kiekviena ESXi priegloba galėtų rinkti vartojimo informaciją iš savo VM atskiroje „Runspace“ ir nedelsiant pranešti apie užbaigimą. Tai leidžia „PowerShell“ nedelsiant uždaryti užduotis, o ne kartoti pagrindinius kompiuterius ir laukti, kol kiekvienas užpildys užklausą.

Šaltinis: Kaip ESXi prietaisų skydelyje parodyti virtualios mašinos įvestį / išvestį

Toliau nurodytu atveju „Runspace“ nebėra naudinga:

„Bandau parašyti scenarijų, kuris surenka daug duomenų iš VM ir prireikus įrašo naujus duomenis. Bėda ta, kad VM yra gana daug, o viename kompiuteryje praleidžiama 5-8 sekundės. 

Šaltinis: Multithreading PowerCLI su RunspacePool

Čia jums reikės Get-View, pereikime prie jo. 

Antrasis etapas: „Get-View“.

Norint suprasti, kodėl Get-View yra naudinga, verta prisiminti, kaip apskritai veikia cmdlet. 

Cmdlet reikalingos norint patogiai gauti informaciją, nereikia studijuoti API žinynų ir iš naujo išradinėti kitą ratą. Tai, kas senais laikais užtrukdavo šimtą ar dvi kodo eilutes, „PowerShell“ leidžia padaryti viena komanda. Už šį patogumą mokame greičiu. Pačiuose cmdlet viduje nėra jokios magijos: tas pats scenarijus, bet žemesnio lygio, parašytas sumaniomis meistro iš saulėtosios Indijos rankomis.

Palyginimui su Get-View, paimkime Get-VM cmdlet: ji pasiekia virtualią mašiną ir grąžina sudėtinį objektą, tai yra, prideda prie jo kitus susijusius objektus: VMHost, Datastore ir kt.  

Get-View savo vietoje neprideda nieko nereikalingo prie grąžinamo objekto. Be to, tai leidžia mums griežtai nurodyti, kokios informacijos mums reikia, o tai palengvins išvesties objektą. „Windows Server“ apskritai ir ypač „Hyper-V“ cmdlet „Get-WMIObject“ yra tiesioginis analogas – idėja lygiai tokia pati.

„Get-View“ yra nepatogu atliekant įprastines operacijas su taškiniais objektais. Tačiau kalbant apie tūkstančius ir dešimtis tūkstančių objektų, tai neturi jokios kainos.

Daugiau galite perskaityti VMware tinklaraštyje: Įvadas į Get-View

Dabar aš jums viską parodysiu naudodamas tikrą dėklą. 

Scenarijaus rašymas VM iškrovimui

Vieną dieną mano kolega paprašė manęs optimizuoti jo scenarijų. Užduotis yra įprasta: suraskite visas VM su pasikartojančiu „cloud.uuid“ parametru (taip, tai įmanoma klonuojant VM „vCloud Director“). 

Akivaizdus sprendimas, kuris ateina į galvą, yra:

  1. Gaukite visų VM sąrašą.
  2. Kaip nors išanalizuoti sąrašą.

Pradinė versija buvo toks paprastas scenarijus:

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

Viskas labai paprasta ir aišku. Su kavos pertraukėle galima parašyti per porą minučių. Užsukite filtravimą ir viskas.

Bet išmatuokime laiką:

Kaip sukurti „PowerCLI“ scenarijų raketų stiprintuvą

Kaip sukurti „PowerCLI“ scenarijų raketų stiprintuvą

2 minutės 47 sekundžių apdorojant beveik 10 XNUMX VM. Privalumas yra filtrų nebuvimas ir poreikis rankiniu būdu rūšiuoti rezultatus. Akivaizdu, kad scenarijų reikia optimizuoti.

Runspaces yra pirmosios, kurios į pagalbą ateina, kai reikia vienu metu gauti pagrindinio kompiuterio metriką iš „vCenter“ arba apdoroti dešimtis tūkstančių objektų. Pažiūrėkime, ką šis požiūris atneša.

Įjunkite pirmąjį greitį: „PowerShell Runspaces“.

Pirmas dalykas, kuris ateina į galvą šiam scenarijui, yra paleisti kilpą ne nuosekliai, o lygiagrečiomis gijomis, surinkti visus duomenis į vieną objektą ir jį filtruoti. 

Tačiau yra problema: „PowerCLI“ neleis mums atidaryti daugelio nepriklausomų seansų „vCenter“ ir išmes juokingą klaidą:

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.

Norėdami tai išspręsti, pirmiausia turite perduoti seanso informaciją sraute. Prisiminkime, kad „PowerShell“ veikia su objektais, kurie gali būti perduoti kaip parametras funkcijai arba ScriptBlock. Perduokime sesiją tokio objekto pavidalu, apeinant $global:DefaultVIServers (Connect-VIServer su klavišu -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 $_
           }
       }
   }

Dabar įgyvendinkime kelių gijų per Runspace Pools.  

Algoritmas yra toks:

  1. Gauname visų VM sąrašą.
  2. Lygiagrečiais srautais gauname debesį.uuid.
  3. Duomenis iš srautų renkame į vieną objektą.
  4. Filtruojame objektą sugrupuodami jį pagal CloudUUID lauko reikšmę: tie, kuriuose unikalių reikšmių skaičius yra didesnis nei 1, yra mūsų ieškomos VM.

Kaip rezultatas, mes gauname scenarijų:


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
}

Šio scenarijaus grožis yra tas, kad jį galima naudoti kitais panašiais atvejais tiesiog pakeičiant ScriptBlock ir parametrus, kurie bus perduoti srautui. Išnaudok tai!

Matuojame laiką:

Kaip sukurti „PowerCLI“ scenarijų raketų stiprintuvą

55 sek. Tai geriau, bet vis tiek gali būti greitesnė. 

Pereikime prie antrojo greičio: GetView

Išsiaiškinkime, kas negerai.
Visų pirma, Get-VM cmdlet vykdomas ilgai.
Antra, Get-AdvancedOptions cmdlet užbaigimas užtrunka dar ilgiau.
Pirmiausia susidorokime su antruoju. 

Get-AdvancedOptions yra patogus atskiriems VM objektams, tačiau labai gremėzdiškas dirbant su daugybe objektų. Tą pačią informaciją galime gauti iš paties virtualios mašinos objekto (Get-VM). Jis tiesiog gerai palaidotas ExtensionData objekte. Apsiginklavę filtravimu, pagreitiname reikalingų duomenų gavimo procesą.

Nedideliu rankos judesiu tai yra:


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

Pavirsta į tai:


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

Išvestis yra tokia pati kaip Get-AdvancedOptions, tačiau ji veikia daug kartų greičiau. 

Dabar prie Get-VM. Tai nėra greita, nes ji susijusi su sudėtingais objektais. Kyla logiškas klausimas: kam šiuo atveju reikia papildomos informacijos ir monstriško PSOobjekto, kai tereikia VM pavadinimo, jo būsenos ir gudraus atributo reikšmės?  

Be to, iš scenarijaus pašalinta kliūtis Get-AdvancedOptions forma. Naudoti „Runspace Pools“ dabar atrodo per daug, nes perduodant seansą nebėra poreikio lygiagrečiai atlikti lėtą užduotį tarp pritūpusių gijų. Priemonė gera, bet ne šiam atvejui. 

Pažvelkime į ExtensionData išvestį: tai ne kas kita, kaip Get-View objektas. 

Pasikvieskime senovinę PowerShell meistrų techniką: viena eilutė naudojant filtrus, rūšiavimas ir grupavimas. Visas ankstesnis siaubas elegantiškai sutrauktas į vieną eilutę ir įvykdytas per vieną seansą:


$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

Matuojame laiką:

Kaip sukurti „PowerCLI“ scenarijų raketų stiprintuvą

9 sekundžių beveik 10 XNUMX objektų su filtravimu pagal pageidaujamą sąlygą. Puiku!

Vietoj išvados

Priimtinas rezultatas tiesiogiai priklauso nuo įrankio pasirinkimo. Dažnai sunku tiksliai pasakyti, ką tiksliai reikėtų pasirinkti norint tai pasiekti. Kiekvienas iš išvardytų scenarijų paspartinimo metodų yra geras savo pritaikomumo ribose. Tikiuosi, kad šis straipsnis padės jums atlikti sudėtingą užduotį – suprasti procesų automatizavimo ir optimizavimo savo infrastruktūroje pagrindus.

PS: Autorius dėkoja visiems bendruomenės nariams už pagalbą ir paramą rengiant straipsnį. Net tie, kurie turi letenas. Ir net tie, kurie neturi kojų, kaip boa constrictor.

Šaltinis: www.habr.com

Добавить комментарий