kitchen-hyperv 0.2.3 → 0.3.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,205 +1,212 @@
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 ensure_vm_running_ps
95
- <<-RUNNING
96
-
97
- Assert-VmRunning -ID "#{@state[:id]}" | ConvertTo-Json
98
- RUNNING
99
- end
100
-
101
- def new_vm_ps
102
- <<-NEWVM
103
-
104
- $NewVMParams = @{
105
- Generation = #{config[:vm_generation]}
106
- MemoryStartupBytes = #{config[:memory_startup_bytes]}
107
- Name = "#{instance.name}"
108
- Path = "#{kitchen_vm_path}"
109
- VHDPath = "#{differencing_disk_path}"
110
- SwitchName = "#{config[:vm_switch]}"
111
- ProcessorCount = #{config[:processor_count]}
112
- UseDynamicMemory = "#{config[:dynamic_memory]}"
113
- DynamicMemoryMinBytes = #{config[:dynamic_memory_min_bytes]}
114
- DynamicMemoryMaxBytes = #{config[:dynamic_memory_max_bytes]}
115
- boot_iso_path = "#{boot_iso_path}"
116
- }
117
- New-KitchenVM @NewVMParams | ConvertTo-Json
118
- NEWVM
119
- end
120
-
121
- def vm_details_ps
122
- <<-DETAILS
123
-
124
- Get-VmDetail -id "#{@state[:id]}" | ConvertTo-Json
125
- DETAILS
126
- end
127
-
128
- def delete_vm_ps
129
- <<-REMOVE
130
-
131
- $null = Get-VM -ID "#{@state[:id]}" |
132
- Stop-VM -Force -TurnOff -PassThru |
133
- Remove-VM -Force
134
- REMOVE
135
- end
136
-
137
- def set_vm_ipaddress_ps
138
- <<-VMIP
139
-
140
- (Get-VM -id "#{@state[:id]}").NetworkAdapters |
141
- Set-VMNetworkConfiguration -ipaddress "#{config[:ip_address]}" `
142
- -subnet "#{config[:subnet]}" `
143
- -gateway "#{config[:gateway]}" `
144
- -dnsservers #{ruby_array_to_ps_array(config[:dns_servers])} |
145
- ConvertTo-Json
146
- VMIP
147
- end
148
-
149
- def vm_default_switch_ps
150
- <<-VMSWITCH
151
- Get-DefaultVMSwitch #{config[:vm_switch]} | ConvertTo-Json
152
- VMSWITCH
153
- end
154
-
155
- def mount_vm_iso
156
- <<-MOUNTISO
157
- mount-vmiso -id "#{@state[:id]}" -Path #{config[:iso_path]}
158
- MOUNTISO
159
- end
160
-
161
- def copy_vm_file_ps(source, dest)
162
- <<-FILECOPY
163
- Function CopyFile ($VM, [string]$SourcePath, [string]$DestPath) {
164
- $p = @{ CreateFullPath = $true ; FileSource = 'Host'; Force = $true }
165
- $VM |
166
- Copy-VMFile -SourcePath $SourcePath -DestinationPath $DestPath @p
167
- }
168
-
169
- $sourceLocation = '#{source}'
170
- $destinationLocation = '#{dest}'
171
- $vmId = '#{@state[:id]}'
172
- If (Test-Path $sourceLocation) {
173
- $vm = Get-VM -ID $vmId
174
- $service = 'Guest Service Interface'
175
-
176
- If ((Get-VMIntegrationService -Name $service -VM $vm).Enabled -ne $true) {
177
- Enable-VMIntegrationService -Name $service -VM $vm
178
- Start-Sleep -Seconds 3
179
- }
180
-
181
- If ((Get-Item $sourceLocation) -is [System.IO.DirectoryInfo]) {
182
- ForEach ($item in (Get-ChildItem -Path $sourceLocation -File)) {
183
- $destFullPath = (Join-Path $destinationLocation $item.Name)
184
- CopyFile $vm $item.FullName $destFullPath
185
- }
186
- }
187
- Else {
188
- CopyFile $vm $sourceLocation $destinationLocation
189
- }
190
- }
191
- else {
192
- Write-Error "Source file path does not exist: $sourceLocation"
193
- }
194
- FILECOPY
195
- end
196
-
197
- private
198
-
199
- def ruby_array_to_ps_array(list)
200
- return "@()" if list.nil? || list.empty?
201
- list.to_s.tr('[]','()').prepend('@')
202
- end
203
- end
204
- end
205
- 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 ensure_vm_running_ps
95
+ <<-RUNNING
96
+
97
+ Assert-VmRunning -ID "#{@state[:id]}" | ConvertTo-Json
98
+ RUNNING
99
+ end
100
+
101
+ def new_vm_ps
102
+ <<-NEWVM
103
+
104
+ $NewVMParams = @{
105
+ Generation = #{config[:vm_generation]}
106
+ MemoryStartupBytes = #{config[:memory_startup_bytes]}
107
+ Name = "#{instance.name}"
108
+ Path = "#{kitchen_vm_path}"
109
+ VHDPath = "#{differencing_disk_path}"
110
+ SwitchName = "#{config[:vm_switch]}"
111
+ ProcessorCount = #{config[:processor_count]}
112
+ UseDynamicMemory = "#{config[:dynamic_memory]}"
113
+ DynamicMemoryMinBytes = #{config[:dynamic_memory_min_bytes]}
114
+ DynamicMemoryMaxBytes = #{config[:dynamic_memory_max_bytes]}
115
+ boot_iso_path = "#{boot_iso_path}"
116
+ EnableGuestServices = "#{config[:enable_guest_services]}"
117
+ }
118
+ New-KitchenVM @NewVMParams | ConvertTo-Json
119
+ NEWVM
120
+ end
121
+
122
+ def vm_details_ps
123
+ <<-DETAILS
124
+
125
+ Get-VmDetail -id "#{@state[:id]}" | ConvertTo-Json
126
+ DETAILS
127
+ end
128
+
129
+ def delete_vm_ps
130
+ <<-REMOVE
131
+
132
+ $null = Get-VM -ID "#{@state[:id]}" |
133
+ Stop-VM -Force -TurnOff -PassThru |
134
+ Remove-VM -Force
135
+ REMOVE
136
+ end
137
+
138
+ def set_vm_ipaddress_ps
139
+ <<-VMIP
140
+
141
+ (Get-VM -id "#{@state[:id]}").NetworkAdapters |
142
+ Set-VMNetworkConfiguration -ipaddress "#{config[:ip_address]}" `
143
+ -subnet "#{config[:subnet]}" `
144
+ -gateway "#{config[:gateway]}" `
145
+ -dnsservers #{ruby_array_to_ps_array(config[:dns_servers])} |
146
+ ConvertTo-Json
147
+ VMIP
148
+ end
149
+
150
+ def vm_default_switch_ps
151
+ <<-VMSWITCH
152
+ Get-DefaultVMSwitch #{config[:vm_switch]} | ConvertTo-Json
153
+ VMSWITCH
154
+ end
155
+
156
+ def mount_vm_iso
157
+ <<-MOUNTISO
158
+ mount-vmiso -id "#{@state[:id]}" -Path #{config[:iso_path]}
159
+ MOUNTISO
160
+ end
161
+
162
+ def set_vm_note
163
+ <<-VMNOTE
164
+ Set-VM -Name (Get-VM | Where-Object{ $_.ID -eq "#{@state[:id]}"}).Name -Note "#{config[:vm_note]}"
165
+ VMNOTE
166
+ end
167
+
168
+ def copy_vm_file_ps(source, dest)
169
+ <<-FILECOPY
170
+ Function CopyFile ($VM, [string]$SourcePath, [string]$DestPath) {
171
+ $p = @{ CreateFullPath = $true ; FileSource = 'Host'; Force = $true }
172
+ $VM |
173
+ Copy-VMFile -SourcePath $SourcePath -DestinationPath $DestPath @p
174
+ }
175
+
176
+ $sourceLocation = '#{source}'
177
+ $destinationLocation = '#{dest}'
178
+ $vmId = '#{@state[:id]}'
179
+ If (Test-Path $sourceLocation) {
180
+ $vm = Get-VM -ID $vmId
181
+ $service = 'Guest Service Interface'
182
+
183
+ If ((Get-VMIntegrationService -Name $service -VM $vm).Enabled -ne $true) {
184
+ Enable-VMIntegrationService -Name $service -VM $vm
185
+ Start-Sleep -Seconds 3
186
+ }
187
+
188
+ If ((Get-Item $sourceLocation) -is [System.IO.DirectoryInfo]) {
189
+ ForEach ($item in (Get-ChildItem -Path $sourceLocation -File)) {
190
+ $destFullPath = (Join-Path $destinationLocation $item.Name)
191
+ CopyFile $vm $item.FullName $destFullPath
192
+ }
193
+ }
194
+ Else {
195
+ CopyFile $vm $sourceLocation $destinationLocation
196
+ }
197
+ }
198
+ else {
199
+ Write-Error "Source file path does not exist: $sourceLocation"
200
+ }
201
+ FILECOPY
202
+ end
203
+
204
+ private
205
+
206
+ def ruby_array_to_ps_array(list)
207
+ return "@()" if list.nil? || list.empty?
208
+ list.to_s.tr('[]','()').prepend('@')
209
+ end
210
+ end
211
+ end
212
+ end
@@ -1,70 +1,70 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2015, Fletcher Nichol
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- require_relative "../../spec_helper"
20
-
21
- require "logger"
22
- require "stringio"
23
- require "kitchen"
24
- require 'kitchen/driver/hyperv_version'
25
- require "kitchen/driver/hyperv"
26
- require "kitchen/provisioner/dummy"
27
- require "kitchen/transport/dummy"
28
- require "kitchen/verifier/dummy"
29
-
30
- describe Kitchen::Driver::Hyperv do
31
-
32
- let(:logged_output) { StringIO.new }
33
- let(:logger) { Logger.new(logged_output) }
34
- let(:config) { { :kitchen_root => "c:/test_root" } }
35
- let(:platform) { Kitchen::Platform.new(:name => "fooos-99") }
36
- let(:suite) { Kitchen::Suite.new(:name => "suitey") }
37
- let(:verifier) { Kitchen::Verifier::Dummy.new }
38
- let(:provisioner) { Kitchen::Provisioner::Dummy.new }
39
- let(:transport) { Kitchen::Transport::Dummy.new }
40
- let(:state_file) { stub("state_file") }
41
- let(:state) { Hash.new }
42
- let(:env) { Hash.new }
43
-
44
- let(:driver_object) { Kitchen::Driver::Hyperv.new(config) }
45
-
46
- let(:driver) do
47
- d = driver_object
48
- instance
49
- d
50
- end
51
-
52
- let(:instance) do
53
- Kitchen::Instance.new(
54
- :verifier => verifier,
55
- :driver => driver_object,
56
- :logger => logger,
57
- :suite => suite,
58
- :platform => platform,
59
- :provisioner => provisioner,
60
- :transport => transport,
61
- :state_file => state_file
62
- )
63
- end
64
-
65
- #before { stub_const("ENV", env) }
66
-
67
- it 'driver api_version is 2' do
68
- driver.diagnose_plugin[:api_version].must_equal(2)
69
- end
70
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2015, Fletcher Nichol
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative "../../spec_helper"
20
+
21
+ require "logger"
22
+ require "stringio"
23
+ require "kitchen"
24
+ require 'kitchen/driver/hyperv_version'
25
+ require "kitchen/driver/hyperv"
26
+ require "kitchen/provisioner/dummy"
27
+ require "kitchen/transport/dummy"
28
+ require "kitchen/verifier/dummy"
29
+
30
+ describe Kitchen::Driver::Hyperv do
31
+
32
+ let(:logged_output) { StringIO.new }
33
+ let(:logger) { Logger.new(logged_output) }
34
+ let(:config) { { :kitchen_root => "c:/test_root" } }
35
+ let(:platform) { Kitchen::Platform.new(:name => "fooos-99") }
36
+ let(:suite) { Kitchen::Suite.new(:name => "suitey") }
37
+ let(:verifier) { Kitchen::Verifier::Dummy.new }
38
+ let(:provisioner) { Kitchen::Provisioner::Dummy.new }
39
+ let(:transport) { Kitchen::Transport::Dummy.new }
40
+ let(:state_file) { stub("state_file") }
41
+ let(:state) { Hash.new }
42
+ let(:env) { Hash.new }
43
+
44
+ let(:driver_object) { Kitchen::Driver::Hyperv.new(config) }
45
+
46
+ let(:driver) do
47
+ d = driver_object
48
+ instance
49
+ d
50
+ end
51
+
52
+ let(:instance) do
53
+ Kitchen::Instance.new(
54
+ :verifier => verifier,
55
+ :driver => driver_object,
56
+ :logger => logger,
57
+ :suite => suite,
58
+ :platform => platform,
59
+ :provisioner => provisioner,
60
+ :transport => transport,
61
+ :state_file => state_file
62
+ )
63
+ end
64
+
65
+ #before { stub_const("ENV", env) }
66
+
67
+ it 'driver api_version is 2' do
68
+ driver.diagnose_plugin[:api_version].must_equal(2)
69
+ end
70
+ end