Loading

Автоматическое разворачивание виртуальных машин с помощью шаблона в VMware

09.10.2015 - 13:34

Сразу сделаю громкое заявление, я ленивый, очень, страшно! И поэтому на работе, столкнувшись с необходимостью разворачивания ВМ с шаблона, по 12-20 в неделю, я задумался написать скрипт. Признаюсь, мои коллеги уже имели скрипт в PowerShell, который это делает, но он был на столько... эм... не знаю, как сказать, в общем, нужно было информацию по каждой ВМ вписывать вручную, диски не мапятся, сетевые карты не добавляются, с ядерностью проца - траблы, и т.д.
Решил я его переделать, автоматизировать, так сказать )))
Для начала, нужно установить модуль PowerShell для VMware - PowerCLI.
Здесь есть полезная инфа, как и чего.
Доступные командлеты с описанием и примерами
Обратите внимание, что существуют ограничения для командлетов "в релизе", некоторые из них работают ТОЛЬКО в 4й версии VSphere, другие - только в 5й. Скрипт, который предоставлен ниже, работает только с 5й и выше версиями, так как в нём используются соответствующие командлеты.
Скрипт скрипт использует сессии к серверу, где установлен VMware VCenter. Скрипт использует CSV файл для работы, так как названия серверов, датацентров, пути к определённой папке, названия шаблонов - всегда будет где-то ошибка.
Структура CSV файла выглядит так:

  • VMName - Имя, которое должно быть присвоено ВМ.
  • VMTemplateName - Имя шаблона, с которого будет разворачиваться ВМ.
  • VCenterHostName - Имя сервера, на котором установлен VCenter, указан потому, что на каждый датацентр (физический, а не VMware) существует свой VCenter сервер, а в файле можно указать ВМ для разных датацентров.
  • VSphereCluster - Кластер VSphere, к которому проводится подключение после подключения к VCenter серверу.
  • VSphereResPool - ресурсный пул для ВМ, если ресурсы датацентра поделены на несколько "ярусов", например, по производительности платформы в случае использования разных серверов (старых и новых) или дисков - SSD или SATA (для БД это критично).
  • VSphereDataStore - датастор для ВМ, указывается хранилище данных, где "физически" будет располагаться ВМ.
  • VSphereFolder - каталог, в котором должна находиться ВМ. Тут путь выглядит в формате "DC2-Cloud PROD Tier|Wintel TEST & DEV|Project BI", так как в VMware у нас может быть несколько каталогов с одинаковым именем, только по разным адресам. К сожалению, указать полный путь к нужному каталогу не получится, параметр ввода каталога - имя, либо ID, который у всех каталогов уникальный. Для определения этого ID был написана функция, которая ищет необходимый нам каталог по заданному адресу (был подан в отдельной статье ранее). Разделение каталогов в строке пути - "|", так как "\" - служебный символ в PowerShell и его нужно экранировать, а это дополнительное баловство с синтаксисом и повышение вероятности ошибки.
  • VMSocket - Кол-во сокетов для ВМ.
  • VMCore - Кол-во ядер для ВМ.
  • VMRAM - тут понятно, но всё же, кол-во ОЗУ в ГБ.
  • VMHDD - если указано число, отличное от нуля - добавляет ещё один диск (не для системы) с указанным объёмом, так как в настройках шаблона уже должен быть указан системный диск и его объём.
  • VMNetworks - указывает VLAN-ы сетевых карт. Подаётся в формате "387|388|389", где каждое число - это уникальное значение VLAN-a, так как имя VLAN-а создаётся согласно определённому шаблону, например "DC2N-MGMT-VLAN387" или "DC2N-PROD-VLAN389". Разделители - "|", для того, чтобы скрипт понимал кол-во сетевых карт и куда их подключить. Плодить дополнительные столбцы в CSV при отутствии ограничения максимального кол-ва сетевых карт - неправильно.
  • OSCustomizationSpec - Спецификация кастомизации - политика разворачивания шаблона, в которой указаны основные настройки ВМ после установки, например, размер системного диска, кол-во COM-портов :CRAZY: или генерирование нового SID-а для ВМ.

По ходу скрипта будут сделаны замечания, как/почему это сделано.

