Memorandum: True VM Cloning with vSphere PowerCLI
前回のエントリで備忘録を残した、BIOS UUID と Disk UUID をそのままにクローンする PowerCLI のスクリプトです。中身は、クローン ➡ UUID を後から再構成、という動作です。
Function TrueClone-VM {
Param(
$VM,
$Name
)
Begin {}
Process {
$OriginalBiosUuid = $VM.ExtensionData.Config.Uuid
$OriginalDevices = $VM.ExtensionData.Config.Hardware.Device
$OriginalDiskUuids = @{}
$OriginalDevices | ForEach-Object {
$OriginalDevice = $_
$DeviceType = $OriginalDevice.GetType()
If ($OriginalDevice -is [VMware.Vim.VirtualDisk]) {
$OriginalDiskUuids.Add($OriginalDevice.Key, $OriginalDevice.Backing.Uuid)
} ElseIf ($DeviceType.IsSubclassOf([VMware.Vim.VirtualEthernetCard])) {
If ("Manual" -ne $OriginalDevice.AddressType ) {
Throw "Ethernet card: " + $OriginalDevice.DeviceInfo.Label + " does not have manual MAC address."
}
}
}
$ClonedVM = New-VM -VM $VM -ResourcePool ( $VM | Get-Cluster ) -Name $Name
$ClonedDevices = $ClonedVM.ExtensionData.Config.Hardware.Device
$VmSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$VmSpec.Uuid = $OriginalBiosUuid
$ClonedDevices | ForEach-Object {
$ClonedDevice = $_
$ClonedDeviceType = $ClonedDevice.GetType()
If ($ClonedDevice -is [VMware.Vim.VirtualDisk]) {
$ClonedDevice.Backing.Uuid = $OriginalDiskUuids[$ClonedDevice.Key]
$DeviceSpec = New-Object VMware.Vim.VirtualDeviceConfigSpec
$DeviceSpec.Operation = [VMware.Vim.VirtualDeviceConfigSpecOperation]::Edit
$DeviceSpec.Device = $ClonedDevice
$VmSpec.DeviceChange += $DeviceSpec
}
}
$ClonedVM.ExtensionData.ReconfigVM_Task($VmSpec)
}
End {}
}
10-11 行目: BIOS UUID や Disk UUID は ExtensionData (一昔前の言い方をすれば View オブジェクト) にしかないため、ExtensionData 内のデータをサルベージします。ExtensionData 以下のプロパティやメソッドは vSphere Web Services SDK と一緒なので、vCenter Server に対して細部までスクリプティングを行う場合には、vSphere Web Services SDK API の習得は避けて通れない道です。
12 行目: 複数の仮想ディスクを持っている仮想マシンに対応するため Disk UUID は連想配列に格納しておきます。ここでは、そのための空の連想配列を作成しています。
13 行目: 仮想マシンのデバイスは、どんなデバイスでもフラットな構造として保持されています。仮想ディスク、仮想 NIC はもとより、キーボードやビデオカードさえ $VM.ExtensionData.Config.Device という配列にフラットに格納されています。この ForEach-Object 内部でデバイスオブジェクトの型を確認しながら、仮想ディスクの UUID を探していきます。
14 行目: 我流の ForEach-Object の記述方法なので、気持ち悪いと思われる方もいらっしゃるかも知れません。$_ は分かりにくいのでこうしてしまうのです
15 行目: 後続の行で比較するデバイス オブジェクトの型を取得します
16-17 行目: 仮想ディスクだった場合は、UUID を連想配列にデバイスの Key と共に格納します。Key がデバイスのユニークな ID となります。なお、親子関係はデバイスの ControllerKey という値で親のデバイスの Key を指定することで実現されています。また、SCSI デバイスの Unit Number はデバイスの UnitNumber で表現されます。
18-19 行目: 仮想 NIC の MAC アドレスが手動でなかった場合に、例外を投げます。後からスクリプトで固定 MAC アドレスを振ることも出来ますが、家ラボ環境ではすでに Manual にしているので、このスクリプトでは例外を出すのみとしています。なお、全ての仮想 NIC オブジェクトの親クラスである VMware.Vim.VirtualEthernetCard オブジェクトのサブクラスか否かを確認することで、条件文を短くしています。なお vCenter Orchestrator のスクリプトでは、クラス間の親子関係の情報が消えるのでこういったシンプルな記述ができません。
25 行目: 仮想マシンをクローンします。フォルダーもデータストアも指定していないので、好きなクローン先がある場合にはパラメーターを追加してください
27 行目: クローンした仮想マシンから再構成のためのデバイス情報を取得します
28-29 行目: 再構成用のパラメーターオブジェクトを作成し、まずは BIOS UUID をクローン元の仮想マシンのそれに合わせます
31-42 行目: 仮想ディスクであれば、Key の情報と一致するクローン元の Disk UUID をセットしていきます。デバイスの再構成は少々面倒で、デバイスオブジェクトを VMware.Vim.VirtualDeviceConfigSpec でラップし、Operation プロパティに変更 (Edit)、追加 (Add)、削除 (Remove) なのかを明記しなければいけません。仮想ディスクの新規作成などの場合は さらに FileOperation プロパティをセットする必要があります。
44 行目: 変更したい部分のプロパティをセットした VMware.Vim.VirtualMachineConfigSpec オブジェクトを引数として ReconfigVM_Task を実行します。VirtualMachineConfigSpec オブジェクトは、VirtualMachineConfigInfo オブジェクトと非常に似ていますが deviceChange などチョイチョイ違うプロパティを持っているので注意してください。なお、ReconfigVM_Task に渡す VirtualMachineConfigSpec オブジェクトは、変更部分のみをセットするだけでよく、変更しない部分は空の状態として問題ありません。
このスクリプトを TrueClone-VM.ps1 として保存し、以下のように実行します。
> Add-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue > . .TrueClone-VM.ps1 > Connect-VIServer -Server ${vCenter のアドレス} -User ${ユーザー名} -Password ${パスワード} > $vm = Get-VM ${VM 名} > TrueClone-VM -VM $vm -Name "trueclone"