Чӣ тавр сохтани мушак барои скриптҳои PowerCLI 

Дер ё зуд, ягон маъмури системаи VMware барои автоматикунонии вазифаҳои муқаррарӣ меояд. Ҳамааш аз сатри фармон оғоз мешавад, пас PowerShell ё VMware PowerCLI меояд.

Фарз мекунем, ки шумо PowerShell-ро каме бештар аз оғози ISE ва истифодаи cmdlet-ҳои стандартӣ аз модулҳое, ки аз ҳисоби “як навъ ҷодугарӣ” кор мекунанд, азхуд кардаед. Вақте ки шумо ҳисобкунии мошинҳои виртуалиро дар садҳо оғоз мекунед, шумо хоҳед дид, ки скриптҳое, ки дар миқёси хурд кӯмак мекунанд, дар миқёси калон ба таври назаррас сусттар кор мекунанд. 

Дар ин ҳолат, 2 восита кӯмак хоҳад кард:

  • Рангҳои PowerShell – равиш, ки ба шумо имкон медиҳад, ки иҷрои равандҳоро дар риштаҳои алоҳида параллел созед; 
  • Гирифтан-Намоиш – вазифаи асосии PowerCLI, аналоги Get-WMIObject дар Windows. Ин cmdlet объектҳои ҳамроҳи объектҳоро намекашад, балки маълумотро дар шакли объекти оддӣ бо намудҳои оддии додаҳо қабул мекунад. Дар бисёр мавридҳо он зудтар мебарояд.

Минбаъд, ман дар бораи ҳар як асбоб мухтасар сӯҳбат мекунам ва намунаҳои истифодаро нишон медиҳам. Биёед скриптҳои мушаххасро таҳлил кунем ва бубинем, ки кадоме аз дигараш беҳтар кор мекунад. Бирав!

Чӣ тавр сохтани мушак барои скриптҳои PowerCLI

Марҳилаи аввал: Ранг

Ҳамин тавр, Runspace барои коркарди мувозии вазифаҳо берун аз модули асосӣ пешбинӣ шудааст. Албатта, шумо метавонед як раванди дигареро оғоз кунед, ки каме хотира, протсессор ва ғайраҳоро истеъмол мекунад. Агар скрипти шумо дар тӯли якчанд дақиқа кор кунад ва як гигабайт хотираро истеъмол кунад, эҳтимоли зиёд ба шумо Runspace лозим нест. Аммо барои скриптҳо барои даҳҳо ҳазор объект лозим аст.

Шумо метавонед омӯзишро дар ин ҷо оғоз кунед: 
Оғози истифодаи PowerShell Rnspaces: Қисми 1

Истифодаи Runspace чӣ медиҳад:

  • суръат тавассути маҳдуд кардани рӯйхати фармонҳои иҷрошуда,
  • иҷрои баробари вазифаҳо,
  • бехатарӣ.

Ин аст як мисол аз Интернет, вақте ки Runspace кӯмак мекунад:

"Мушкилоти нигаҳдорӣ яке аз ченакҳои душвортарин барои пайгирӣ дар vSphere аст. Дар дохили vCenter, шумо наметавонед танҳо рафта бубинед, ки кадом VM захираҳои нигаҳдории бештарро истеъмол мекунад. Хушбахтона, шумо метавонед ин маълумотро дар тӯли дақиқаҳо ба шарофати PowerShell ҷамъ кунед.
Ман як скриптро мубодила мекунам, ки ба маъмурони системаи VMware имкон медиҳад, ки дар тамоми vCenter зуд ҷустуҷӯ кунанд ва рӯйхати VM-ро бо маълумот дар бораи истеъмоли миёнаи онҳо гиранд.  
Скрипт фазои иҷроиши PowerShell-ро истифода мебарад, то ба ҳар як мизбони ESXi имкон диҳад, ки маълумоти истеъмолиро аз VM-ҳои худ дар Runspace-и алоҳида ҷамъоварӣ кунад ва фавран дар бораи анҷомёбӣ гузориш диҳад. Ин ба PowerShell имкон медиҳад, ки корҳоро фавран пӯшад, ба ҷои такрор кардани ҳостҳо ва интизор шудани ҳар як дархости худ."

Манбаъ: Чӣ тавр нишон додани мошини виртуалии I/O дар панели ESXi

Дар ҳолати зер, Runspace дигар муфид нест:

“Ман кӯшиш мекунам, ки скрипте нависам, ки аз VM маълумоти зиёде ҷамъоварӣ кунад ва дар ҳолати зарурӣ маълумоти нав менависад. Масъала дар он аст, ки VM-ҳо хеле зиёданд ва барои як мошин 5-8 сония сарф мешавад." 

Манбаъ: Multithreading PowerCLI бо RunspacePool

Дар ин ҷо ба шумо Get-View лозим мешавад, биёед ба он гузарем. 