#Блок определения параметров, запуск скрипта из PowerShell подразумевает указания CSV файла со всей информацией. Может быть удалён и указан статически.
param
(
    [string]$csvFile = $(throw "-csv file path is required.")
)
# статическое указание файла конфигурации (закомментировано).
#$csvFile = "D:\Script\VMDeploy.csv"
# проверка на существование файла, если его нет (в имени ошибка) - прерывание выполнения скрипта
if(Test-Path -Path $csvFile)
{
    $VMCSV = Import-Csv -Path $csvFile
}
else
{
    Write-Host "CSV file not found"
    exit
}

# выполняем действия для каждой ВМ:
foreach($VMArray in $VMCSV) # for each line in CSV
{
# начало блока скрипта, который позже будет выслан на сервер VCenter
    $script = {
       
        param($VMArray) # считывание параметров CSV файла
# проверка возможности загрузки модуля PowerCLI, в случае ошибки - переход к следующей ВМ
        Get-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -ErrorVariable PSError
        if($PSError)
        {
            Add-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -ErrorVariable SnapInError
            if($SnapInError)
            {
                "VMware.VimAutomation.Core could not be loaded by the reason $SnapInError"
                Exit
            }
        }
# установка конфигурации работы PowerCLI, необходимая вещь! :JOKINGLY:
        Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -InvalidCertificateAction Ignore -DisplayDeprecationWarnings:$false -Confirm:$false
    #подключение к VCenter серверу
        $vSphere_Connection = Connect-VIServer -Server $VMArray[0].VCenterHostName
        "Connection to $vSphere_Connection has been established."
# проверка на существование необходимой ВМ, чтобы не пытаться создать с уже занятым именем. В случае наличия ВМ - переход к созданию новой ВМ.
        if(Get-VM -Name $VMArray[0].VMName -ErrorAction SilentlyContinue -ErrorVariable CheckVmExists)
        {
            $VMArray[0].VMName + " already exists."
        }
# если нет ВМ с заданым именем:
        else
        {
# подключаемся к кластеру
            $vSphereCluster = Get-Cluster -Name $VMArray[0].VSphereCluster # get the necessary cluster
            "$vSphereCluster connected."
# получаем данные ресурсного пула, чтобы потом его указать при создании ВМ
            $vSphereResPool = Get-ResourcePool -Name $VMArray[0].VSphereResPool -Location $vSphereCluster # get the necessary resource pool
            "$vSphereResPool state."
# указываем путь к каталогу ВМ и начинаем поиск указанного каталога, в переменную записывается ИД необходимого каталога. В случае, если данный каталог не найден - указывается ИД корневого каталога, ВМ можно перенести вручную.
            $Path = ($VMArray[0].VSphereFolder).Split("|") # split the folder pass into array to find the final folder
            $vSphere_Datacenter = Get-Inventory -Location (Get-Folder -Name Datacenters -NoRecursion) -NoRecursion # Start from the root - datacenter
            $VMFolder = Get-Inventory -Location $vSphere_Datacenter -NoRecursion | where {$_.type -eq "VM"} # get all folders in datacenter and capture the folder for VMs
# поиск каталога
            for($i=0; $i -lt $Path.Count; $i++) # for each folder in the path - check if exist the next hop folder
            {
                if((Get-Inventory -Location $VMFolder -NoRecursion | select -ExpandProperty Name) -contains (($Path[$i]).Trim()))
                {
                    $VMFolder = Get-Inventory -Name $Path[$i] -Location $VMFolder -NoRecursion
                }
# если каталог не найден
                else
                {
                    $VMFolder = Get-Inventory -Location $vSphere_Datacenter -NoRecursion | where {$_.type -eq "VM"}
                    "Break VMFolder " + $VMFolder
                    break
                }
            }
# проверка на доступность хранилища, куда будет "положена" или "покладена" ВМ :CRAZY: если датастор не доступен - переход к следующей ВМ
            if ((Get-Datastore -Name $VMArray[0].VSphereDataStore).State -ne "Available")
            {
                "There is no Datastore name "+ $VMArray[0].VSphereDataStore + " to accomodate this Vm: "+ $VMArray[0].VMName
            }
# если датастор доступен - создание ВМ с указанием почти всех параметров. Некоторые параметры используются после создания ВМ.
            else
            {
                New-VM -Name $VMArray[0].VMName -Location $VMFolder -Template $VMArray[0].VMTemplateName -ResourcePool $vSphereCluster -DataStore $VMArray[0].VSphereDataStore -OSCustomizationSpec $VMArray[0].OSCustomizationSpec -ErrorVariable VMError
                if($VMError)
                {
# в случае ошибки при создании - вывести ошибку
                    $VMError
                }
                else
                {
# если ВМ создана, то перемещаем ВМ в ресоурс пул, который нам указан. У VMware есть проблема, при создании они просят указать кластер, но называют это "ресоурс пул", а параметра для ресоурс пула нет, поэтому ВМ создаётся в ресоурс пуле по умолчанию, а потом - переносится в необходимый.
                    $VMArray[0].VMName + " moving to " + $VMArray[0].VSphereResPool
                    Move-VM -VM $VMArray[0].VMName -Destination $VMArray[0].VSphereResPool
# изменение ОЗУ
                    "RAM: " + ([int]$VMArray[0].VMRAM) + " CPU " + ([int]$VMArray[0].VMSocket)
                    Set-VM -VM $VMArray[0].VMName -MemoryGB ([int]$VMArray[0].VMRAM) -NumCpu ([int]$VMArray[0].VMSocket) -Confirm:$false
# VMware из PowerShell позволяет только изменить кол-во сокетов, а кол-во ядер - нет. Поэтому, пришлось делать вручную
                    "Cores per socket " + ([int]$VMArray[0].VMSocket)
                    $TempSpec = New-Object -Type VMware.Vim.VirtualMachineConfigSpec -Property @{"NumCoresPerSocket"=([int]$VMArray[0].VMSocket);"numCPUs"=([int]$VMArray[0].VMSocket * [int]$VMArray[0].VMCore)}
                    "numCPUs = " + ([int]$VMArray[0].VMSocket * [int]$VMArray[0].VMCore)
                    (Get-VM $VMArray[0].VMName).ExtensionData.ReconfigVM_Task($TempSpec)
#добавление жёсткого диска, в случае необходимости (если указано число больше ноля)
                    "HDD " + [int]$VMArray[0].VMHDD
                    if([int]$VMArray[0].VMHDD -ne "0")
                    {
                        New-HardDisk -VM $VMArray[0].VMName -CapacityGB ([int]$VMArray[0].VMHDD) -StorageFormat Thick
                    }
# так как мне нехотелось получать ИД созданной сетевой карты, а потом менять VLAN (там тоже свои проблемы при определении параметров командлета), я решил её просто удалить и создать новую ))))
                    Get-NetworkAdapter -VM $VMArray[0].VMName | Remove-NetworkAdapter -Confirm:$false
                    "VMNetworks " + ($VMArray[0].VMNetworks).Split("|")
# создание новых сетевых карт с подключением к необходимому VLAN-у. Нужно было бы провести проверку на существование VLAN-а, при неправильном указании имени, но лень ))) так что, смотрите в оба!
                    foreach($VLAN in (($VMArray[0].VMNetworks).Split("|")))
                    {
                        $VLAN = (Get-VirtualPortGroup | Where-Object {($_.Name -Match ("VLAN" + $VLAN))}).Name
                        "Adding VLAN: " + $VLAN
                        New-NetworkAdapter -NetworkName $VLAN -VM $VMArray[0].VMName -Type e1000
                    }
# включение сетевых карт при включении ВМ
                    "Set all NICs to Conect at Power On."
                    Get-NetworkAdapter -VM $VMArray[0].VMName | Set-NetworkAdapter -StartConnected:$true -Confirm:$false
                }
            }
        }
# отключение от VCenter сервера
        Disconnect-VIServer -Server $vSphere_Connection -Confirm:$false
       
              }
# старт удалённой сессии на VCenter сервер
    $session = New-PsSession -ComputerName $VMArray[0].VCenterHostName
# передача блока скрипта на выполнение
    Invoke-Command -Session $session -ScriptBlock $script -ArgumentList (,$VMArray)
# завершение сессии - ОБЯЗАТЕЛЬНО!
    Remove-PSSession -Session $session
}

Стоит заметить, что VSphere у каждого настроен по своему, и для Вас необходимо будет, скорее всего, менять некоторые параметры. Но сути это не меняет, ВМ может быть создана автоматически за 5 минут, либо будете кликать мышкой более 20.

Во вложении пример CSV файла и скрипт без моих комментариев :)

Особая благодарность Mateusz Skrzynski за помощь при написании скрипта.

Прикрепленный файлРазмер
DeployWinVM.zip2.56 кб
Голосов пока нет