kitchen-hyperv 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,22 +1,22 @@
1
- #
2
- # Author:: Steven Murawski <smurawski@chef.io>
3
- # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
- module Kitchen
19
- module Driver
20
- HYPERV_VERSION = '0.4.1'.freeze
21
- end
22
- end
1
+ #
2
+ # Author:: Steven Murawski <smurawski@chef.io>
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ module Kitchen
19
+ module Driver
20
+ HYPERV_VERSION = '0.5.0'.freeze
21
+ end
22
+ end
@@ -1,235 +1,236 @@
1
- #
2
- # Author:: Steven Murawski <smurawski@chef.io>
3
- # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
- require 'mixlib/shellout'
19
- require 'fileutils'
20
- require 'JSON'
21
-
22
- module Kitchen
23
- module Driver
24
- module PowerShellScripts
25
- def encode_command(script)
26
- encoded_script = script.encode('UTF-16LE', 'UTF-8')
27
- Base64.strict_encode64(encoded_script)
28
- end
29
-
30
- def is_64bit?
31
- os_arch = ENV['PROCESSOR_ARCHITEW6432'] || ENV['PROCESSOR_ARCHITECTURE']
32
- ruby_arch = ['foo'].pack('p').size == 4 ? 32 : 64
33
- os_arch == 'AMD64' && ruby_arch == 64
34
- end
35
-
36
- def is_32bit?
37
- os_arch = ENV['PROCESSOR_ARCHITEW6432'] || ENV['PROCESSOR_ARCHITECTURE']
38
- ruby_arch = ['foo'].pack('p').size == 4 ? 32 : 64
39
- os_arch != 'AMD64' && ruby_arch == 32
40
- end
41
-
42
- def powershell_64_bit
43
- if is_64bit? || is_32bit?
44
- 'c:\windows\system32\windowspowershell\v1.0\powershell.exe'
45
- else
46
- 'c:\windows\sysnative\windowspowershell\v1.0\powershell.exe'
47
- end
48
- end
49
-
50
- def wrap_command(script)
51
- base_script_path = File.join(File.dirname(__FILE__), '/../../../support/hyperv.ps1')
52
- debug("Loading functions from #{base_script_path}")
53
- new_script = [ ". #{base_script_path}", "#{script}" ].join(";\n")
54
- debug("Wrapped script: #{new_script}")
55
- "#{powershell_64_bit} -noprofile -executionpolicy bypass" \
56
- " -encodedcommand #{encode_command new_script} -outputformat Text"
57
- end
58
-
59
- # Convenience method to run a powershell command locally.
60
- #
61
- # @param cmd [String] command to run locally
62
- # @param options [Hash] options hash
63
- # @see Kitchen::ShellOut.run_command
64
- # @api private
65
- def run_ps(cmd, options = {})
66
- cmd = "echo #{cmd}" if config[:dry_run]
67
- debug('Preparing to run: ')
68
- debug(" #{cmd}")
69
- wrapped_command = wrap_command cmd
70
- execute_command wrapped_command, options
71
- end
72
-
73
- def execute_command(cmd, options = {})
74
- debug("#Local Command BEGIN (#{cmd})")
75
- sh = Mixlib::ShellOut.new(cmd, options)
76
- sh.run_command
77
- debug("Local Command END #{Util.duration(sh.execution_time)}")
78
- raise "Failed: #{sh.stderr}" if sh.error?
79
- stdout = sanitize_stdout(sh.stdout)
80
- JSON.parse(stdout) if stdout.length > 2
81
- end
82
-
83
- def sanitize_stdout(stdout)
84
- stdout.split("\n").select { |s| !s.start_with?("PS") }.join("\n")
85
- end
86
-
87
- def new_differencing_disk_ps
88
- <<-DIFF
89
-
90
- New-DifferencingDisk -Path "#{differencing_disk_path}" -ParentPath "#{parent_vhd_path}"
91
- DIFF
92
- end
93
-
94
- def new_additional_disk_ps(disk_path, disk_size)
95
- <<-ADDDISK
96
-
97
- New-VHD -Path "#{disk_path}" -SizeBytes #{disk_size}GB | Out-Null
98
- ADDDISK
99
- end
100
-
101
- def ensure_vm_running_ps
102
- <<-RUNNING
103
-
104
- Assert-VmRunning -ID "#{@state[:id]}" | ConvertTo-Json
105
- RUNNING
106
- end
107
-
108
- def new_vm_ps
109
- <<-NEWVM
110
-
111
- $NewVMParams = @{
112
- Generation = #{config[:vm_generation]}
113
- DisableSecureBoot = "#{config[:disable_secureboot]}"
114
- MemoryStartupBytes = #{config[:memory_startup_bytes]}
115
- Name = "#{instance.name}"
116
- Path = "#{kitchen_vm_path}"
117
- VHDPath = "#{differencing_disk_path}"
118
- SwitchName = "#{config[:vm_switch]}"
119
- VlanId = #{config[:vm_vlan_id] || '$null'}
120
- ProcessorCount = #{config[:processor_count]}
121
- UseDynamicMemory = "#{config[:dynamic_memory]}"
122
- DynamicMemoryMinBytes = #{config[:dynamic_memory_min_bytes]}
123
- DynamicMemoryMaxBytes = #{config[:dynamic_memory_max_bytes]}
124
- boot_iso_path = "#{boot_iso_path}"
125
- EnableGuestServices = "#{config[:enable_guest_services]}"
126
- #{additional_disks}
127
- }
128
- New-KitchenVM @NewVMParams | ConvertTo-Json
129
- NEWVM
130
- end
131
-
132
- def additional_disks
133
- return if config[:additional_disks].nil?
134
- <<-EOH
135
- AdditionalDisks = @("#{@additional_disk_objects.join('","')}")
136
- EOH
137
- end
138
-
139
- def vm_details_ps
140
- <<-DETAILS
141
-
142
- Get-VmDetail -id "#{@state[:id]}" | ConvertTo-Json
143
- DETAILS
144
- end
145
-
146
- def delete_vm_ps
147
- <<-REMOVE
148
-
149
- $null = Get-VM -ID "#{@state[:id]}" |
150
- Stop-VM -Force -TurnOff -PassThru |
151
- Remove-VM -Force
152
- REMOVE
153
- end
154
-
155
- def set_vm_ipaddress_ps
156
- <<-VMIP
157
-
158
- (Get-VM -id "#{@state[:id]}").NetworkAdapters |
159
- Set-VMNetworkConfiguration -ipaddress "#{config[:ip_address]}" `
160
- -subnet "#{config[:subnet]}" `
161
- -gateway "#{config[:gateway]}" `
162
- -dnsservers #{ruby_array_to_ps_array(config[:dns_servers])} |
163
- ConvertTo-Json
164
- VMIP
165
- end
166
-
167
- def vm_default_switch_ps
168
- <<-VMSWITCH
169
- Get-DefaultVMSwitch #{config[:vm_switch]} | ConvertTo-Json
170
- VMSWITCH
171
- end
172
-
173
- def mount_vm_iso
174
- <<-MOUNTISO
175
- mount-vmiso -id "#{@state[:id]}" -Path #{config[:iso_path]}
176
- MOUNTISO
177
- end
178
-
179
- def resize_vhd
180
- <<-VMNOTE
181
- Resize-VHD -Path "#{parent_vhd_path}" -Size #{config[:resize_vhd]}
182
- VMNOTE
183
- end
184
-
185
- def set_vm_note
186
- <<-VMNOTE
187
- Set-VM -Name (Get-VM | Where-Object{ $_.ID -eq "#{@state[:id]}"}).Name -Note "#{config[:vm_note]}"
188
- VMNOTE
189
- end
190
-
191
- def copy_vm_file_ps(source, dest)
192
- <<-FILECOPY
193
- Function CopyFile ($VM, [string]$SourcePath, [string]$DestPath) {
194
- $p = @{ CreateFullPath = $true ; FileSource = 'Host'; Force = $true }
195
- $VM |
196
- Copy-VMFile -SourcePath $SourcePath -DestinationPath $DestPath @p
197
- }
198
-
199
- $sourceLocation = '#{source}'
200
- $destinationLocation = '#{dest}'
201
- $vmId = '#{@state[:id]}'
202
- If (Test-Path $sourceLocation) {
203
- $vm = Get-VM -ID $vmId
204
- $service = 'Guest Service Interface'
205
-
206
- If ((Get-VMIntegrationService -Name $service -VM $vm).Enabled -ne $true) {
207
- Enable-VMIntegrationService -Name $service -VM $vm
208
- Start-Sleep -Seconds 3
209
- }
210
-
211
- If ((Get-Item $sourceLocation) -is [System.IO.DirectoryInfo]) {
212
- ForEach ($item in (Get-ChildItem -Path $sourceLocation -File)) {
213
- $destFullPath = (Join-Path $destinationLocation $item.Name)
214
- CopyFile $vm $item.FullName $destFullPath
215
- }
216
- }
217
- Else {
218
- CopyFile $vm $sourceLocation $destinationLocation
219
- }
220
- }
221
- else {
222
- Write-Error "Source file path does not exist: $sourceLocation"
223
- }
224
- FILECOPY
225
- end
226
-
227
- private
228
-
229
- def ruby_array_to_ps_array(list)
230
- return "@()" if list.nil? || list.empty?
231
- list.to_s.tr('[]','()').prepend('@')
232
- end
233
- end
234
- end
235
- end
1
+ #
2
+ # Author:: Steven Murawski <smurawski@chef.io>
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'mixlib/shellout'
19
+ require 'fileutils'
20
+ require 'JSON'
21
+
22
+ module Kitchen
23
+ module Driver
24
+ module PowerShellScripts
25
+ def encode_command(script)
26
+ encoded_script = script.encode('UTF-16LE', 'UTF-8')
27
+ Base64.strict_encode64(encoded_script)
28
+ end
29
+
30
+ def is_64bit?
31
+ os_arch = ENV['PROCESSOR_ARCHITEW6432'] || ENV['PROCESSOR_ARCHITECTURE']
32
+ ruby_arch = ['foo'].pack('p').size == 4 ? 32 : 64
33
+ os_arch == 'AMD64' && ruby_arch == 64
34
+ end
35
+
36
+ def is_32bit?
37
+ os_arch = ENV['PROCESSOR_ARCHITEW6432'] || ENV['PROCESSOR_ARCHITECTURE']
38
+ ruby_arch = ['foo'].pack('p').size == 4 ? 32 : 64
39
+ os_arch != 'AMD64' && ruby_arch == 32
40
+ end
41
+
42
+ def powershell_64_bit
43
+ if is_64bit? || is_32bit?
44
+ 'c:\windows\system32\windowspowershell\v1.0\powershell.exe'
45
+ else
46
+ 'c:\windows\sysnative\windowspowershell\v1.0\powershell.exe'
47
+ end
48
+ end
49
+
50
+ def wrap_command(script)
51
+ base_script_path = File.join(File.dirname(__FILE__), '/../../../support/hyperv.ps1')
52
+ debug("Loading functions from #{base_script_path}")
53
+ new_script = [ ". #{base_script_path}", "#{script}" ].join(";\n")
54
+ debug("Wrapped script: #{new_script}")
55
+ "#{powershell_64_bit} -noprofile -executionpolicy bypass" \
56
+ " -encodedcommand #{encode_command new_script} -outputformat Text"
57
+ end
58
+
59
+ # Convenience method to run a powershell command locally.
60
+ #
61
+ # @param cmd [String] command to run locally
62
+ # @param options [Hash] options hash
63
+ # @see Kitchen::ShellOut.run_command
64
+ # @api private
65
+ def run_ps(cmd, options = {})
66
+ cmd = "echo #{cmd}" if config[:dry_run]
67
+ debug('Preparing to run: ')
68
+ debug(" #{cmd}")
69
+ wrapped_command = wrap_command cmd
70
+ execute_command wrapped_command, options
71
+ end
72
+
73
+ def execute_command(cmd, options = {})
74
+ debug("#Local Command BEGIN (#{cmd})")
75
+ sh = Mixlib::ShellOut.new(cmd, options)
76
+ sh.run_command
77
+ debug("Local Command END #{Util.duration(sh.execution_time)}")
78
+ raise "Failed: #{sh.stderr}" if sh.error?
79
+ stdout = sanitize_stdout(sh.stdout)
80
+ JSON.parse(stdout) if stdout.length > 2
81
+ end
82
+
83
+ def sanitize_stdout(stdout)
84
+ stdout.split("\n").select { |s| !s.start_with?("PS") }.join("\n")
85
+ end
86
+
87
+ def new_differencing_disk_ps
88
+ <<-DIFF
89
+
90
+ New-DifferencingDisk -Path "#{differencing_disk_path}" -ParentPath "#{parent_vhd_path}"
91
+ DIFF
92
+ end
93
+
94
+ def new_additional_disk_ps(disk_path, disk_size)
95
+ <<-ADDDISK
96
+
97
+ New-VHD -Path "#{disk_path}" -SizeBytes #{disk_size}GB | Out-Null
98
+ ADDDISK
99
+ end
100
+
101
+ def ensure_vm_running_ps
102
+ <<-RUNNING
103
+
104
+ Assert-VmRunning -ID "#{@state[:id]}" | ConvertTo-Json
105
+ RUNNING
106
+ end
107
+
108
+ def new_vm_ps
109
+ <<-NEWVM
110
+
111
+ $NewVMParams = @{
112
+ Generation = #{config[:vm_generation]}
113
+ DisableSecureBoot = "#{config[:disable_secureboot]}"
114
+ MemoryStartupBytes = #{config[:memory_startup_bytes]}
115
+ StaticMacAddress = "#{config[:static_mac_address]}"
116
+ Name = "#{instance.name}"
117
+ Path = "#{kitchen_vm_path}"
118
+ VHDPath = "#{differencing_disk_path}"
119
+ SwitchName = "#{config[:vm_switch]}"
120
+ VlanId = #{config[:vm_vlan_id] || '$null'}
121
+ ProcessorCount = #{config[:processor_count]}
122
+ UseDynamicMemory = "#{config[:dynamic_memory]}"
123
+ DynamicMemoryMinBytes = #{config[:dynamic_memory_min_bytes]}
124
+ DynamicMemoryMaxBytes = #{config[:dynamic_memory_max_bytes]}
125
+ boot_iso_path = "#{boot_iso_path}"
126
+ EnableGuestServices = "#{config[:enable_guest_services]}"
127
+ #{additional_disks}
128
+ }
129
+ New-KitchenVM @NewVMParams | ConvertTo-Json
130
+ NEWVM
131
+ end
132
+
133
+ def additional_disks
134
+ return if config[:additional_disks].nil?
135
+ <<-EOH
136
+ AdditionalDisks = @("#{@additional_disk_objects.join('","')}")
137
+ EOH
138
+ end
139
+
140
+ def vm_details_ps
141
+ <<-DETAILS
142
+
143
+ Get-VmDetail -id "#{@state[:id]}" | ConvertTo-Json
144
+ DETAILS
145
+ end
146
+
147
+ def delete_vm_ps
148
+ <<-REMOVE
149
+
150
+ $null = Get-VM -ID "#{@state[:id]}" |
151
+ Stop-VM -Force -TurnOff -PassThru |
152
+ Remove-VM -Force
153
+ REMOVE
154
+ end
155
+
156
+ def set_vm_ipaddress_ps
157
+ <<-VMIP
158
+
159
+ (Get-VM -id "#{@state[:id]}").NetworkAdapters |
160
+ Set-VMNetworkConfiguration -ipaddress "#{config[:ip_address]}" `
161
+ -subnet "#{config[:subnet]}" `
162
+ -gateway "#{config[:gateway]}" `
163
+ -dnsservers #{ruby_array_to_ps_array(config[:dns_servers])} |
164
+ ConvertTo-Json
165
+ VMIP
166
+ end
167
+
168
+ def vm_default_switch_ps
169
+ <<-VMSWITCH
170
+ Get-DefaultVMSwitch #{config[:vm_switch]} | ConvertTo-Json
171
+ VMSWITCH
172
+ end
173
+
174
+ def mount_vm_iso
175
+ <<-MOUNTISO
176
+ mount-vmiso -id "#{@state[:id]}" -Path #{config[:iso_path]}
177
+ MOUNTISO
178
+ end
179
+
180
+ def resize_vhd
181
+ <<-VMNOTE
182
+ Resize-VHD -Path "#{parent_vhd_path}" -Size #{config[:resize_vhd]}
183
+ VMNOTE
184
+ end
185
+
186
+ def set_vm_note
187
+ <<-VMNOTE
188
+ Set-VM -Name (Get-VM | Where-Object{ $_.ID -eq "#{@state[:id]}"}).Name -Note "#{config[:vm_note]}"
189
+ VMNOTE
190
+ end
191
+
192
+ def copy_vm_file_ps(source, dest)
193
+ <<-FILECOPY
194
+ Function CopyFile ($VM, [string]$SourcePath, [string]$DestPath) {
195
+ $p = @{ CreateFullPath = $true ; FileSource = 'Host'; Force = $true }
196
+ $VM |
197
+ Copy-VMFile -SourcePath $SourcePath -DestinationPath $DestPath @p
198
+ }
199
+
200
+ $sourceLocation = '#{source}'
201
+ $destinationLocation = '#{dest}'
202
+ $vmId = '#{@state[:id]}'
203
+ If (Test-Path $sourceLocation) {
204
+ $vm = Get-VM -ID $vmId
205
+ $service = 'Guest Service Interface'
206
+
207
+ If ((Get-VMIntegrationService -Name $service -VM $vm).Enabled -ne $true) {
208
+ Enable-VMIntegrationService -Name $service -VM $vm
209
+ Start-Sleep -Seconds 3
210
+ }
211
+
212
+ If ((Get-Item $sourceLocation) -is [System.IO.DirectoryInfo]) {
213
+ ForEach ($item in (Get-ChildItem -Path $sourceLocation -File)) {
214
+ $destFullPath = (Join-Path $destinationLocation $item.Name)
215
+ CopyFile $vm $item.FullName $destFullPath
216
+ }
217
+ }
218
+ Else {
219
+ CopyFile $vm $sourceLocation $destinationLocation
220
+ }
221
+ }
222
+ else {
223
+ Write-Error "Source file path does not exist: $sourceLocation"
224
+ }
225
+ FILECOPY
226
+ end
227
+
228
+ private
229
+
230
+ def ruby_array_to_ps_array(list)
231
+ return "@()" if list.nil? || list.empty?
232
+ list.to_s.tr('[]','()').prepend('@')
233
+ end
234
+ end
235
+ end
236
+ end