PowerCLI скриптүүдэд зориулсан пуужин өргөгчийг хэрхэн бүтээх вэ 

Эрт орой хэзээ нэгэн цагт аливаа VMware системийн администратор ердийн ажлуудыг автоматжуулахаар ирдэг. Энэ бүхэн тушаалын мөрөөс эхэлж, дараа нь PowerShell эсвэл VMware PowerCLI ирдэг.

Та PowerShell-ийг ISE-г эхлүүлж, "ямар нэгэн ид шидийн" ачаар ажилладаг модулиудын стандарт командуудыг ашиглахаас арай илүү эзэмшсэн гэж бодъё. Виртуал машинуудыг хэдэн зуугаар нь тоолж эхлэхэд жижиг хэмжээнд тусалдаг скриптүүд том хэмжээний хувьд мэдэгдэхүйц удаашралтай ажиллах болно. 

Энэ тохиолдолд 2 хэрэгсэл туслах болно:

  • PowerShell ажиллуулах зай – тусдаа хэлхээ дэх процессуудын гүйцэтгэлийг зэрэгцүүлэх боломжийг олгодог арга; 
  • Авах-Харах – үндсэн PowerCLI функц, Windows дээрх Get-WMIObject-ийн аналог. Энэ командлет нь дагалдах объектуудыг татахгүй, харин энгийн өгөгдлийн төрлүүдтэй энгийн объект хэлбэрээр мэдээллийг хүлээн авдаг. Ихэнх тохиолдолд энэ нь илүү хурдан гарч ирдэг.

Дараа нь би хэрэгсэл бүрийн талаар товч ярьж, хэрэглээний жишээг харуулах болно. Тодорхой скриптүүдэд дүн шинжилгээ хийж, аль нь нөгөөгөөсөө илүү сайн ажиллахыг харцгаая. Яв!

PowerCLI скриптүүдэд зориулсан пуужин өргөгчийг хэрхэн бүтээх вэ

Эхний шат: Ажиллах зай

Тиймээс, Runspace нь үндсэн модулийн гаднах даалгавруудыг зэрэгцээ боловсруулахад зориулагдсан. Мэдээжийн хэрэг, та санах ой, процессор гэх мэт бага зэрэг идэх өөр процессыг эхлүүлж болно. Хэрэв таны скрипт хэдхэн минутын дотор ажиллаж, нэг гигабайт санах ой зарцуулдаг бол танд Runspace хэрэггүй болно. Гэхдээ хэдэн арван мянган объектын скриптүүдийн хувьд энэ нь шаардлагатай.

Та эндээс сурч эхэлж болно: 
PowerShell runspace-ийн ашиглалтын эхлэл: 1-р хэсэг

Runspace ашиглах нь юу өгдөг вэ:

  • гүйцэтгэсэн тушаалуудын жагсаалтыг хязгаарлах замаар хурд,
  • даалгавруудыг зэрэгцүүлэн гүйцэтгэх,
  • аюулгүй байдал.

Runspace нь туслах үед интернетээс авсан жишээ энд байна:

“Хадгалалтын маргаан бол vSphere дээр хянахад хамгийн хэцүү хэмжүүрүүдийн нэг юм. vCenter дотор та аль VM илүү хадгалах нөөцийг ашиглаж байгааг харж чадахгүй. Аз болоход та PowerShell-ийн ачаар энэ өгөгдлийг хэдхэн минутын дотор цуглуулах боломжтой.
Би VMware системийн администраторуудад vCenter даяар хурдан хайлт хийж, дундаж хэрэглээнийхээ өгөгдөл бүхий VM-ийн жагсаалтыг хүлээн авах скриптийг хуваалцах болно.  
Скрипт нь PowerShell ажиллах зайг ашигладаг бөгөөд ESXi хост бүр өөрийн VM-ээс хэрэглээний мэдээллийг тусдаа Runspace-д цуглуулж, дууссан тухай нэн даруй мэдээлэх боломжийг олгодог. Энэ нь PowerShell-д хостуудыг давтаж, хүсэлтээ дуусгахыг хүлээхийн оронд шууд ажлын байрыг хаах боломжийг олгодог."

Эх сурвалж: ESXi хяналтын самбар дээр виртуал машины I/O-г хэрхэн харуулах вэ

Дараах тохиолдолд Runspace ашиггүй болсон:

“Би VM-ээс маш их мэдээлэл цуглуулж, шаардлагатай үед шинэ өгөгдөл бичих скрипт бичихийг оролдож байна. Асуудал нь маш олон VM байдаг бөгөөд нэг машинд 5-8 секунд зарцуулагддаг.” 

Эх сурвалж: RunspacePool-тэй олон урсгалтай PowerCLI

Энд танд Get-View хэрэгтэй болно, үүн рүү шилжье. 

Хоёр дахь шат: Get-View

Get-View яагаад хэрэгтэй болохыг ойлгохын тулд командлетууд хэрхэн ажилладагийг санах нь зүйтэй. 

