kitchen-hyperv 0.5.1 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8d3ff9e9f8b99293939c7c141455c2ec41abd93d
4
- data.tar.gz: 0c2f6720c12e51087617bc30f26118ed8d5a94b7
2
+ SHA256:
3
+ metadata.gz: 77de7e7e7c1ef9e2beccf916a5d2cfa43944e21a20c5f20b7b05fdccf6fbe7f1
4
+ data.tar.gz: 56e1414348b16545ca9352c2f8412f646357d722eb734ce6d63fba284ba0d70c
5
5
  SHA512:
6
- metadata.gz: d0c19962957e55d526736b5e8dc9ee0a94939c7e46192077ff13b29717294d68ded617672260025a8b8f3470737c798bca125560f53bbe77d262d0891897d566
7
- data.tar.gz: 6d95718a8bd947220c7d6a12c82539ec03befc7509d8281e0e152b49c996cecd3b90bc7ceffdf6f4e38c5749798d0e9c4cde16c4c0af760e6cdad2b84f85ded9
6
+ metadata.gz: bc98efd324d739c4acbc8a8f94126af271e93b0b0221eed758011cbd6e62e7e208faa9db97d7af2a9bc636fdc0dcd01bc2e405e98794093c60603ae2f32043e7
7
+ data.tar.gz: 7bf53cdba391cf217b1e178a3c6150c6a4aa69b8dc100aba62d2f8360c67e65973f83936ec15967e7bb95b7ed0ee0082f3f951499673097c3a199ec7ff3c72eb
data/Gemfile CHANGED
@@ -1,15 +1,25 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in kitchen-hyperv.gemspec
4
- gemspec
5
-
6
- gem 'win32-process'
7
- gem 'win32-api'
8
- gem 'windows-pr'
9
- gem 'windows-api'
10
- gem 'ffi'
11
- gem 'rb-readline'
12
- gem 'pry'
13
- gem 'pry-stack_explorer'
14
- gem 'pry-byebug'
15
- gem 'github_changelog_generator'
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in kitchen-pester.gemspec
4
+ gemspec
5
+
6
+ group :integration do
7
+ gem "berkshelf"
8
+ gem "kitchen-inspec"
9
+ gem "kitchen-dokken"
10
+ gem "kitchen-vagrant"
11
+ end
12
+
13
+ group :debug do
14
+ gem "pry"
15
+ gem "pry-byebug"
16
+ gem "pry-stack_explorer"
17
+ end
18
+
19
+ group :chefstyle do
20
+ gem "chefstyle"
21
+ end
22
+
23
+ group :docs do
24
+ gem "yard"
25
+ end
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2020 Steven Murawski
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/Rakefile CHANGED
@@ -1,32 +1,50 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require "bundler/gem_tasks"
4
- require "kitchen/driver/hyperv_version"
5
-
6
- require "rake/testtask"
7
- Rake::TestTask.new(:unit) do |t|
8
- t.libs.push "lib"
9
- t.test_files = FileList["spec/**/*_spec.rb"]
10
- t.verbose = true
11
- end
12
-
13
- desc "Run all test suites"
14
- task :test => [:unit]
15
-
16
-
17
- task :default => [:test]
18
-
19
- begin
20
- require "github_changelog_generator/task"
21
-
22
- GitHubChangelogGenerator::RakeTask.new :changelog do |config|
23
- config.future_release = "v#{Kitchen::Driver::HYPERV_VERSION}"
24
- config.issues = false
25
- config.pulls = true
26
- config.user = 'test-kitchen'
27
- config.project = 'kitchen-hyperv'
28
- end
29
- rescue LoadError
30
- puts "github_changelog_generator is not available. " \
31
- "gem install github_changelog_generator to generate changelogs"
32
- end
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "bundler/gem_tasks"
4
+ require "kitchen/driver/hyperv_version"
5
+
6
+ require "rake/testtask"
7
+ Rake::TestTask.new(:unit) do |t|
8
+ t.libs.push "lib"
9
+ t.test_files = FileList["spec/**/*_spec.rb"]
10
+ t.verbose = true
11
+ end
12
+
13
+ desc "Run all test suites"
14
+ task test: :unit
15
+
16
+ begin
17
+ require "chefstyle"
18
+ require "rubocop/rake_task"
19
+ RuboCop::RakeTask.new(:style) do |task|
20
+ task.options += ["--display-cop-names", "--no-color"]
21
+ end
22
+ rescue LoadError
23
+ puts "chefstyle is not available. (sudo) gem install chefstyle to do style checking."
24
+ end
25
+
26
+ desc "Run all quality tasks"
27
+ task quality: :style
28
+
29
+ begin
30
+ require "yard" unless defined?(YARD)
31
+ YARD::Rake::YardocTask.new
32
+ rescue LoadError
33
+ puts "yard is not available. (sudo) gem install yard to generate yard documentation."
34
+ end
35
+
36
+ task default: %i{test quality}
37
+ begin
38
+ require "github_changelog_generator/task"
39
+
40
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
41
+ config.future_release = "v#{Kitchen::Driver::HYPERV_VERSION}"
42
+ config.issues = false
43
+ config.pulls = true
44
+ config.user = "test-kitchen"
45
+ config.project = "kitchen-hyperv"
46
+ end
47
+ rescue LoadError
48
+ puts "github_changelog_generator is not available. " \
49
+ "gem install github_changelog_generator to generate changelogs"
50
+ end
@@ -1,32 +1,26 @@
1
- # encoding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
-
5
- require 'kitchen/driver/hyperv_version'
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = "kitchen-hyperv"
9
- spec.version = Kitchen::Driver::HYPERV_VERSION
10
- spec.authors = ["Steven Murawski"]
11
- spec.email = ["steven.murawski@gmail.com"]
12
- spec.summary = 'Hyper-V Driver for Test-Kitchen'
13
- spec.description = 'Hyper-V Driver for Test-Kitchen'
14
- spec.homepage = "https://github.com/test-kitchen/kitchen-hyperv"
15
- spec.license = "Apache 2"
16
-
17
- spec.files = `git ls-files -z`.split("\x0")
18
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
- spec.require_paths = ["lib"]
21
-
22
- spec.add_development_dependency "bundler", "~> 1.7"
23
- spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_development_dependency "pry", "~> 0.10"
25
- spec.add_development_dependency "cane"
26
- spec.add_development_dependency "finstyle"
27
- spec.add_development_dependency "rubocop"
28
- spec.add_development_dependency "yard"
29
- spec.add_development_dependency "countloc"
30
-
31
- spec.add_dependency "test-kitchen", "~> 1.4"
32
- end
1
+ # encoding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require "kitchen/driver/hyperv_version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "kitchen-hyperv"
9
+ spec.version = Kitchen::Driver::HYPERV_VERSION
10
+ spec.authors = ["Steven Murawski"]
11
+ spec.email = ["steven.murawski@gmail.com"]
12
+ spec.summary = "Hyper-V Driver for Test-Kitchen"
13
+ spec.description = "Hyper-V Driver for Test-Kitchen"
14
+ spec.homepage = "https://github.com/test-kitchen/kitchen-hyperv"
15
+ spec.license = "Apache-2.0"
16
+
17
+ spec.files = %w{LICENSE kitchen-hyperv.gemspec Gemfile Rakefile support/hyperv.ps1} + Dir.glob("lib/**/*")
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "rake"
21
+ spec.add_development_dependency "minitest", "~> 5.3", "< 5.15"
22
+ spec.add_development_dependency "minitest-stub-const"
23
+ spec.add_development_dependency "mocha", "~> 1.1"
24
+
25
+ spec.add_dependency "test-kitchen", ">= 1.4", "< 4"
26
+ end
@@ -1,279 +1,297 @@
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
-
19
- require 'kitchen'
20
- require 'kitchen/driver'
21
- require 'kitchen/driver/hyperv_version'
22
- require 'kitchen/driver/powershell'
23
- require 'mixlib/shellout'
24
- require 'fileutils'
25
- require 'JSON'
26
-
27
- module Kitchen
28
-
29
- module Driver
30
-
31
- # Driver for Hyper-V
32
- class Hyperv < Kitchen::Driver::Base
33
-
34
- kitchen_driver_api_version 2
35
- plugin_version Kitchen::Driver::HYPERV_VERSION
36
-
37
- default_config :parent_vhd_folder
38
- default_config :parent_vhd_name
39
- default_config :memory_startup_bytes, 536_870_912
40
- default_config :dynamic_memory_min_bytes, 536_870_912
41
- default_config :dynamic_memory_max_bytes, 2_147_483_648
42
- default_config :dynamic_memory, false
43
- default_config :processor_count, 2
44
- default_config :ip_address
45
- default_config :gateway
46
- default_config :dns_servers
47
- default_config :subnet, '255.255.255.0'
48
- default_config :vm_switch
49
- default_config :vm_vlan_id
50
- default_config :iso_path
51
- default_config :boot_iso_path
52
- default_config :enable_guest_services
53
- default_config :vm_note
54
- default_config :resize_vhd
55
- default_config :additional_disks
56
- default_config :vm_generation, 1
57
- default_config :disable_secureboot, false
58
- default_config :static_mac_address
59
- default_config :disk_type do |driver|
60
- File.extname(driver[:parent_vhd_name])
61
- end
62
-
63
- include Kitchen::Driver::PowerShellScripts
64
-
65
- def create(state)
66
- @state = state
67
- validate_vm_settings
68
- create_new_differencing_disk
69
- create_additional_disks
70
- create_virtual_machine
71
- set_virtual_machine_note
72
- update_state
73
- mount_virtual_machine_iso
74
- instance.transport.connection(@state).wait_until_ready
75
- copy_vm_files
76
- info("Hyper-V instance #{instance.to_str} created.")
77
- end
78
-
79
- def destroy(state)
80
- @state = state
81
- if differencing_disk_exists && !vm_exists_silent
82
- remove_differencing_disk
83
- end
84
- return unless vm_exists
85
- instance.transport.connection(state).close
86
- remove_virtual_machine
87
- remove_differencing_disk
88
- remove_additional_disks
89
- info("The Hyper-V instance #{instance.to_str} has been removed.")
90
- state.delete(:id)
91
- end
92
-
93
- private
94
-
95
- def validate_vm_settings
96
- raise "Missing parent_vhd_folder" unless vhd_folder?
97
- raise "Missing parent_vhd_name" unless vhd?
98
- if config[:dynamic_memory]
99
- startup_bytes = config[:memory_startup_bytes]
100
- min = config[:dynamic_memory_min_bytes]
101
- max = config[:dynamic_memory_max_bytes]
102
- memory_valid = startup_bytes.between?(min, max)
103
- warning = "memory_startup_bytes (#{startup_bytes}) must" \
104
- " fall within dynamic memory range (#{min}-#{max})"
105
- raise warning unless memory_valid
106
- end
107
- config[:vm_switch] = vm_switch
108
- if config[:vm_vlan_id]
109
- vm_vlan_id = config[:vm_vlan_id]
110
- vm_vlan_id_min = 1
111
- vm_vlan_id_max = 4094
112
- vm_vlan_id_valid = vm_vlan_id.between?(vm_vlan_id_min, vm_vlan_id_max)
113
- vm_vlan_id_warning = "vm_vlan_id (#{vm_vlan_id}) must be a valid 802.1Q" \
114
- " VLAN ID between (#{vm_vlan_id_min}-#{vm_vlan_id_max})"
115
- raise vm_vlan_id_warning unless vm_vlan_id_valid
116
- end
117
- end
118
-
119
- def create_new_differencing_disk
120
- info("Creating differencing disk for #{instance.name}.")
121
- run_ps new_differencing_disk_ps
122
- info("Created differencing disk for #{instance.name}.")
123
- set_new_vhd_size
124
- end
125
-
126
- def create_additional_disks
127
- return if config[:additional_disks].nil?
128
- @additional_disk_objects = []
129
- config[:additional_disks].each do |additional_disk|
130
- raise "Missing name for additional disk" unless additional_disk[:name]
131
- disk_type = additional_disk[:type] || config[:disk_type]
132
- disk_path = additional_disk_path(additional_disk[:name], disk_type)
133
- raise "Additional disk file already exists: #{disk_path}" unless !File.exist?(disk_path)
134
- disk_size = additional_disk[:size_gb] || 5
135
- info("Creating additional disk #{additional_disk[:name]} for #{instance.name}.")
136
- run_ps new_additional_disk_ps(disk_path, disk_size)
137
- info("Created additional disk #{additional_disk[:name]} for #{instance.name}.")
138
- @additional_disk_objects.push(disk_path)
139
- end
140
- end
141
-
142
- def vm_switch
143
- default_switch_object = run_ps vm_default_switch_ps
144
- if default_switch_object.nil? ||
145
- !default_switch_object.key?('Name') ||
146
- default_switch_object['Name'].empty?
147
- raise "Failed to find a default VM Switch."
148
- end
149
- default_switch_object['Name']
150
- end
151
-
152
- def create_virtual_machine
153
- return if vm_exists
154
- info("Creating virtual machine for #{instance.name}.")
155
- new_vm_object = run_ps new_vm_ps
156
- @state[:id] = new_vm_object['Id']
157
- info("Created virtual machine for #{instance.name}.")
158
- end
159
-
160
- def update_state
161
- vm_details
162
- @state[:id] = @vm['Id']
163
- @state[:hostname] = @vm['IpAddress']
164
- @state[:vm_name] = @vm['Name']
165
- end
166
-
167
- def vm_details
168
- run_ps set_vm_ipaddress_ps if config[:ip_address]
169
- @vm = run_ps vm_details_ps
170
- end
171
-
172
- def mount_virtual_machine_iso
173
- return unless config[:iso_path]
174
- info("Mounting #{config[:iso_path]}")
175
- run_ps mount_vm_iso
176
- info("Done mounting #{config[:iso_path]}")
177
- end
178
-
179
- def set_new_vhd_size
180
- return unless config[:resize_vhd]
181
- info("Resizing differencing disk for #{instance.name}.")
182
- run_ps resize_vhd
183
- info("Resized differencing disk for #{instance.name}.")
184
- end
185
-
186
- def set_virtual_machine_note
187
- return unless config[:vm_note]
188
- info("Adding note to VM: '#{config[:vm_note]}'")
189
- run_ps set_vm_note
190
- end
191
-
192
- def copy_vm_files
193
- return if config[:copy_vm_files].nil?
194
- info("Copying files to virtual machine")
195
- config[:copy_vm_files].each do |file_info|
196
- run_ps copy_vm_file_ps(file_info[:source], file_info[:dest])
197
- end
198
- info("Copied files to virtual machine")
199
- end
200
-
201
- def vm_exists
202
- info('Checking for existing virtual machine.')
203
- return false unless @state.key?(:id) && !@state[:id].nil?
204
- existing_vm = run_ps ensure_vm_running_ps
205
- return false if existing_vm.nil? || existing_vm['Id'].nil?
206
- info("Found an exising VM with an ID: #{existing_vm['Id']}")
207
- true
208
- end
209
-
210
- # Used in testing if a stale diff disk exists. Silent so the output doesn't
211
- # appear twice on the kitchen destroy command for the second check for vm_exists
212
- def vm_exists_silent
213
- return false unless @state.key?(:id) && !@state[:id].nil?
214
- existing_vm = run_ps ensure_vm_running_ps
215
- return false if existing_vm.nil? || existing_vm['Id'].nil?
216
- true
217
- end
218
-
219
- def differencing_disk_exists
220
- return unless File.exist? differencing_disk_path
221
- true
222
- end
223
-
224
- def remove_virtual_machine
225
- info("Deleting virtual machine for #{instance.name}")
226
- run_ps delete_vm_ps
227
- info("Deleted virtual machine for #{instance.name}")
228
- end
229
-
230
- def remove_differencing_disk
231
- info("Removing the differencing disk for #{instance.name}.")
232
- FileUtils.rm(differencing_disk_path)
233
- info("Removed the differencing disk for #{instance.name}.")
234
- end
235
-
236
- def remove_additional_disks
237
- return if config[:additional_disks].nil?
238
- config[:additional_disks].each do |additional_disk|
239
- raise "Missing name for additional disk" unless additional_disk[:name]
240
- disk_type = additional_disk[:type] || config[:disk_type]
241
- disk_path = additional_disk_path(additional_disk[:name], disk_type)
242
- if File.exist?(disk_path)
243
- info("Removing additional disk #{additional_disk[:name]} for #{instance.name}.")
244
- FileUtils.rm(disk_path)
245
- info("Removed additional disk #{additional_disk[:name]} for #{instance.name}.")
246
- end
247
- end
248
- end
249
-
250
- def kitchen_vm_path
251
- @kitchen_vm_path ||= File.join(config[:kitchen_root], ".kitchen/#{instance.name}")
252
- end
253
-
254
- def boot_iso_path
255
- @boot_iso_path ||= config[:boot_iso_path]
256
- end
257
-
258
- def differencing_disk_path
259
- @differencing_disk_path ||= File.join(kitchen_vm_path, "diff" + "#{config[:disk_type]}")
260
- end
261
-
262
- def additional_disk_path(disk_name, disk_type)
263
- File.join(kitchen_vm_path, disk_name + disk_type)
264
- end
265
-
266
- def parent_vhd_path
267
- @parent_vhd_path ||= File.join(config[:parent_vhd_folder], config[:parent_vhd_name])
268
- end
269
-
270
- def vhd_folder?
271
- config[:parent_vhd_folder] && Dir.exist?(config[:parent_vhd_folder])
272
- end
273
-
274
- def vhd?
275
- config[:parent_vhd_name] && File.exist?(parent_vhd_path)
276
- end
277
- end
278
- end
279
- end
1
+ #
2
+ # Author:: Steven Murawski <smurawski@chef.io>
3
+ # Copyright:: Copyright (c) 2020 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
+
19
+ require "kitchen"
20
+ require "kitchen/driver"
21
+ require_relative "hyperv_version"
22
+ require_relative "powershell"
23
+ require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
24
+ require "fileutils" unless defined?(FileUtils)
25
+ require "json" unless defined?(JSON)
26
+
27
+ module Kitchen
28
+
29
+ module Driver
30
+
31
+ # Driver for Hyper-V
32
+ class Hyperv < Kitchen::Driver::Base
33
+
34
+ kitchen_driver_api_version 2
35
+ plugin_version Kitchen::Driver::HYPERV_VERSION
36
+
37
+ default_config :parent_vhd_folder
38
+ default_config :parent_vhd_name
39
+ default_config :memory_startup_bytes, 536_870_912
40
+ default_config :dynamic_memory_min_bytes, 536_870_912
41
+ default_config :dynamic_memory_max_bytes, 2_147_483_648
42
+ default_config :dynamic_memory, false
43
+ default_config :processor_count, 2
44
+ default_config :ip_address
45
+ default_config :gateway
46
+ default_config :dns_servers
47
+ default_config :subnet, "255.255.255.0"
48
+ default_config :vm_switch
49
+ default_config :vm_vlan_id
50
+ default_config :iso_path
51
+ default_config :boot_iso_path
52
+ default_config :enable_guest_services
53
+ default_config :vm_note
54
+ default_config :resize_vhd
55
+ default_config :additional_disks
56
+ default_config :vm_generation, 1
57
+ default_config :disable_secureboot, false
58
+ default_config :static_mac_address
59
+ default_config :disk_type do |driver|
60
+ File.extname(driver[:parent_vhd_name])
61
+ end
62
+
63
+ include Kitchen::Driver::PowerShellScripts
64
+
65
+ def create(state)
66
+ @state = state
67
+ validate_vm_settings
68
+ create_new_differencing_disk
69
+ create_additional_disks
70
+ create_virtual_machine
71
+ set_virtual_machine_note
72
+ update_state
73
+ mount_virtual_machine_iso
74
+ instance.transport.connection(@state).wait_until_ready
75
+ copy_vm_files
76
+ info("Hyper-V instance #{instance.to_str} created.")
77
+ end
78
+
79
+ def destroy(state)
80
+ @state = state
81
+ if differencing_disk_exists && !vm_exists_silent
82
+ remove_differencing_disk
83
+ end
84
+ return unless vm_exists
85
+
86
+ instance.transport.connection(state).close
87
+ remove_virtual_machine
88
+ remove_differencing_disk
89
+ remove_additional_disks
90
+ info("The Hyper-V instance #{instance.to_str} has been removed.")
91
+ state.delete(:id)
92
+ end
93
+
94
+ private
95
+
96
+ def validate_vm_settings
97
+ raise "Missing parent_vhd_folder" unless vhd_folder?
98
+ raise "Missing parent_vhd_name" unless vhd?
99
+
100
+ if config[:dynamic_memory]
101
+ startup_bytes = config[:memory_startup_bytes]
102
+ min = config[:dynamic_memory_min_bytes]
103
+ max = config[:dynamic_memory_max_bytes]
104
+ memory_valid = startup_bytes.between?(min, max)
105
+ warning = "memory_startup_bytes (#{startup_bytes}) must" \
106
+ " fall within dynamic memory range (#{min}-#{max})"
107
+ raise warning unless memory_valid
108
+ end
109
+ config[:vm_switch] = vm_switch
110
+ if config[:vm_vlan_id]
111
+ vm_vlan_id = config[:vm_vlan_id]
112
+ vm_vlan_id_min = 1
113
+ vm_vlan_id_max = 4094
114
+ vm_vlan_id_valid = vm_vlan_id.between?(vm_vlan_id_min, vm_vlan_id_max)
115
+ vm_vlan_id_warning = "vm_vlan_id (#{vm_vlan_id}) must be a valid 802.1Q" \
116
+ " VLAN ID between (#{vm_vlan_id_min}-#{vm_vlan_id_max})"
117
+ raise vm_vlan_id_warning unless vm_vlan_id_valid
118
+ end
119
+ end
120
+
121
+ def create_new_differencing_disk
122
+ info("Creating differencing disk for #{instance.name}.")
123
+ run_ps new_differencing_disk_ps
124
+ info("Created differencing disk for #{instance.name}.")
125
+ set_new_vhd_size
126
+ end
127
+
128
+ def create_additional_disks
129
+ return if config[:additional_disks].nil?
130
+
131
+ @additional_disk_objects = []
132
+ config[:additional_disks].each do |additional_disk|
133
+ raise "Missing name for additional disk" unless additional_disk[:name]
134
+
135
+ disk_type = additional_disk[:type] || config[:disk_type]
136
+ disk_path = additional_disk_path(additional_disk[:name], disk_type)
137
+ raise "Additional disk file already exists: #{disk_path}" if File.exist?(disk_path)
138
+
139
+ disk_size = additional_disk[:size_gb] || 5
140
+ info("Creating additional disk #{additional_disk[:name]} for #{instance.name}.")
141
+ run_ps new_additional_disk_ps(disk_path, disk_size)
142
+ info("Created additional disk #{additional_disk[:name]} for #{instance.name}.")
143
+ @additional_disk_objects.push(disk_path)
144
+ end
145
+ end
146
+
147
+ def vm_switch
148
+ default_switch_object = run_ps vm_default_switch_ps
149
+ if default_switch_object.nil? ||
150
+ !default_switch_object.key?("Name") ||
151
+ default_switch_object["Name"].empty?
152
+ raise "Failed to find a default VM Switch."
153
+ end
154
+
155
+ default_switch_object["Name"]
156
+ end
157
+
158
+ def create_virtual_machine
159
+ return if vm_exists
160
+
161
+ info("Creating virtual machine for #{instance.name}.")
162
+ new_vm_object = run_ps new_vm_ps
163
+ @state[:id] = new_vm_object["Id"]
164
+ info("Created virtual machine for #{instance.name}.")
165
+ end
166
+
167
+ def update_state
168
+ vm_details
169
+ @state[:id] = @vm["Id"]
170
+ @state[:hostname] = @vm["IpAddress"]
171
+ @state[:vm_name] = @vm["Name"]
172
+ end
173
+
174
+ def vm_details
175
+ run_ps set_vm_ipaddress_ps if config[:ip_address]
176
+ @vm = run_ps vm_details_ps
177
+ end
178
+
179
+ def mount_virtual_machine_iso
180
+ return unless config[:iso_path]
181
+
182
+ info("Mounting #{config[:iso_path]}")
183
+ run_ps mount_vm_iso
184
+ info("Done mounting #{config[:iso_path]}")
185
+ end
186
+
187
+ def set_new_vhd_size
188
+ return unless config[:resize_vhd]
189
+
190
+ info("Resizing differencing disk for #{instance.name}.")
191
+ run_ps resize_vhd
192
+ info("Resized differencing disk for #{instance.name}.")
193
+ end
194
+
195
+ def set_virtual_machine_note
196
+ return unless config[:vm_note]
197
+
198
+ info("Adding note to VM: '#{config[:vm_note]}'")
199
+ run_ps set_vm_note
200
+ end
201
+
202
+ def copy_vm_files
203
+ return if config[:copy_vm_files].nil?
204
+
205
+ info("Copying files to virtual machine")
206
+ config[:copy_vm_files].each do |file_info|
207
+ run_ps copy_vm_file_ps(file_info[:source], file_info[:dest])
208
+ end
209
+ info("Copied files to virtual machine")
210
+ end
211
+
212
+ def vm_exists
213
+ info("Checking for existing virtual machine.")
214
+ return false unless @state.key?(:id) && !@state[:id].nil?
215
+
216
+ existing_vm = run_ps ensure_vm_running_ps
217
+ return false if existing_vm.nil? || existing_vm["Id"].nil?
218
+
219
+ info("Found an exising VM with an ID: #{existing_vm["Id"]}")
220
+ true
221
+ end
222
+
223
+ # Used in testing if a stale diff disk exists. Silent so the output doesn't
224
+ # appear twice on the kitchen destroy command for the second check for vm_exists
225
+ def vm_exists_silent
226
+ return false unless @state.key?(:id) && !@state[:id].nil?
227
+
228
+ existing_vm = run_ps ensure_vm_running_ps
229
+ return false if existing_vm.nil? || existing_vm["Id"].nil?
230
+
231
+ true
232
+ end
233
+
234
+ def differencing_disk_exists
235
+ return unless File.exist? differencing_disk_path
236
+
237
+ true
238
+ end
239
+
240
+ def remove_virtual_machine
241
+ info("Deleting virtual machine for #{instance.name}")
242
+ run_ps delete_vm_ps
243
+ info("Deleted virtual machine for #{instance.name}")
244
+ end
245
+
246
+ def remove_differencing_disk
247
+ info("Removing the differencing disk for #{instance.name}.")
248
+ FileUtils.rm(differencing_disk_path)
249
+ info("Removed the differencing disk for #{instance.name}.")
250
+ end
251
+
252
+ def remove_additional_disks
253
+ return if config[:additional_disks].nil?
254
+
255
+ config[:additional_disks].each do |additional_disk|
256
+ raise "Missing name for additional disk" unless additional_disk[:name]
257
+
258
+ disk_type = additional_disk[:type] || config[:disk_type]
259
+ disk_path = additional_disk_path(additional_disk[:name], disk_type)
260
+ if File.exist?(disk_path)
261
+ info("Removing additional disk #{additional_disk[:name]} for #{instance.name}.")
262
+ FileUtils.rm(disk_path)
263
+ info("Removed additional disk #{additional_disk[:name]} for #{instance.name}.")
264
+ end
265
+ end
266
+ end
267
+
268
+ def kitchen_vm_path
269
+ @kitchen_vm_path ||= File.join(config[:kitchen_root], ".kitchen/#{instance.name}")
270
+ end
271
+
272
+ def boot_iso_path
273
+ @boot_iso_path ||= config[:boot_iso_path]
274
+ end
275
+
276
+ def differencing_disk_path
277
+ @differencing_disk_path ||= File.join(kitchen_vm_path, "diff" + "#{config[:disk_type]}")
278
+ end
279
+
280
+ def additional_disk_path(disk_name, disk_type)
281
+ File.join(kitchen_vm_path, disk_name + disk_type)
282
+ end
283
+
284
+ def parent_vhd_path
285
+ @parent_vhd_path ||= File.join(config[:parent_vhd_folder], config[:parent_vhd_name])
286
+ end
287
+
288
+ def vhd_folder?
289
+ config[:parent_vhd_folder] && Dir.exist?(config[:parent_vhd_folder])
290
+ end
291
+
292
+ def vhd?
293
+ config[:parent_vhd_name] && File.exist?(parent_vhd_path)
294
+ end
295
+ end
296
+ end
297
+ end