kitchen-hyperv 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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