Кастомизация гостевых ОС
Описание методов модификации
Итак, чтобы модифицировать средствами хоста виртуализации параметры гостевой ОС, необходимо каким-либо образом ей передать некую команду, которая должна вы-полниться в ее среде. Наиболее простой способ – исполь-зование штатных средств, в качестве таковых обычно вы-ступают средства интеграции, установленные в гостевой ОС. Анализ показывает, что это возможно только при ис-пользовании платформы виртуализации VMware, при ус-ловии, что в гостевой ОС установлены средства интегра-ции – VMware Tools. Данный способ действительно прост и удобен, не предполагает каких-либо трудностей при реа-лизации, и пример действий будет приведен в конце статьи для сравнения. Однако по причине указанных выше ограни-чений – имеющаяся платформа виртуализации VMware и на-личие установленных VMware Tools – часто мы вынуждены прибегать к другому способу.
Второй способ носит более изощренный характер и за-ключается в монтировании виртуального диска ВМ в среде ОС хоста, модификации скриптов инициализации и запус-ке виртуальной машины с выполнением подготовленных скриптов. Детальный список действий и используемые средства будут определяться типом платформы виртуа-лизации и типом гостевой ОС, общими будут следующие шаги.
> Монтирование виртуального диска ВМ. Средства хоста должны позволять выполнение такой операции, должны присутствовать необходимые драйверы и утили-ты. Также на этом этапе определяется местоположение скриптов инициализации, поскольку виртуальный диск может содержать более одного раздела, и заранее неиз-вестно, какой именно раздел является системным.
> Модификация скриптов инициализации. Для реализа-ции этого этапа необходима поддержка файловой сис-темы дисков гостевой ОС в среде хоста виртуализации. Модифицированный скрипт должен обеспечить одно-кратность выполнения кода и остановку гостевой ОС после выполнения скрипта. Этап завершается размонти-рованием виртуального диска.
> Старт ВМ с выполнением подготовленных скриптов.
Результатом этого этапа будет неактивная ВМ, парамет-ры гостевой ОС которой изменены согласно намеченно-му плану.
> Опциональный этап – создание снимка ВМ в случае не-обходимости.
Проверка на практике. Подготовительный этап
Далее в качестве конкретного примера рассмотрим автоматизацию импорта и модификацию параметров сетевого адаптера одного из оценочных образов ОС Windows, предоставляемых фирмой Microsoft.
Для тестов удобно выбрать образ минимального объема – Windows Server 2008 R2 Enterprise Edition x64 (Базовая версия). В качестве платформы виртуализации выберем Windows Server 2008 R2, поскольку это позволит наиболее полно проиллюстрировать все возникающие задачи и их ре-шения.
Для выбранного образа и платформы виртуализации логично использовать Windows PowerShell в качестве языка сценариев. К сожалению, в Windows PowerShell из состава Windows Server 2008 R2 отсутствуют командлеты управления виртуальной средой, поэтому воспользуемся сторон-ним свободно распространяемым решением – модулем pshyperv, доступным на сайте CodePlex. Загруженный модуль необходимо установить в соответствии с прилагае-мыми инструкциями.
Для удобства представления тестовый скрипт разчленен на отдельные части в соответствии с описанными ранее этапами.
Первый фрагмент (см. листинг 1) выполняет импорт ВМ и монтирование виртуального жесткого диска. Для им-порта и монтирования используются командлеты модуля pshyperv, поэтому в начале скрипта предусмотрена про-верка установки данного модуля, а также проверка наличия и корректности аргументов скрипта. В качестве аргумента необходимо предоставить путь к папке с файлами ВМ. По-скольку заранее неизвестно, на каком из разделов вирту-ального жесткого диска расположен системный диск ОС, в скрипте выполняется поиск системного раздела среди вновь смонтированных томов по критерию максимального объема. В реальных условиях, возможно, понадобится ис-пользовать более значимые критерии, например, имя тома, либо наличие определенных элементов (например, каталога %systemroot%) в файловой структуре. Завершается данный фрагмент присвоением переменной значения, соответству-ющего системному диску гостевой ОС. Дополнительные пояснения представлены в комментариях в листинге скрипта.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
Листинг 1 # Проверка аргумента if (-not ($args) -or ($args).count -gt 1) { Write-host "Usage: AutoDeploy.ps1 ↵ <drive:\virtualmachinefolder> " Write-host " where 'virtualmachinefolder' ↵ - folder with virtulal machine files config.xml." Exit } # Проверка установки модуля pshyperv if (-not(Get-Module hyperv)) {import-module hyperv} if (-not(Get-Module hyperv)) { Write-Host "Install module 'HyperV'" Exit} #Проверка корректности аргумента – наличие каталога $vmPath = $args[0] if (Test-Path $vmPath){ $VMFolder = Get-Item -Path $vmPath\ } else { Write-Host "Virtual Machine Folder not found" Exit } if(-not ($VMFolder.PSisContainer)) { Write-Host "Virtual Machine's item is not folder." Exit } $savedir=$pwd #Импорт ВМ Write-Host "Import VM in folder " $VMFolder.FullName $Exists = Get-VM -name ([string] $VMFolder.Name) ↵ -ErrorAction SilentlyContinue If (!($Exists)){ Write-Host ("Importing virtual machine : ") -noNewLine Write-Host ([string] $VMFolder.Name) -foreground Green Write-Host Virtual Machine path: ↵ ([string] $VMFolder.FullName) Import-VM -path ([string] $VMFolder.FullName) -Wait Write-Host } Else { Write-Host ('Virtual machine "') -noNewLine Write-Host ([string] $VMFolder.Name) -noNewLine ↵ -foreground Yellow Write-Host ('" does already exist.') } #Создание виртуального сетевого коммутатора и подключение #к нему виртуального сетевого адаптера $tswitch = Get-VMSwitch -VirtualSwitchName "testswitch" if (-not $tswitch) { $tswitch = New-VMPrivateSwitch -VirtualSwitchName ↵ "TestSwitch" | Out-Null } Get-VM -name ([string] $VMFolder.Name) | Get-VMNIC | ↵ Set-VMNICSwitch -VirtualSwitch $tswitch.elementname #Получение файлов виртуальных дисков в каталоге $VHDs = get-childitem "$VMFolder\virtual hard disks\*.vhd" foreach ($VHD in $VHDs) { if ($vhd -and ($vhd.length -ne 0)) { Write-Host "Mounting for modification VHD " ↵ $VHD.FullName #Монтирование виртуального диска и поиск #системного раздела $volbefore = gwmi -Namespace root\cimv2 ↵ -Class win32_volume Mount-VHD -VHDPaths $VHD.FullName | Out-Null $volafter = gwmi -Namespace root\cimv2 ↵ -Class win32_volume # Поиск системного тома (критерий – максимальный # размер, вновь подключенный диск) $volsel = $null foreach ($vol in $volafter) { $cont = $false foreach ($volb in $volbefore) { if ($volb.deviceid -eq $vol.deviceid){ $cont = $true } } if (-not ($cont)) { if ($volsel) { if ($vol.capacity -gt $volsel.capacity) { $volsel = $vol } } else { $volsel = $vol } } } $sysdrive=$volsel.driveletter |
Проверка на практике. Основные действия
В следующем фрагменте (см. листинг 2) выполняется модификация стартовых скриптов, которые при запуске ВМ про-изведут необходимые изменения.
В качестве скриптов инициализации выбраны стартап-скрипты групповых политик Windows. Это возможно для серверных ОС Windows, а также для профессиональных и корпоративных редакций клиентских Windows. Для других редакций клиентских систем Windows также возможна ор-ганизация стартап-скриптов, сделать это можно путем нас-тройки автоматической регистрации пользователя и моди-фикации логин-скрипта для этого пользователя. Реализация этого варианта выполняется без особого труда на основе представленных листингов.
Предлагаемый вариант имеет некоторые особенности, связанные с тем, что при монтировании диска отсутствует активная среда гостевой ОС, поэтому нет возможности кон-фигурировать стартовые скрипты штатными средствами. Проведенный анализ позволил сделать вывод, что редакти-рование стартовых скриптов групповых политик и задание связанных с ними конфигурационных параметров возможно выполнить путем прямого редактирования файлов в файло-вой системе виртуального диска и редактирования ключей реестра гостевой ОС.
В представленном фрагменте для организации стартовых скриптов в первую очередь создается структура папок в файловой системе системного диска, затем создаются необходимые конфигурационные файлы. После этого соз-дается стартовый скрипт групповой политики, в котором собственно и предусмотрено выполнение команд модифи-кации параметров активного сетевого адаптера.
Далее для того, чтобы данная процедура выполнилась только один раз, создается скрипт выключения, в котором стартовый скрипт удаляется из конфигурационных файлов. Кроме этого, необходимо модифицировать ключи реестра гостевой ОС для задействования клиентских расширений (CSE) групповых политик, обеспечивающих выполнение стартовых скриптов.
Завершается фрагмент размонтированием виртуально-го жесткого диска.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
Листинг 2. if ($sysdrive) { Write-Host "Drive letter for SysDrive is " $sysdrive Write-Host "This volume on the one of partitions ↵ of VHD " $VHD.FullName if (Test-Path $sysdrive\windows\system32) { #Создание структуры папок для стартовых скриптов #и конфигурационных файлов new-item $sysdrive\windows\system32\grouppolicy ↵ -itemtype directory -ErrorAction ↵ SilentlyContinue | Out-Null new-item $sysdrive\windows\system32\grouppolicy\ ↵ machine -itemtype directory -ErrorAction ↵ SilentlyContinue | Out-Null new-item $sysdrive\windows\system32\grouppolicy\ ↵ user -itemtype directory -ErrorAction ↵ SilentlyContinue | Out-Null new-item $sysdrive\windows\system32\grouppolicy\ ↵ machine\scripts -itemtype directory↵ -ErrorAction SilentlyContinue | Out-Null new-item $sysdrive\windows\system32\grouppolicy\ ↵ machine\scripts\startup –itemtype ↵ directory -ErrorAction SilentlyContinue ↵ | Out-Null new-item $sysdrive\windows\system32\grouppolicy\ ↵ machine\scripts\shutdown -itemtype ↵ directory -ErrorAction SilentlyContinue | ↵ Out-Null #Создание конфигурационных файлов групповых политик $StrGptIni = '[General]' + "`r`n" + ↵ 'gPCMachineExtensionNames=[ ↵ {42B5FAAE-6536-11D2-AE5A-0000F87571E3} ↵ {40B6664F-4972-11D1-A7CA-0000F87571E3}]' ↵ + "`r`n" + 'Version=5' out-file -filepath "$sysdrive\windows\system32\ ↵ grouppolicy\gpt.ini" -InputObject ↵ $StrGptIni -encoding ascii | Out-Null $StrScriptsIni= "`r`n" + '[Startup]' + "`r`n" + ↵ '0CmdLine=c:\windows\system32\ ↵ grouppolicy\machine\scripts\startup\ ↵ startup.cmd' + "`r`n" + '0Parameters=' ↵ + "`r`n" + '[Shutdown]' + "`r`n" + ↵ '0CmdLine=c:\windows\system32\ ↵ grouppolicy\machine\scripts\shutdown\ ↵ remove.cmd' + "`r`n" + '0Parameters=' out-file -filepath "$sysdrive\windows\system32\ ↵ grouppolicy\machine\scripts\scripts.ini" ↵ -inputobject $StrScriptsIni -encoding ↵ ascii | Out-Null #Создание стартового скрипта $StrStartupCmd = 'For /f "skip=3 tokens=4*" ↵ %%a In (' + "'NetSh Interface IPv4 Show ↵ Interfaces'" + ') Do (Call ↵ :UseNetworkAdapter %%a "%%b") ' + "`r`n" ↵ + 'c:\windows\system32\shutdown.exe -f ↵ -s -t 30' + "`r`n" + 'Exit /B' + "`r`n" ↵ + ':UseNetworkAdapter' + "`r`n" + 'If ↵ %1==connected (@if %2 neq "Loopback ↵ Pseudo-Interface 1" ( netsh int ipv4 ↵ set addr %2 static 10.10.0.33 ↵ 255.255.0.0 10.10.0.1))' + "`r`n" + ↵ 'Exit /B' + "`r`n" out-file –filepath "$sysdrive\windows\system32\ ↵ grouppolicy\machine\scripts\startup\ ↵ startup.cmd" -InputObject ↵ $StrStartupCmd -encoding ascii | Out-Null #Создание скрипта выключения гостевой ОС $StrRemoveCmd = 'del /q c:\windows\system32\ ↵ grouppolicy\machine\scripts\startup\ ↵ startup.cmd' + "`r`n" + 'del /q ↵ c:\windows\system32\grouppolicy\machine\ ↵ scripts\scripts.ini' + "`r`n" + 'del /q ↵ c:\windows\system32\grouppolicy\gpt.ini' ↵ + "`r`n" + 'c:\windows\system32\reg.exe ↵ delete "HKLM\software\microsoft\windows\ ↵ currentversion\group policy\Status\ ↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A- ↵ 0000F87571E3}" /f '+ "`r`n" + 'del /q ↵ c:\windows\system32\grouppolicy\machine\ ↵ scripts\shutdown\remove.cmd' out-file -filepath "$sysdrive\windows\system32\ ↵ grouppolicy\machine\scripts\shutdown\ ↵ remove.cmd" -InputObject $StrRemoveCmd ↵ -encoding ascii | Out-Null #Модификация ключей реестра для задействования CSE cd C:\Windows\System32 C:\Windows\System32\reg.exe load HKLM\onvhd ↵ $sysdrive\Windows\System32\config\ ↵ SOFTWARE | out-null reg add "HKLM\onvhd\microsoft\windows\ ↵ currentversion\group policy\Status\↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵ 0000F87571E3}" /f | out-null reg add "HKLM\onvhd\microsoft\windows\ ↵ currentversion\group policy\Status\↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A- ↵ 0000F87571E3}" /v ForceRefreshFG ↵ /t REG_DWORD /d 0 /f | out-null reg add "HKLM\onvhd\microsoft\windows\ ↵ currentversion\group policy\Status\ ↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵ 0000F87571E3}" /v LastPolicyTime ↵ /t REG_DWORD /d 0 /f | out-null reg add "HKLM\onvhd\microsoft\windows\ ↵ currentversion\group policy\Status\ ↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵ 0000F87571E3}" /v PrevRsopLogging ↵ /t REG_DWORD /d 0 /f | out-null reg add "HKLM\onvhd\microsoft\windows\ ↵ currentversion\group policy\Status\ ↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵ 0000F87571E3}" /v PrevSlowLink ↵ /t REG_DWORD /d 0 /f | out-null reg add "HKLM\onvhd\microsoft\windows\ ↵ currentversion\group policy\Status\ ↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵ 0000F87571E3}" /v RsopStatus ↵ /t REG_DWORD /d 0 /f | out-null reg add "HKLM\onvhd\microsoft\windows\ ↵ currentversion\group policy\Status\ ↵ GPExtensions\{42B5FAAE-6536-11D2-AE5A-↵ 0000F87571E3}" /v Status /t REG_DWORD ↵ /d 0 /f | out-null reg unload HKLM\onvhd | out-null } } else { Write-Host "Drive letter not assigned for " $VHD.FullName } Dismount-VHD -VHDPaths $VHD.FullName -Force } } cd $saveDir |
Проверка на практике. Исполнение
Наконец остается запустить ВМ, дождаться завершения ее работы и создать снимок ВМ. Эти действия выполняет оставшийся фрагмент скрипта (см. листинг 3).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
Листинг 3. #Запуск ВМ $Exists = get-vm -name ([string] $VMFolder.Name) ↵ -ErrorAction SilentlyContinue If ($Exists){ Write-Host ("Starting virtual machine : ") -noNewLine Write-Host ([string] $VMFolder.Name) -foreground Green $exists | start-vm -wait #Ожидание завершения работы ВМ с проверкой 6-минутного #тайм-аута $checktime = (get-date).addminutes(6) while ((($exists | Get-VMState).enabledstate ↵ -eq "running") ↵ -and ((get-date).compareto($checktime) -lt 0)){ start-sleep 5 } #Если ВМ еще работает, запускается принудительное #выключение if (($exists | Get-VMState).enabledstate -eq "running") { Write-Host "Forced shutdown VM " $exist.elementname $exists | Invoke-VMShutdown ↵ -force -ShutdownTimeOut 2 } while (-not (($exists | Get-VMState).enabledstate ↵ -eq "stopped")){ start-sleep 1 } if (($exists | Get-VMState).enabledstate -eq "stopped") { # Создание снимка виртуальной машины Write-Host "Create snapshot for virtual machine " ↵ $exists.elementname $exists | New-VMSnapshot -Wait -Force -Note ↵ "StartImage" | Out-Null } Write-Host } Else { Write-Host ('Virtual machine "') -noNewLine Write-Host ([string] $DriveDstFolder.Name) ↵ -noNewLine -foreground magenta Write-Host ('" does not exist. Skip.') } |
Для выполнения скрипта необходимо распаковать ВМ в выбранную папку и запустить скрипт с аргументом, указывающим на путь к этой папке. Результатом выполнения скрипта будет подготовленная ВМ в выключенном состо-янии, с модифицированными параметрами гостевой ОС и снимком состояния.
То же самое штатными средствами
Для сравнения приведу пример управления гостевой ОС штатными средствами хоста виртуализации, что возможно в среде VMware при установленных средствах интеграции VMware Tools и использовании в качестве клиента vSphere PowerCLI . При таких условиях часть скрипта, выполняю-щего модификацию параметров гостевой ОС виртуальной машины VMname будет представлена строками листинга 4.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Листинг 4. #Подготовка содержимого командного файла $StrCmd = 'For /f "skip=3 tokens=4*" %%a In ↵ (' + "'NetSh Interface IPv4 Show Interfaces'" ↵ + ') Do (Call :UseNetworkAdapter %%a "%%b") ' + ↵ "`r`n" + 'c:\windows\system32\shutdown.exe -f -s ↵ -t 30' + "`r`n" + 'Exit /B' + "`r`n" + ↵ ':UseNetworkAdapter' + "`r`n" + 'If %1==connected ↵ (@if %2 neq "Loopback Pseudo-Interface 1" ↵ ( netsh int ipv4 set addr %2 static 10.10.0.33 ↵ 255.255.0.0 10.10.0.1))' + "`r`n" + 'Exit /B' + ↵ "`r`n" # Сохранение файла в файловой системе хоста виртуализации out-file –filepath "c:\changeip.cmd" -InputObject $StrCmd ↵ -encoding ascii | Out-Null #Копирование файла в гостевую операционную систему Copy-VMGuestFile -Source c:\changeip.cmd -Destination ↵ c:\temp\ -VM "VMname" -LocalToGuest -GuestUser ↵ Administrator -GuestPassword Pa$$w0rd #Выполнение подготовленного командного файла Get-VM "VMname" | Invoke-VMscript -ScriptText ↵ "c:\temp\changeip.cmd" -ScriptType Bat -GuestUser ↵ Administrator -GuestPassword Pa$$w0rd |
В этом случае нет нужды манипулировать стартовыми скриптами, поскольку команды установки параметров выполняются непосредственно в среде гостевой ОС, при работающей ВМ. Разумеется, что в таком варианте может потребоваться перезагрузка гостевой ОС, если этого требуют выполненные изменения.
Дополнительно отмечу, что, если в качестве гостевой ОС используется Windows Server 2012 R2, скрипт примет еще более простой вид, представленный на листинге 5. (Подраз-умевается, что в гостевой ОС имеется только один активный сетевой адаптер.)
1 2 |
Листинг 5. Get-VM "VMname" | Invoke-VMscript -ScriptText 'New-NetIPAddress -InterfaceIndex ((Get-NetAdapter).ifindex) -IPAddress 10.10.0.33 -PrefixLength 16’ -GuestUser Administrator -GuestPassword Pa$$w0rd |
Можно предположить, что в очередных версиях платформы виртуализации Hyper-V будет реализован аналогичный спо-соб управления. Об этом говорит то, что роль виртуализации ОС Windows Server 2012 R2 поддерживает копирование файлов в гостевую ОС (но не из гостевой ОС на хост виртуализации) с помощью командлета Copy-VMFile.
Если клиентское ПО продолжит развитие в этом направлении и будет реализовано не только копирование файлов, но и выполнение произвольных команд, описанные в дан-ной статье манипуляции потеряют актуальность в контексте платформ виртуализации. В настоящее же время описанный способ управления может послужить примером для реализации различных сценариев автоматизации виртуальной инфраструктуры.
Источник «Системный администратор» №156, 2015
Сопровождение систем виртуализации, установка и настройка, [email protected]