Марҳилаи дуюм: Get-View

Барои фаҳмидани он ки чаро Get-View муфид аст, бояд дар хотир дошт, ки чӣ гуна cmdletҳо умуман кор мекунанд. 

Cmdlets барои ба осонӣ ба даст овардани маълумот бидуни омӯзиши китобҳои API ва аз нав ихтироъ кардани чархи навбатӣ лозиманд. Он чизе ки дар айёми қадим сад ё ду сатри рамзро мегирад, PowerShell ба шумо имкон медиҳад, ки бо як фармон кор кунед. Мо барои ин бароҳатӣ бо суръат пардохт мекунем. Дар дохили худи cmdlets ҷодугарӣ нест: ҳамон скрипт, вале дар сатҳи поёнтар, ки бо дастони моҳир устоди Ҳиндустони офтобӣ навишта шудааст.

Акнун, барои муқоиса бо Get-View, биёед cmdlet-и Get-VM-ро гирем: он ба мошини виртуалӣ дастрасӣ пайдо мекунад ва объекти таркибро бармегардонад, яъне ба он дигар объектҳои алоқамандро замима мекунад: VMHost, Datastore ва ғайра.  

Get-View дар ҷои худ ба объекти баргардонидашуда ягон чизи нолозимро илова намекунад. Илова бар ин, он ба мо имкон медиҳад, ки ба таври қатъӣ муайян кунем, ки кадом иттилоот ба мо лозим аст, ки объекти баромадро осонтар мекунад. Дар маҷмӯъ дар Windows Server ва махсусан дар Hyper-V, cmdlet Get-WMIObject аналоги мустақим аст - идея комилан якхела аст.

Get-View барои амалиёти муқаррарӣ дар объектҳои нуқта номувофиқ аст. Аммо вакте ки сухан дар бораи хазорхо ва даххо хазор объектхо меравад, нарх надорад.

Шумо метавонед бештар дар блоги VMware хонед: Муқаддима ба Get-View

Ҳоло ман ҳама чизро ба шумо бо истифода аз парвандаи воқеӣ нишон медиҳам. 

Навиштани скрипт барои холӣ кардани VM

Як рӯз ҳамкорам аз ман хоҳиш кард, ки сенарияи ӯро оптимизатсия кунам. Вазифа як реҷаи маъмул аст: ҳама VM-ҳоро бо параметри такрории cloud.uuid пайдо кунед (бале, ин ҳангоми клон кардани VM дар vCloud Director имконпазир аст). 

Ҳалли равшане, ки ба ақл меояд, ин аст:

  1. Рӯйхати ҳамаи VMҳоро гиред.
  2. Рӯйхатро бо ягон роҳ таҳлил кунед.

Варианти аслӣ ин скрипти оддӣ буд:

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

Ҳама чиз бениҳоят содда ва равшан аст. Онро дар давоми якчанд дақиқа бо кофе-брейк навиштан мумкин аст. Филтрро винт кунед ва он анҷом ёфт.

Аммо биёед вақтро чен кунем:

Чӣ тавр сохтани мушак барои скриптҳои PowerCLI

Чӣ тавр сохтани мушак барои скриптҳои PowerCLI

2 дақиқаю 47 сония ҳангоми коркарди қариб 10k VM. Бонус ин набудани филтрҳо ва зарурати ба таври дастӣ ҷудо кардани натиҷаҳо мебошад. Аён аст, ки скрипт оптимизатсияро талаб мекунад.

Вақте ки шумо бояд ҳамзамон аз vCenter метрикаи мизбон гиред ё даҳҳо ҳазор объектро коркард кунед, runspaces аввалин шуда ба наҷот меоянд. Биёед бубинем, ки ин равиш чӣ меорад.

Суръати аввалро фаъол созед: PowerShell Runspaces

Аввалин чизе, ки барои ин скрипт ба хотир меояд, иҷро кардани циклро на пай дар пай, балки дар риштаҳои параллелӣ ҷамъоварӣ кардани ҳама маълумот дар як объект ва филтр кардани он аст. 

Аммо мушкилот вуҷуд дорад: PowerCLI ба мо имкон намедиҳад, ки дар vCenter бисёр сеансҳои мустақил кушоем ва хатои хандаовар содир мекунад:

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.

Барои ҳалли ин, шумо бояд аввал маълумоти сессияро дар дохили ҷараён гузаронед. Биёед дар хотир дорем, ки PowerShell бо объектҳое кор мекунад, ки онҳоро ҳамчун параметр ё ба функсия ё ба ScriptBlock интиқол додан мумкин аст. Биёед сессияро дар шакли чунин объект гузаронем, ки $global:DefaultVIServers (Connect-VIServer бо калиди -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 $_
           }
       }
   }

Акнун биёед multithreading тавассути Pools Runspace амалӣ кунем.  