API лавлах номуудыг судалж, дараагийн дугуйг шинээр зохион бүтээх шаардлагагүйгээр мэдээллийг хялбархан олж авахад Cmdlet-ууд хэрэгтэй. Хуучин цагт зуу эсвэл хоёр мөр код авдаг байсан бол PowerShell нь танд нэг командын тусламжтайгаар үүнийг хийх боломжийг олгодог. Бид энэ тав тухыг хурдтайгаар төлдөг. Комдлетууд дотроо ямар ч ид шид байхгүй: ижил скрипт, гэхдээ доод түвшинд, нарлаг Энэтхэгийн мастерын чадварлаг гараар бичсэн.

Одоо Get-View-тэй харьцуулахын тулд Get-VM командыг авч үзье: энэ нь виртуал машин руу нэвтэрч, нийлмэл объектыг буцаана, өөрөөр хэлбэл VMHost, Datastore гэх мэт бусад холбогдох объектуудыг хавсаргана.  

Оруулсан Get-View нь буцаж ирсэн объектод шаардлагагүй зүйл нэмэхгүй. Түүнээс гадна, энэ нь бидэнд ямар мэдээлэл хэрэгтэйг нарийн зааж өгөх боломжийг олгодог бөгөөд энэ нь гаралтын объектыг хөнгөвчлөх болно. Ерөнхийдөө Windows Server болон Hyper-V дээр Get-WMIObject команд нь шууд аналог юм - санаа нь яг ижил юм.

Get-View нь цэгийн объектууд дээр ердийн үйлдэл хийхэд тохиромжгүй байдаг. Харин мянга, арван мянган объектын тухайд үнэ байхгүй.

Та VMware блогоос илүү ихийг уншиж болно: Get-View програмын танилцуулга

Одоо би танд бодит хэрэг ашиглан бүх зүйлийг харуулах болно. 

VM-г буулгах скрипт бичиж байна

Нэг өдөр манай хамтрагч надаас зохиолоо оновчтой болгохыг хүссэн. Даалгавар нь нийтлэг ажил юм: давхардсан cloud.uuid параметр бүхий бүх VM-г олох (тиймээ, vCloud Director дээр VM-г клон хийх үед энэ боломжтой). 

Оюун санаанд орж ирэх тодорхой шийдэл нь:

  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 секунд бараг 10к VM боловсруулах үед. Урамшуулал бол шүүлтүүр байхгүй, үр дүнг гараар эрэмбэлэх хэрэгцээ юм. Мэдээжийн хэрэг, скрипт нь оновчтой болгохыг шаарддаг.

Runspaces нь vCenter-ээс нэгэн зэрэг хост хэмжигдэхүүн авах эсвэл хэдэн арван мянган объектыг боловсруулах шаардлагатай үед аврах ажилд хамгийн түрүүнд ирдэг. Энэ арга юу авчрахыг харцгаая.

Эхний хурдыг асаана уу: 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 $_
           }
       }
   }

Одоо Runspace Pools-ээр дамжуулан олон урсгалыг хэрэгжүүлье.  

Алгоритм дараах байдалтай байна.

  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

Юу нь болохгүй байгааг олж мэдье.
Юуны өмнө Get-VM командыг ажиллуулахад удаан хугацаа шаардагдана.
Хоёрдугаарт, 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 руу очно уу. Энэ нь нарийн төвөгтэй объектуудтай харьцдаг тул хурдан биш юм. Логик асуулт гарч ирнэ: яагаад бидэнд VM-ийн нэр, түүний төлөв байдал, зальтай шинж чанарын үнэ цэнэ хэрэгтэй байхад энэ тохиолдолд бидэнд нэмэлт мэдээлэл, аймшигтай PSObject хэрэгтэй байна вэ?  

Үүнээс гадна Get-AdvancedOptions хэлбэрийн саадыг скриптээс хассан. Хэлэлцүүлгийг дамжуулахдаа squat thread дээр удаан даалгаврыг зэрэгцүүлэх шаардлагагүй болсон тул Runspace Pools-г ашиглах нь одоо хэтэрхий хэцүү мэт санагдаж байна. Энэ хэрэгсэл нь сайн, гэхдээ энэ тохиолдолд биш. 

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 секунд бараг 10к объектын хувьд хүссэн нөхцөлөөр шүүнэ. Агуу их!

Оронд дүгнэлтийг

Зөвшөөрөгдөх үр дүн нь багажийн сонголтоос шууд хамаарна. Үүнд хүрэхийн тулд яг юуг сонгох ёстойг тодорхой хэлэхэд хэцүү байдаг. Скриптийг хурдасгах жагсаалтад орсон аргууд бүр нь хэрэглэх боломжийнхоо хүрээнд сайн байдаг. Энэ нийтлэл нь таны дэд бүтцийн процессын автоматжуулалт, оновчлолын үндсийг ойлгох хүнд хэцүү ажилд тусална гэж найдаж байна.

Жич: Зохиогч нийтлэлийг бэлтгэхэд тусалж, дэмжсэн нийгэмлэгийн бүх гишүүдэд талархаж байна. Сарвуутай хүмүүс хүртэл. Хөлгүй хүмүүс ч гэсэн боа хуяг шиг.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх