kitchen-hyperv 0.1.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 +7 -0
- data/.cane +2 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +5 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +52 -0
- data/kitchen-hyperv.gemspec +27 -0
- data/lib/kitchen/driver/hyperv.rb +139 -0
- data/lib/kitchen/driver/hyperv_version.rb +22 -0
- data/lib/kitchen/driver/powershell.rb +131 -0
- data/spec/kitchen/driver/hyperv_spec.rb +70 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/hyperv.Tests.ps1 +2 -0
- data/support/hyperv.ps1 +149 -0
- metadata +119 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 7588944a18673c39d89916777a86bfd20fefada1
|
|
4
|
+
data.tar.gz: f11736929cca5a1c06ce00e8b27e9f8821991992
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 51c6e027033709b450e949468550bf3bad75a2ab43e6c32a972d21d40f9cd75329e0624b62b6bdd9137fa6827e4b0838c5df1fcc9762b6e00cf0dc9eb9800ab3
|
|
7
|
+
data.tar.gz: 113b8020c4d1f4e25941d7699cb494851f45eac56e09aa38ac0179a419d85f7f9569865ab3648aabbcafca62aa8ac22d2bb43e247f1cfcaf1a847dede9e9d70d
|
data/.cane
ADDED
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2015 Steven Murawski
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Kitchen::Hyperv
|
|
2
|
+
|
|
3
|
+
TODO: Write a gem description
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'kitchen-hyperv'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install kitchen-hyperv
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
TODO: Write usage instructions here
|
|
24
|
+
|
|
25
|
+
## Contributing
|
|
26
|
+
|
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/kitchen-hyperv/fork )
|
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
|
|
5
|
+
require "rake/testtask"
|
|
6
|
+
Rake::TestTask.new(:unit) do |t|
|
|
7
|
+
t.libs.push "lib"
|
|
8
|
+
t.test_files = FileList["spec/**/*_spec.rb"]
|
|
9
|
+
t.verbose = true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
desc "Run all test suites"
|
|
13
|
+
task :test => [:unit]
|
|
14
|
+
|
|
15
|
+
desc "Display LOC stats"
|
|
16
|
+
task :stats do
|
|
17
|
+
puts "\n## Production Code Stats"
|
|
18
|
+
sh "countloc -r lib"
|
|
19
|
+
puts "\n## Test Code Stats"
|
|
20
|
+
sh "countloc -r spec"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require "finstyle"
|
|
24
|
+
require "rubocop/rake_task"
|
|
25
|
+
RuboCop::RakeTask.new(:style) do |task|
|
|
26
|
+
task.options << "--display-cop-names"
|
|
27
|
+
task.options << "--lint"
|
|
28
|
+
task.options << '--config' << '.rubocop.yml'
|
|
29
|
+
task.patterns = ['lib/**/*.rb']
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
require "cane/rake_task"
|
|
33
|
+
desc "Run cane to check quality metrics"
|
|
34
|
+
Cane::RakeTask.new do |cane|
|
|
35
|
+
cane.canefile = "./.cane"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "Run all quality tasks"
|
|
39
|
+
task :quality => [:cane, :style, :stats]
|
|
40
|
+
|
|
41
|
+
require "yard"
|
|
42
|
+
YARD::Rake::YardocTask.new
|
|
43
|
+
|
|
44
|
+
desc "Generate gem dependency graph"
|
|
45
|
+
task :viz do
|
|
46
|
+
Bundler.with_clean_env do
|
|
47
|
+
sh "bundle viz --without test development guard " \
|
|
48
|
+
"--requirements --version"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
task :default => [:test, :quality]
|
|
@@ -0,0 +1,27 @@
|
|
|
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 = ""
|
|
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
|
+
|
|
26
|
+
spec.add_dependency "test-kitchen", "~> 1.4"
|
|
27
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
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 :processor_count, 2
|
|
41
|
+
default_config :password
|
|
42
|
+
# because test-kitchen defaults to the wrong value
|
|
43
|
+
default_config :username, 'Administrator'
|
|
44
|
+
default_config :ip_address
|
|
45
|
+
default_config :vm_switch
|
|
46
|
+
|
|
47
|
+
include Kitchen::Driver::PowerShellScripts
|
|
48
|
+
|
|
49
|
+
def create(state)
|
|
50
|
+
@state = state
|
|
51
|
+
validate_vm_settings
|
|
52
|
+
create_new_differencing_disk
|
|
53
|
+
create_virtual_machine
|
|
54
|
+
update_state
|
|
55
|
+
instance.transport.connection(@state).wait_until_ready
|
|
56
|
+
info("Hyper-V instance #{instance.to_str} created.")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def destroy(state)
|
|
60
|
+
@state = state
|
|
61
|
+
return unless vm_exists
|
|
62
|
+
instance.transport.connection(state).close
|
|
63
|
+
remove_virtual_machine
|
|
64
|
+
remove_differencing_disk
|
|
65
|
+
info("The Hyper-V instance #{instance.to_str} has been removed.")
|
|
66
|
+
state.delete(:id)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def validate_vm_settings
|
|
72
|
+
return if config[:vm_switch]
|
|
73
|
+
config[:vm_switch] = (run_ps vm_default_switch_ps)['Name']
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def kitchen_vm_path
|
|
77
|
+
@kitchen_vm_path ||= File.join(config[:kitchen_root], ".kitchen/#{instance.name}")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def differencing_disk_path
|
|
81
|
+
@differencing_disk_path ||= File.join(kitchen_vm_path, 'diff.vhd')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def parent_vhd_path
|
|
85
|
+
@parent_vhd_path ||= File.join(config[:parent_vhd_folder], config[:parent_vhd_name])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def vm_exists
|
|
89
|
+
info('Checking for existing virtual machine.')
|
|
90
|
+
return false unless @state.key?(:id) || @state[:id].nil?
|
|
91
|
+
existing_vm = run_ps ensure_vm_running_ps
|
|
92
|
+
info("Found an exising VM with an ID: #{existing_vm['Id']}")
|
|
93
|
+
return true unless existing_vm.nil? || existing_vm['Id'].nil?
|
|
94
|
+
#fail('Failed to start existing VM.')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def remove_differencing_disk
|
|
98
|
+
info("Removing the differencing disk for #{instance.name}.")
|
|
99
|
+
FileUtils.rm(differencing_disk_path)
|
|
100
|
+
info("Removed the differencing disk for #{instance.name}.")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def create_new_differencing_disk
|
|
104
|
+
return if File.exist? differencing_disk_path
|
|
105
|
+
info("Creating differencing disk for #{instance.name}.")
|
|
106
|
+
run_ps new_differencing_disk_ps
|
|
107
|
+
info("Created differencing disk for #{instance.name}.")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def remove_virtual_machine
|
|
111
|
+
info("Deleting virtual machine for #{instance.name}")
|
|
112
|
+
run_ps delete_vm_ps
|
|
113
|
+
info("Deleted virtual machine for #{instance.name}")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def create_virtual_machine
|
|
117
|
+
return if vm_exists
|
|
118
|
+
info("Creating virtual machine for #{instance.name}.")
|
|
119
|
+
new_vm_object = run_ps new_vm_ps
|
|
120
|
+
@state[:id] = new_vm_object['Id']
|
|
121
|
+
info("Created virtual machine for #{instance.name}.")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def update_state
|
|
125
|
+
vm_details
|
|
126
|
+
@state[:id] = @vm['Id']
|
|
127
|
+
@state[:hostname] = @vm['IpAddress']
|
|
128
|
+
@state[:vm_name] = @vm['Name']
|
|
129
|
+
@state[:password] = config[:password]
|
|
130
|
+
@state[:username] = config[:username]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def vm_details
|
|
134
|
+
run_ps set_vm_ipaddress_ps if config[:ip_address]
|
|
135
|
+
@vm = run_ps vm_details_ps
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +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.1.0'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
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 powershell_64_bit
|
|
31
|
+
'c:\windows\sysnative\windowspowershell\v1.0\powershell.exe'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def wrap_command(script)
|
|
35
|
+
base_script_path = File.join(File.dirname(__FILE__), '/../../../support/hyperv.ps1')
|
|
36
|
+
debug("Loading functions from #{base_script_path}")
|
|
37
|
+
new_script = ". #{base_script_path}; " << script
|
|
38
|
+
debug("Wrapped script: #{new_script}")
|
|
39
|
+
"#{powershell_64_bit} -encodedcommand #{encode_command new_script} -outputformat Text"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Convenience method to run a powershell command locally.
|
|
43
|
+
#
|
|
44
|
+
# @param cmd [String] command to run locally
|
|
45
|
+
# @param options [Hash] options hash
|
|
46
|
+
# @see Kitchen::ShellOut.run_command
|
|
47
|
+
# @api private
|
|
48
|
+
def run_ps(cmd, options = {})
|
|
49
|
+
cmd = "echo #{cmd}" if config[:dry_run]
|
|
50
|
+
debug('Preparing to run: ')
|
|
51
|
+
debug(" #{cmd}")
|
|
52
|
+
wrapped_command = wrap_command cmd
|
|
53
|
+
execute_command wrapped_command, options
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# rubocop:disable Metrics/AbcSize
|
|
57
|
+
def execute_command(cmd, options = {})
|
|
58
|
+
debug("#Local Command BEGIN (#{cmd})")
|
|
59
|
+
sh = Mixlib::ShellOut.new(cmd, options)
|
|
60
|
+
sh.run_command
|
|
61
|
+
debug("Local Command END #{Util.duration(sh.execution_time)}")
|
|
62
|
+
fail "Failed: #{sh.stderr}" if sh.error?
|
|
63
|
+
JSON.parse(sh.stdout) if sh.stdout.length > 2
|
|
64
|
+
end
|
|
65
|
+
# rubocop:enable Metrics/AbcSize
|
|
66
|
+
|
|
67
|
+
def new_differencing_disk_ps
|
|
68
|
+
<<-DIFF
|
|
69
|
+
|
|
70
|
+
New-DifferencingDisk -Path "#{differencing_disk_path}" -ParentPath "#{parent_vhd_path}"
|
|
71
|
+
DIFF
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def ensure_vm_running_ps
|
|
75
|
+
<<-RUNNING
|
|
76
|
+
|
|
77
|
+
Assert-VmRunning -ID "#{@state[:id]}" | ConvertTo-Json
|
|
78
|
+
RUNNING
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# rubocop:disable Metrics/MethodLength
|
|
82
|
+
def new_vm_ps
|
|
83
|
+
<<-NEWVM
|
|
84
|
+
|
|
85
|
+
$NewVMParams = @{
|
|
86
|
+
Generation = 1
|
|
87
|
+
MemoryStartupBytes = #{config[:memory_startup_bytes]}
|
|
88
|
+
Name = "#{instance.name}"
|
|
89
|
+
Path = "#{kitchen_vm_path}"
|
|
90
|
+
VHDPath = "#{differencing_disk_path}"
|
|
91
|
+
SwitchName = "#{config[:vm_switch]}"
|
|
92
|
+
ProcessorCount = #{config[:processor_count]}
|
|
93
|
+
}
|
|
94
|
+
New-KitchenVM @NewVMParams | ConvertTo-Json
|
|
95
|
+
NEWVM
|
|
96
|
+
end
|
|
97
|
+
# rubocop:enable Metrics/MethodLength
|
|
98
|
+
|
|
99
|
+
def vm_details_ps
|
|
100
|
+
<<-DETAILS
|
|
101
|
+
|
|
102
|
+
Get-VmDetail -id "#{@state[:id]}" | ConvertTo-Json
|
|
103
|
+
DETAILS
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def delete_vm_ps
|
|
107
|
+
<<-REMOVE
|
|
108
|
+
|
|
109
|
+
$null = Get-VM -ID "#{@state[:id]}" |
|
|
110
|
+
Stop-VM -Force -TurnOff -PassThru |
|
|
111
|
+
Remove-VM -Force
|
|
112
|
+
REMOVE
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def set_vm_ipaddress_ps
|
|
116
|
+
<<-VMIP
|
|
117
|
+
|
|
118
|
+
(Get-VM -id "#{@state[:id]}").NetworkAdapters |
|
|
119
|
+
Set-VMNetworkConfiguration -ipaddress "#{config[:ip_address]}" -subnet 255.255.255.0 |
|
|
120
|
+
ConvertTo-Json
|
|
121
|
+
VMIP
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def vm_default_switch_ps
|
|
125
|
+
<<-VMSWITCH
|
|
126
|
+
Get-DefaultVMSwitch | ConvertTo-Json
|
|
127
|
+
VMSWITCH
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +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
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2012, 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
|
+
gem "minitest"
|
|
20
|
+
gem "minitest-stub-const"
|
|
21
|
+
|
|
22
|
+
if ENV["CODECLIMATE_REPO_TOKEN"]
|
|
23
|
+
require "codeclimate-test-reporter"
|
|
24
|
+
CodeClimate::TestReporter.start
|
|
25
|
+
elsif ENV["COVERAGE"]
|
|
26
|
+
require "simplecov"
|
|
27
|
+
SimpleCov.profiles.define "gem" do
|
|
28
|
+
command_name "Specs"
|
|
29
|
+
|
|
30
|
+
add_filter ".gem/"
|
|
31
|
+
add_filter "/spec/"
|
|
32
|
+
add_filter "/lib/vendor/"
|
|
33
|
+
|
|
34
|
+
add_group "Libraries", "/lib/"
|
|
35
|
+
end
|
|
36
|
+
SimpleCov.start "gem"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
require 'minitest'
|
|
40
|
+
require 'minitest/stub_const'
|
|
41
|
+
require "minitest/autorun"
|
|
42
|
+
require "mocha/setup"
|
|
43
|
+
require "tempfile"
|
data/support/hyperv.ps1
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
|
|
2
|
+
$ProgressPreference = "SilentlyContinue"
|
|
3
|
+
|
|
4
|
+
<<<<<<< HEAD:lib/kitchen/support/hyperv.ps1
|
|
5
|
+
function new-differencingdisk
|
|
6
|
+
=======
|
|
7
|
+
function New-DifferencingDisk
|
|
8
|
+
>>>>>>> rubocop'd and some tests:support/hyperv.ps1
|
|
9
|
+
{
|
|
10
|
+
[cmdletbinding()]
|
|
11
|
+
param ([string[]]$Path, [string]$ParentPath)
|
|
12
|
+
if (-not (test-path $Path))
|
|
13
|
+
{
|
|
14
|
+
$null = new-vhd @psboundparameters -Differencing
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Assert-VmRunning
|
|
19
|
+
{
|
|
20
|
+
[cmdletbinding()]
|
|
21
|
+
param([string]$Id)
|
|
22
|
+
|
|
23
|
+
if ([string]::IsNullOrEmpty($ID))
|
|
24
|
+
{
|
|
25
|
+
$Output = [pscustomobject]@{Name = '';State =''}
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
{
|
|
29
|
+
$Output = Get-VM -Id $ID |
|
|
30
|
+
foreach {
|
|
31
|
+
if ($_.State -notlike 'Running')
|
|
32
|
+
{
|
|
33
|
+
$_ | start-vm -passthru
|
|
34
|
+
}
|
|
35
|
+
else
|
|
36
|
+
{
|
|
37
|
+
$_
|
|
38
|
+
}
|
|
39
|
+
} |
|
|
40
|
+
select Name, Id, State
|
|
41
|
+
}
|
|
42
|
+
$output
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function New-KitchenVM
|
|
46
|
+
{
|
|
47
|
+
[cmdletbinding()]
|
|
48
|
+
param (
|
|
49
|
+
$Generation = 1,
|
|
50
|
+
$MemoryStartupBytes,
|
|
51
|
+
$Name,
|
|
52
|
+
$Path,
|
|
53
|
+
$VHDPath,
|
|
54
|
+
$SwitchName,
|
|
55
|
+
$ProcessorCount
|
|
56
|
+
)
|
|
57
|
+
$null = $psboundparameters.remove('ProcessorCount')
|
|
58
|
+
new-vm @psboundparameters |
|
|
59
|
+
Set-Vm -ProcessorCount $ProcessorCount -passthru |
|
|
60
|
+
Start-Vm -passthru |
|
|
61
|
+
foreach {
|
|
62
|
+
$vm = $_
|
|
63
|
+
do {
|
|
64
|
+
start-sleep -seconds 2
|
|
65
|
+
} while ($vm.state -notlike 'Running')
|
|
66
|
+
$vm
|
|
67
|
+
} |
|
|
68
|
+
select Name, Id, State
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function Get-VmIP($vm)
|
|
72
|
+
{
|
|
73
|
+
$vm.networkadapters.ipaddresses |
|
|
74
|
+
where {$_ -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'} |
|
|
75
|
+
select -first 1
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
Function Set-VMNetworkConfiguration
|
|
79
|
+
{
|
|
80
|
+
[CmdletBinding()]
|
|
81
|
+
Param (
|
|
82
|
+
[parameter(valuefrompipeline)]
|
|
83
|
+
[object]$NetworkAdapter,
|
|
84
|
+
[String[]]$IPAddress=@(),
|
|
85
|
+
[String[]]$Subnet=@()
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
$VM = Get-WmiObject -Namespace 'root\virtualization\v2' -Class 'Msvm_ComputerSystem' | Where-Object { $_.ElementName -eq $NetworkAdapter.VMName }
|
|
89
|
+
$VMSettings = $vm.GetRelated('Msvm_VirtualSystemSettingData') | Where-Object { $_.VirtualSystemType -eq 'Microsoft:Hyper-V:System:Realized' }
|
|
90
|
+
$VMNetAdapters = $VMSettings.GetRelated('Msvm_SyntheticEthernetPortSettingData')
|
|
91
|
+
|
|
92
|
+
$NetworkSettings = @()
|
|
93
|
+
foreach ($NetAdapter in $VMNetAdapters) {
|
|
94
|
+
if ($NetAdapter.Address -eq $NetworkAdapter.MacAddress) {
|
|
95
|
+
$NetworkSettings = $NetworkSettings + $NetAdapter.GetRelated("Msvm_GuestNetworkAdapterConfiguration")
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
$NetworkSettings[0].IPAddresses = $IPAddress
|
|
100
|
+
$NetworkSettings[0].Subnets = $Subnet
|
|
101
|
+
$NetworkSettings[0].ProtocolIFType = 4096
|
|
102
|
+
$NetworkSettings[0].DHCPEnabled = $false
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
$Service = Get-WmiObject -Class "Msvm_VirtualSystemManagementService" -Namespace "root\virtualization\v2"
|
|
106
|
+
$setIP = $Service.SetGuestNetworkAdapterConfiguration($VM, $NetworkSettings[0].GetText(1))
|
|
107
|
+
|
|
108
|
+
if ($setip.ReturnValue -eq 4096) {
|
|
109
|
+
$job=[WMI]$setip.job
|
|
110
|
+
|
|
111
|
+
while ($job.JobState -eq 3 -or $job.JobState -eq 4) {
|
|
112
|
+
start-sleep 1
|
|
113
|
+
$job=[WMI]$setip.job
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if ($job.JobState -ne 7) {
|
|
117
|
+
$job.GetError()
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
(Get-VM -id $NetworkAdapter.VmId).NetworkAdapter | select Name, IpAddress
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function Get-VmDetail
|
|
124
|
+
{
|
|
125
|
+
[cmdletbinding()]
|
|
126
|
+
param($Id)
|
|
127
|
+
|
|
128
|
+
get-vm -id $Id |
|
|
129
|
+
foreach {
|
|
130
|
+
$vm = $_
|
|
131
|
+
do {
|
|
132
|
+
start-sleep -seconds 1
|
|
133
|
+
} while (-not (Get-VmIP $vm))
|
|
134
|
+
|
|
135
|
+
[pscustomobject]@{
|
|
136
|
+
Name = $vm.name
|
|
137
|
+
Id = $vm.ID
|
|
138
|
+
IpAddress = (Get-VmIP $vm)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
<<<<<<< HEAD:lib/kitchen/support/hyperv.ps1
|
|
142
|
+
=======
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function Get-DefaultVMSwitch
|
|
146
|
+
{
|
|
147
|
+
Get-VMSwitch | Select -First 1
|
|
148
|
+
>>>>>>> rubocop'd and some tests:support/hyperv.ps1
|
|
149
|
+
}
|
metadata
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: kitchen-hyperv
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Steven Murawski
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-05-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.7'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.7'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: pry
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.10'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.10'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: test-kitchen
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.4'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.4'
|
|
69
|
+
description: Hyper-V Driver for Test-Kitchen
|
|
70
|
+
email:
|
|
71
|
+
- steven.murawski@gmail.com
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- ".cane"
|
|
77
|
+
- ".gitignore"
|
|
78
|
+
- ".rubocop.yml"
|
|
79
|
+
- Gemfile
|
|
80
|
+
- LICENSE.txt
|
|
81
|
+
- README.md
|
|
82
|
+
- Rakefile
|
|
83
|
+
- kitchen-hyperv.gemspec
|
|
84
|
+
- lib/kitchen/driver/hyperv.rb
|
|
85
|
+
- lib/kitchen/driver/hyperv_version.rb
|
|
86
|
+
- lib/kitchen/driver/powershell.rb
|
|
87
|
+
- spec/kitchen/driver/hyperv_spec.rb
|
|
88
|
+
- spec/spec_helper.rb
|
|
89
|
+
- spec/support/hyperv.Tests.ps1
|
|
90
|
+
- support/hyperv.ps1
|
|
91
|
+
homepage: ''
|
|
92
|
+
licenses:
|
|
93
|
+
- Apache 2
|
|
94
|
+
metadata: {}
|
|
95
|
+
post_install_message:
|
|
96
|
+
rdoc_options: []
|
|
97
|
+
require_paths:
|
|
98
|
+
- lib
|
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - ">="
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '0'
|
|
109
|
+
requirements: []
|
|
110
|
+
rubyforge_project:
|
|
111
|
+
rubygems_version: 2.4.4
|
|
112
|
+
signing_key:
|
|
113
|
+
specification_version: 4
|
|
114
|
+
summary: Hyper-V Driver for Test-Kitchen
|
|
115
|
+
test_files:
|
|
116
|
+
- spec/kitchen/driver/hyperv_spec.rb
|
|
117
|
+
- spec/spec_helper.rb
|
|
118
|
+
- spec/support/hyperv.Tests.ps1
|
|
119
|
+
has_rdoc:
|