Алгоритм чунин аст:

  1. Мо рӯйхати ҳамаи VMҳоро мегирем.
  2. Дар ҷараёнҳои мувозӣ мо cloud.uuid мегирем.
  3. Мо маълумотро аз ҷараёнҳо дар як объект ҷамъ мекунем.
  4. Мо объектро тавассути гурӯҳбандӣ кардани он аз рӯи арзиши майдони CloudUUID филтр мекунем: онҳое, ки шумораи арзишҳои беназир аз 1 зиёд аст, VMҳое мебошанд, ки мо ҷустуҷӯ мекунем.

Дар натиҷа, мо скриптро мегирем:


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
}

Зебоии ин скрипт дар он аст, ки онро метавон дар дигар ҳолатҳои шабеҳ тавассути иваз кардани ScriptBlock ва параметрҳое, ки ба ҷараён интиқол дода мешаванд, истифода бурдан мумкин аст. Онро истифода баред!

Мо вақтро чен мекунем:

Чӣ тавр сохтани мушак барои скриптҳои PowerCLI

55 сония. Ин беҳтар аст, аммо он метавонад зудтар бошад. 

Биёед ба суръати дуюм гузарем: GetView

Биёед бифаҳмем, ки чӣ хато аст.
Пеш аз ҳама, cmdlet Get-VM барои иҷро вақти зиёдро мегирад.
Дуюм, cmdlet Get-AdvancedOptions барои анҷом додани он боз ҳам зиёдтар вақт мегирад.
Биёед аввал бо дуюмаш кор кунем. 

Get-AdvancedOptions барои объектҳои инфиродии VM қулай аст, аммо ҳангоми кор бо бисёр объектҳо хеле корношоям аст. Мо метавонем ҳамон маълумотро аз худи объекти мошини виртуалӣ гирем (Get-VM). Он танҳо дар объекти ExtensionData хуб дафн карда шудааст. Бо филтркунӣ муҷаҳҳаз шуда, мо раванди ба даст овардани маълумоти заруриро суръат мебахшем.

Бо як ҳаракати каме даст ин аст:


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

Ба ин табдил меёбад:


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

Натиҷа бо Get-AdvancedOptions якхела аст, аммо он чанд маротиба тезтар кор мекунад. 

Акнун ба Get-VM. Он зуд нест, зеро он бо объектҳои мураккаб сарукор дорад. Саволи мантиқӣ ба миён меояд: чаро дар ин ҳолат ба мо маълумоти иловагӣ ва як PSObject-и даҳшатнок лозим аст, вақте ки ба мо танҳо номи VM, ҳолати он ва арзиши атрибути ҷолиб лозим аст?  

Илова бар ин, монеа дар шакли Get-AdvancedOptions аз скрипт хориҷ карда шудааст. Истифодаи Runspace Pools ҳоло ба назар аз ҳад зиёд ба назар мерасад, зеро дигар зарурати параллелизатсияи вазифаи суст дар байни риштаҳои squat ҳангоми супурдани сессия вуҷуд надорад. Восита хуб аст, аммо барои ин ҳолат нест. 

Биёед ба натиҷаи ExtensionData назар андозем: он ҷуз як объекти Get-View чизи дигаре нест. 

Биёед ба техникаи қадимии устодони PowerShell муроҷиат кунем: як сатр бо истифода аз филтрҳо, гурӯҳбандӣ ва гурӯҳбандӣ. Ҳама даҳшати қаблӣ ба таври шево дар як сатр ҷамъ карда шуда, дар як сессия иҷро карда мешаванд:


$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

Мо вақтро чен мекунем:

Чӣ тавр сохтани мушак барои скриптҳои PowerCLI

Сонияҳои 9 барои қариб 10k объект бо филтр аз рӯи ҳолати дилхоҳ. Аҷоиб!

Ба ҷои хулоса

Натиҷаи қобили қабул бевосита аз интихоби асбоб вобаста аст. Барои ноил шудан ба он аниқ гуфтан лозим аст, ки чӣ бояд интихоб карда шавад, аксар вақт душвор аст. Ҳар яке аз усулҳои номбаршуда барои суръат бахшидан ба скриптҳо дар доираи татбиқи он хуб аст. Ман умедворам, ки ин мақола ба шумо дар кори душвори фаҳмидани асосҳои автоматикунонии равандҳо ва оптимизатсия дар инфрасохтори шумо кӯмак хоҳад кард.

PS: Муаллиф ба ҳамаи аъзоёни ҷомеа барои кӯмак ва дастгирӣ дар таҳияи мақола изҳори сипос мекунад. Ҳатто онҳое, ки панҷаҳо доранд. Ва ҳатто онҳое, ки пой надоранд, ба монанди як бӯй.

Манбаъ: will.com

Илова Эзоҳ