kitchen-vmm 0.1.1

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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjJiM2EyYmI2YjE1MTgzYmRkM2JkNWY2NjVkMDlmNTM5OTc2OTQzNw==
5
+ data.tar.gz: !binary |-
6
+ OTgxMzBkZmYyMWQ2MDM1ZTc1N2I3NTAzOWE1MTQ5NTIyMzViYjUxYg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YTNkMzUyOTFjODM4MmVlMjYzZDY4MjlmNmE1YjFjMWYyYTVmMDhjOTk3NjUx
10
+ YWU2NjcwOTJiMDBmYjhlMmZhYjgzMjQzN2ZkMTVhOGRhODFmOTAxNGE2ZjQz
11
+ OTlkZTVhY2E3ODdjMGFlNWFjYzE5MWVmYmM2MmVmZTllNmYxM2E=
12
+ data.tar.gz: !binary |-
13
+ MWI1M2NmNmE0ODQ4OWM5NzM4NmQwM2QyY2UyNzQ0YjZkNjNiM2MzNGRkMzlm
14
+ NWI0MzA1ZGFjNzM4ZDQ4NjdjYjM1Nzc3NDA4NzU1MTM2YTg1MjQ3YTk3MWYw
15
+ MzBkZDViNDk4NTUwMDkxYTY5YjgwMjM0NjliNTQ5ZDRiZWE0NmY=
data/.cane ADDED
@@ -0,0 +1,2 @@
1
+ --no-doc
2
+ --style-measure 100
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ Metrics/LineLength:
2
+ Max: 100
3
+
4
+ Style/Documentation:
5
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ bundler_args: --without doc guard --jobs 7
5
+ script: bundle exec rake build
6
+ deploy:
7
+ provider: rubygems
8
+ api_key:
9
+ secure: j4qKRcVgSpULZXlSyGSt5WmHTCazXmH1uNNcfpUioIMOZkceh7CWspMps3FWSPIbINqLoSfzK4hJbUcnoqSZ79ho8NBbcNvqTIJXxFoYbhTgTlUwdNovgto4WmqwEYDSWp+ShryLqLkRY6WGFFUu2ve4eRum1akQcaxkQC1vjcKsQXUDFCY8qW6unsFQivV3YMX+baTHcOpB/YyEqwkHq5N6173U7eM0Rmu5F39PIKovb/wBLYomuV7vDH7kGvxernVguUNC0azgLe9j1lTQT1bkmn78pCwb9PYeW8xkkTWW0DSZf5n9TSG1jhECGUkmeNJbMBpFioApvYfEoyKq58vPPJ5eyjz5rvOshfwIefzOgdS6RoHMfWzA1StzPj3iQwnhow70vhU4vZJ3HI8pTyCv2szhItdBL6Z4Hc90KrXKX6HaBuRHw2wv48+tvoKU3hnguswrYer7nSOSfTKMxMHTNoevlieRNX/3Suh7/8laV1eobYRv7yUSkGpFdeT+8FqlSBJVG/A6fyct/DqOhMLV48y8Rc2pqDTdVJ638LAwdcUhvvqYe04i5Zxr7Qa0Wi89bHLRhR0R3o5pvgVAJt3wjVKKHz0kuN1cbP60B4d/Xmp8lQRL0MADAVfaiSJvI/vDMCt48/qBzRe4IQBMwI4iMCwDZ56DTyXKaGO08x8=
10
+ gem: kitchen-vmm
11
+ on:
12
+ tags: true
13
+ repo: jarig/kitchen-vmm
14
+ all_branches: true
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.1.0 / 06-11-2016
2
+
3
+ * Initial version
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kitchen-vmm.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jaroslav
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,228 @@
1
+ # Kitchen::VMM
2
+
3
+ |Travis CI|Gem|
4
+ |-----|-----|
5
+ | [![Build Status](https://travis-ci.org/jarig/kitchen-vmm.svg?branch=master)](https://travis-ci.org/jarig/kitchen-vmm)|[![Gem Version](https://badge.fury.io/rb/kitchen-vmm.svg)](http://badge.fury.io/rb/kitchen-vmm)|
6
+
7
+ Supports: Windows, Linux
8
+
9
+ Virtual Machine Management plugin for Kitchen.
10
+
11
+ This provider will allow you to create VMs in the remote Virtual Machine Manager via Test Kitchen.
12
+
13
+ ## Installation
14
+
15
+ Install kitchen-vmm gem
16
+
17
+ ```ruby
18
+ chef gem 'kitchen-vmm'
19
+ ```
20
+
21
+ ## Prerequisites
22
+
23
+ 1. You should have template in your VMM which has following things setup:
24
+ - WinRM and firewall configured, using:
25
+ ```
26
+ winrm quickconfig
27
+ ```
28
+ - Either domain or local user with admin rights.
29
+ You can specify its creds using
30
+ (either in cookbook .kitchen.yml or in $HOME/.kitchen/config.yml):
31
+ ```yaml
32
+ transport:
33
+ name: winrm
34
+ username: <username>
35
+ password: <password>
36
+ ```
37
+ - Once VM created in VMM it should automatically get IP assigned, as well as it should be directly accessible from your machine.
38
+ 2. Run kitchen commands under **Administrator** (in admin shell).
39
+
40
+ ## Usage
41
+
42
+ In the .kitchen.yml
43
+
44
+ ### Configure Driver
45
+
46
+ Globally
47
+ ```yaml
48
+ driver:
49
+ name: vmm
50
+ vm_template_name: default-template
51
+ vm_host_group_name: default-group
52
+ ```
53
+
54
+ Or per platform
55
+ ```yaml
56
+ platforms:
57
+ - name: platform1
58
+ driver:
59
+ name: vmm
60
+ vm_template_name: 'overidden-template'
61
+ vm_host_group_name: overidden-group
62
+ ```
63
+
64
+ ### Configure Transport
65
+
66
+ In case you need to create both Linux and Windows machines, then different transport types have to be used(ssh for linux and winrm for windows).
67
+ For easier maintenance and cleaner configuration you can create global kitchen configuration under $HOME/<username>/.kitchen/config.yml with following contents:
68
+
69
+ ```yaml
70
+ <% WINRM_USERNAME = 'winrm_user' %>
71
+ <% WINRM_PASSWORD = 'winrm_dassword' %>
72
+
73
+ # default transport settings
74
+ transport:
75
+ name: ssh
76
+ username: ssh_user
77
+ ssh_key: <path_to_key>
78
+ # winrm related settings that do not clash with ssh ones can also go here
79
+ # example: winrm_transport
80
+ ```
81
+
82
+ Then in your kitchen.yml specify transport either for platform or suite
83
+ ```yaml
84
+ suites:
85
+ - name: windows-basic
86
+ run_list:
87
+ - recipe[windows-basic::default]
88
+ transport:
89
+ name: winrm
90
+ username: <%= WINRM_USERNAME %>
91
+ password: <%= WINRM_PASSWORD %>
92
+ ```
93
+
94
+ ### Required parameters:
95
+
96
+ * #### vm_template_name
97
+
98
+ VMM template name that will be used for VM creation.
99
+
100
+ ```yaml
101
+ driver_config:
102
+ ...
103
+ vm_template_name: vagrant-template-w8.1-64
104
+ ```
105
+
106
+ * #### vm_host_group_name
107
+
108
+ VMM host group where VM will be placed.
109
+ NOTE: Your template or *vm_hardware_profile* should match it as well.
110
+
111
+ ```yaml
112
+ driver_config:
113
+ ...
114
+ vm_host_group_name: 'Host-Group-Name'
115
+ ```
116
+
117
+ * #### vmm_server_address
118
+
119
+ IP/Hostname of the VMM server where VMs are going to be created.
120
+ ```yaml
121
+ driver_config:
122
+ ...
123
+ vmm_server_address: '192.124.125.10'
124
+ ```
125
+
126
+ ### Optional parameters:
127
+
128
+ * #### vm_name
129
+
130
+ Specify name of a VM that is going to be created. Default is Kitchen instance name.
131
+ If VM with such name already exists driver might get random number appended to it.
132
+
133
+ ```yaml
134
+ driver_config:
135
+ ...
136
+ vm_name: 'my-vm-in-vmm'
137
+ ```
138
+
139
+ * #### vm_hardware_profile
140
+
141
+ Specify alternate HW profile that should be used instead of the one provided in your original template.
142
+
143
+ ```yaml
144
+ driver_config:
145
+ ...
146
+ vm_hardware_profile: 'TestHW-8core-8gb'
147
+ ```
148
+
149
+ * #### proxy_server_address
150
+
151
+ If your local machine do not have direct access to the machine that hosts VMM, but you have proxy server(jump box) you can specify its IP in *proxy_server_address* property.
152
+
153
+ ```yaml
154
+ driver_config:
155
+ ...
156
+ proxy_server_address: 'my-proxy-to-vmm'
157
+ ```
158
+
159
+ * #### ad_server
160
+
161
+ You can tell the provider to move your VM under some particular OU once it's created.
162
+
163
+ URL of AD server. Can be derived by running ```echo %LOGONSERVER%``` command in CMD of the VM environment.
164
+
165
+ Example:
166
+ ```yaml
167
+ driver_config:
168
+ ...
169
+ ad_server: 'my-ad-server.some.domain.local'
170
+ ```
171
+
172
+ * #### ad_source_path
173
+
174
+ Base DN container where VM appears(and it will be moved from) once it's created.
175
+ Example:
176
+ ```yaml
177
+ driver_config:
178
+ ...
179
+ ad_source_path: 'CN=Computers,DC=some,DC=domain,DC=local'
180
+ ```
181
+
182
+ * #### ad_target_path
183
+
184
+ New AD path where VM should be moved to.
185
+ Example:
186
+ ```yaml
187
+ driver_config:
188
+ ...
189
+ ad_target_path: 'OU=Vagrant,OU=Chef-Nodes,DC=some,DC=domain,DC=local'
190
+ ```
191
+
192
+
193
+ ## Troubleshooting
194
+
195
+ ### Authorization failure
196
+
197
+ Check that winrm is configured properly in the VM, if username/password is local then ensure you've set winrm transport to plaintext for kitchen.
198
+ ```yaml
199
+ transport:
200
+ name: winrm
201
+ ...
202
+ winrm_transport: plaintext
203
+ ```
204
+ and enable basic auth and unencrypted connection in a VM.
205
+ ```
206
+ winrm set winrm/config/service/auth @{Basic="true"}
207
+ winrm set winrm/config/service @{AllowUnencrypted="true"}
208
+ ```
209
+ and on your local machine
210
+ ```
211
+ winrm set winrm/config/client/auth @{Basic="true"}
212
+ ```
213
+
214
+ ### Unencrypted traffic is currently disabled in the client configuration
215
+
216
+ Run following command on your machine as well:
217
+ ```
218
+ winrm set winrm/config/service @{AllowUnencrypted="true"}
219
+ ```
220
+
221
+
222
+ ## Contributing
223
+
224
+ 1. Fork it ( https://github.com/[my-github-username]/kitchen-vmm/fork )
225
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
226
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
227
+ 4. Push to the branch (`git push origin my-new-feature`)
228
+ 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,31 @@
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/vmm_version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "kitchen-vmm"
9
+ spec.version = Kitchen::Driver::VMM_VERSION
10
+ spec.authors = ["Jaroslav Gorjatsev"]
11
+ spec.email = ["gjarik@gmail.com"]
12
+ spec.summary = 'Virtual Machine Manager Driver for Test-Kitchen'
13
+ spec.description = 'Virtual Machine Manager Driver for Test-Kitchen'
14
+ spec.homepage = "https://github.com/jarig/kitchen-vmm"
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
+
30
+ spec.add_dependency "test-kitchen", "~> 1.4"
31
+ end
@@ -0,0 +1,102 @@
1
+ require 'kitchen'
2
+ require 'kitchen/driver'
3
+ require 'kitchen/driver/vmm_version'
4
+ require 'kitchen/driver/vmm_utils'
5
+ require 'mixlib/shellout'
6
+ require 'fileutils'
7
+ require 'JSON'
8
+
9
+ module Kitchen
10
+
11
+ module Driver
12
+
13
+ # Driver for VMM
14
+ class Vmm < Kitchen::Driver::Base
15
+
16
+ kitchen_driver_api_version 2
17
+ plugin_version Kitchen::Driver::VMM_VERSION
18
+
19
+ default_config :vm_template_name
20
+ default_config :vm_host_group_name
21
+ default_config :vmm_server_address
22
+ default_config :vm_name, nil
23
+ default_config :vm_hardware_profile, ''
24
+ default_config :proxy_server_address, ''
25
+ default_config :ad_server, ''
26
+ default_config :ad_source_path, ''
27
+ default_config :ad_target_path, ''
28
+
29
+ def create(state)
30
+ @state = state
31
+ validate_vm_settings
32
+ create_virtual_machine
33
+ info("VM instance #{instance.to_str} created.")
34
+ end
35
+
36
+ def destroy(state)
37
+ @state = state
38
+ instance.transport.connection(state).close
39
+ remove_virtual_machine
40
+ info("The VM instance #{instance.to_str} has been removed.")
41
+ state.delete(:id)
42
+ end
43
+
44
+ private
45
+
46
+ include Kitchen::Driver::VMMUtils
47
+
48
+ def validate_vm_settings
49
+ raise "Missing vmm_server_address" unless config[:vmm_server_address]
50
+ end
51
+
52
+ def kitchen_vm_path
53
+ @kitchen_vm_path ||= File.join(config[:kitchen_root], ".kitchen/#{instance.name}")
54
+ end
55
+
56
+ def remove_virtual_machine
57
+ info("Deleting virtual machine for #{instance.name}")
58
+ options = {
59
+ vmm_server_address: config[:vmm_server_address],
60
+ proxy_server_address: config[:proxy_server_address],
61
+ vm_id: @state[:id]
62
+ }
63
+ execute('delete_vm.ps1', options)
64
+ info("Deleted virtual machine for #{instance.name}")
65
+ end
66
+
67
+ def vm_exists
68
+ false
69
+ end
70
+
71
+ def create_virtual_machine
72
+ return if vm_exists
73
+ info("Creating virtual machine for #{instance.name}.")
74
+ options = {
75
+ vmm_server_address: config[:vmm_server_address],
76
+ proxy_server_address: config[:proxy_server_address],
77
+ vm_hardware_profile: config[:vm_hardware_profile],
78
+ vm_name: config[:vm_name] || instance.name,
79
+ vm_template_name: config[:vm_template_name],
80
+ vm_host_group_name: config[:vm_host_group_name],
81
+ ad_server: config[:ad_server],
82
+ ad_source_path: config[:ad_source_path],
83
+ ad_target_path: config[:ad_target_path]
84
+ }
85
+
86
+ #
87
+ info("Creating and registering VM in the VMM (#{options[:vmm_server_address]})...")
88
+ if options[:ad_server] && options[:ad_source_path] && options[:ad_target_path]
89
+ info(" ..and moving it under #{options[:ad_target_path]} after it's created.")
90
+ end
91
+ vm = execute('import_vm.ps1', options)
92
+ info("Successfully created the VM with name: #{vm['name']}")
93
+ @state[:id] = vm['id']
94
+ @state[:hostname] = vm['hostname']
95
+ @state[:vm_name] = vm['name']
96
+
97
+ info("Created virtual machine for #{instance.name}.")
98
+ end
99
+
100
+ end # class VMM
101
+ end # module Driver
102
+ end # module Kitchen
@@ -0,0 +1,84 @@
1
+ module Kitchen
2
+ module Driver
3
+ module VMMUtils
4
+
5
+ ERROR_REGEXP = /===Begin-Error===(.+?)===End-Error===/m
6
+ OUTPUT_REGEXP = /===Begin-Output===(.+?)===End-Output===/m
7
+
8
+ def execute(path, options)
9
+ r = execute_powershell(path, options)
10
+ if r.error?
11
+ raise ("Powershell failed, #{path}:#{r.stderr}")
12
+ end
13
+
14
+ # We only want unix-style line endings within Vagrant
15
+ r.stdout.gsub!("\r\n", "\n")
16
+ r.stderr.gsub!("\r\n", "\n")
17
+
18
+ error_match = ERROR_REGEXP.match(r.stdout)
19
+ output_match = OUTPUT_REGEXP.match(r.stdout)
20
+
21
+ if error_match
22
+ data = JSON.parse(error_match[1])
23
+
24
+ # We have some error data.
25
+ raise "#{path}:#{data["error"]}"
26
+ end
27
+
28
+ # Nothing
29
+ return nil if !output_match
30
+ return JSON.parse(output_match[1])
31
+ end
32
+
33
+ def execute_powershell(path, options = {})
34
+ lib_path = Pathname.new(File.expand_path("../../../../support", __FILE__))
35
+ script_path = lib_path.join(path).to_s.gsub("/", "\\")
36
+ ps_options = ''
37
+ options.each do |key, value|
38
+ unless value.nil?
39
+ ps_options += " -#{key} \"#{value}\""
40
+ end
41
+ end
42
+ #
43
+ stdout_stream_reader = StreamReader.new do |line|
44
+ info(line)
45
+ end
46
+ ps_run = Mixlib::ShellOut.new("powershell.exe -File #{script_path} #{ps_options} -ErrorAction Stop")
47
+ debug("Command: #{ps_run.command}")
48
+ ps_run.live_stdout = stdout_stream_reader
49
+ ps_run.run_command
50
+ return ps_run
51
+ end
52
+
53
+ # for powershell stdout read
54
+ class StreamReader
55
+ require 'stringio'
56
+
57
+ def initialize(&block)
58
+ @block = block
59
+ @buffer = StringIO.new
60
+ @buffer.sync = true if @buffer.respond_to?(:sync)
61
+ end
62
+
63
+ def <<(chunk)
64
+ overflow = ''
65
+
66
+ @buffer.write(chunk)
67
+ @buffer.rewind
68
+
69
+ @buffer.each_line do |line|
70
+ if line.match(/\r?\n/)
71
+ @block.call(line.strip)
72
+ else
73
+ overflow = line
74
+ end
75
+ end
76
+
77
+ @buffer.truncate(@buffer.rewind)
78
+ @buffer.write(overflow)
79
+ end
80
+ end # StreamReader
81
+
82
+ end # module VMMUtils
83
+ end # module Driver
84
+ end # module Kitchen
@@ -0,0 +1,7 @@
1
+ #
2
+
3
+ module Kitchen
4
+ module Driver
5
+ VMM_VERSION = '0.1.1'
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ Param(
2
+ [Parameter(Mandatory=$true)]
3
+ [string]$vm_id,
4
+ [Parameter(Mandatory=$true)]
5
+ [string]$vmm_server_address,
6
+ [string]$proxy_server_address=$null
7
+ )
8
+
9
+
10
+ # Include the following modules
11
+ $Dir = Split-Path $script:MyInvocation.MyCommand.Path
12
+ . ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
13
+ . ([System.IO.Path]::Combine($Dir, "utils\vmm_executor.ps1"))
14
+
15
+
16
+ $script_block = {
17
+ # external vars
18
+ $vm_id = $using:vm_id
19
+
20
+ # Get VM
21
+ $vm = Get-SCVirtualMachine -ID $vm_id -ErrorAction Ignore
22
+ if ( $vm )
23
+ {
24
+ if ( $vm.status -eq 'Running' )
25
+ {
26
+ $res = Stop-VM $vm
27
+ }
28
+ $res = Remove-VM $vm
29
+ } else
30
+ {
31
+ Write-Host "VM do not exists or not found: $vm_id"
32
+ }
33
+ }
34
+
35
+ execute $script_block $vmm_server_address $proxy_server_address
@@ -0,0 +1,165 @@
1
+ Param(
2
+ [Parameter(Mandatory=$true)]
3
+ [string]$vm_name,
4
+ [Parameter(Mandatory=$true)]
5
+ [string]$vmm_server_address,
6
+ [Parameter(Mandatory=$true)]
7
+ [string]$vm_template_name,
8
+ [Parameter(Mandatory=$true)]
9
+ [string]$vm_host_group_name,
10
+ [string]$vm_hardware_profile=$null,
11
+ [string]$proxy_server_address=$null,
12
+ [string]$ad_server=$null,
13
+ [string]$ad_source_path=$null,
14
+ [string]$ad_target_path=$null
15
+ )
16
+
17
+ # Include the following modules
18
+ $Dir = Split-Path $script:MyInvocation.MyCommand.Path
19
+ . ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
20
+ . ([System.IO.Path]::Combine($Dir, "utils\vmm_executor.ps1"))
21
+
22
+
23
+ $script_block = {
24
+ # external vars
25
+ $vm_name = $using:vm_name
26
+ $vm_host_group_name = $using:vm_host_group_name
27
+ $server_address = $using:vmm_server_address
28
+ $vm_template_name = $using:vm_template_name
29
+ $vm_hardware_profile_name = $using:vm_hardware_profile
30
+ $ad_server = $using:ad_server
31
+ $ad_source_path = $using:ad_source_path
32
+ $ad_target_path = $using:ad_target_path
33
+
34
+ $description = "VM created by chef test-kitchen for testing purposes"
35
+ $MinFreeSpaceGB = 300 #
36
+
37
+ $domain_name = $null
38
+ if ( $ad_source_path )
39
+ {
40
+ $domain_name = $($ad_source_path.split(",")|Where {$_.Contains("DC")}| ForEach-Object { $_.replace("DC=", "") }) -join "."
41
+ }
42
+ # Truncate vm name to 15 chars due to windows limitation
43
+ $vm_name = $vm_name.substring(0, [math]::Min(15, $vm_name.length))
44
+
45
+ # get VM Template object
46
+ $VMTemplate = Get-SCVMTemplate -Name $vm_template_name
47
+ # get host group
48
+ $VMHostGroup = Get-VMHostGroup -Name $vm_host_group_name
49
+ #
50
+ Write-Host "Creating VM from template $vm_template_name"
51
+
52
+ $tries = 10
53
+ while ( $tries -gt 0 ) {
54
+ $vm = Get-SCVirtualMachine -Name $vm_name
55
+ if ( $vm -eq $null ) {
56
+ break
57
+ } else {
58
+ $vm_name = $vm_name.substring(0, [math]::Min(14, $vm_name.length)) + $(Get-Random -Minimum 0 -Maximum 10)
59
+ }
60
+ $tries -= 1
61
+ }
62
+ if ( $vm -eq $null )
63
+ {
64
+ # Get and sort the host ratings for all the hosts in the host group.
65
+ # select host which has rating > 0
66
+ $hRatingHashParams = @{VMTemplate=$VMTemplate;
67
+ DiskSpaceGB=$MinFreeSpaceGB;
68
+ VMName=$vm_name;
69
+ VMHostGroup=$VMHostGroup;
70
+ }
71
+
72
+ if ( $vm_hardware_profile_name )
73
+ {
74
+ $vm_hardware_profile = Get-SCHardwareProfile | where {$_.Name -eq $vm_hardware_profile_name}
75
+ Write-host "Applying hardware profile: $vm_hardware_profile_name"
76
+ $VMTemplate = New-SCVMTemplate -Name "Temporary Template$([guid]::NewGuid())" -VMTemplate $VMTemplate -HardwareProfile $vm_hardware_profile
77
+ }
78
+
79
+ $VMHost = $null
80
+ $HostRatings = @(Get-SCVMHostRating @hRatingHashParams | Sort-Object -property Rating -descending)
81
+ If($HostRatings.Count -eq 0) { throw "No hosts meet the requirements." }
82
+ $VMHost = $HostRatings[0].VMHost
83
+
84
+ # If there is at least one host that will support the virtual machine, create the virtual machine on the highest-rated host.
85
+ If ($VMHost -ne $null )
86
+ {
87
+ # get placement path
88
+ $path = $($VMHost.DiskVolumes | where { $_.IsAvailableForPlacement -eq $True } | Sort-Object -Property FreeSpace -Descending)[0]
89
+ Write-Host "----- Creating VM ----"
90
+ Write-Host "Host: $VMHost, $($VMHost.CPUManufacturer) $($VMHost.Rank)"
91
+ Write-host "Placement path: $($path.Name), Free space - $($path.FreeSpace/1024/1024/1024) GB"
92
+ Write-Host "Name: $vm_name"
93
+ Write-Host "----- ----------- ----"
94
+ # Create the virtual machine.
95
+ $vmCreateParams = @{Name=$vm_name;
96
+ Path=$path.Name;
97
+ VMHost = $VMHost;
98
+ VMTemplate=$VMTemplate;
99
+ Description=$description;
100
+ ComputerName=$vm_name;
101
+ BlockDynamicOptimization=$false;
102
+ ReturnImmediately = $false; AnswerFile = $null;
103
+ StartAction = "NeverAutoTurnOnVM";
104
+ StopAction = "TurnOffVM";
105
+ StartVM=$true;
106
+ ErrorAction="stop";
107
+ }
108
+
109
+ $vm = New-SCVirtualMachine @vmCreateParams
110
+ } else {
111
+ Write-Error "Cannot find suitable host for the VM."
112
+ }
113
+ } else {
114
+ Write-Warning "Machine $vm_name already exists on host $($vm.VMHost.Name)"
115
+ }
116
+ Write-Host "Machine created."
117
+ # try to move it in AD
118
+ try
119
+ {
120
+ # move it to under AD path if required
121
+ if ($ad_target_path -ne $null -and $ad_source_path -ne $null -and $ad_server -ne $null)
122
+ {
123
+ Write-host "Moving it AD under $ad_target_path"
124
+ $cred_param = @{}
125
+ if ($proxy_credential)
126
+ {
127
+ # if proxy used to overcome credssp auth
128
+ $cred_param["Credential"] = $proxy_credential
129
+ }
130
+ $ad_res = Get-ADComputer -Identity:"CN=$vm_name,$ad_source_path" -Server:$ad_server -ErrorAction Ignore @cred_param
131
+ if ( $ad_res -ne $null )
132
+ {
133
+ Move-ADObject -Identity:"CN=$vm_name,$ad_source_path" -TargetPath:$ad_target_path -Server:$ad_server @cred_param
134
+ }
135
+ }
136
+ } catch
137
+ {
138
+ Write-Warning "Couldn't move under specified OU: $_"
139
+ }
140
+
141
+ $fqdn = $vm.ComputerNameString
142
+ if ( ! $fqdn.contains($domain_name) )
143
+ {
144
+ # Linux machines do not always set domain name propery for example
145
+ $fqdn = "$fqdn.$domain_name"
146
+ }
147
+
148
+ # return vm object
149
+ @{
150
+ vm = $vm
151
+ fqdn = $fqdn
152
+ ip = $ip
153
+ }
154
+ }
155
+
156
+ $result = execute $script_block $vmm_server_address $proxy_server_address
157
+
158
+ $resultHash = @{
159
+ hostname = $result.fqdn
160
+ name = $result.vm.Name
161
+ id = $result.vm.id.guid
162
+ }
163
+
164
+ $result = ConvertTo-Json $resultHash
165
+ Write-Output-Message $result
@@ -0,0 +1,26 @@
1
+
2
+ # get either cached or entered in the prompt credentials
3
+ function Get-Creds($server_address, $prompt_message, $username = $null, $password = $null )
4
+ {
5
+ $temp_folder = $env:temp
6
+ # get creds
7
+ $cred_file = $temp_folder + "\creds_$server_address.clixml"
8
+ if ( Test-Path $cred_file )
9
+ {
10
+ $credential = Import-CliXml $cred_file
11
+ } else
12
+ {
13
+ if ( $username -ne $null -and $password -ne $null )
14
+ {
15
+ # creds passed, use them
16
+ $password = ConvertTo-SecureString -string $password -asPlainText -force
17
+ $credential = New-Object System.Management.Automation.PSCredential($username, $password)
18
+ } else
19
+ {
20
+ $credential = Get-Credential -Message $prompt_message
21
+ }
22
+ $credential | Export-CliXml $cred_file
23
+ Write-host "Credentials for $server_address is cached in $cred_file"
24
+ }
25
+ return $credential
26
+ }
@@ -0,0 +1,28 @@
1
+
2
+ # add $address to trusted host list
3
+ function Add-To-Trusted($address)
4
+ {
5
+ $trusted_hosts = get-item wsman:\localhost\Client\TrustedHosts
6
+ if ( $address -as [ipaddress] -and !$trusted_hosts.Value.Contains($address) )
7
+ {
8
+ if ($trusted_hosts.Value)
9
+ {
10
+ $new_th_values = "$($trusted_hosts.Value),$address"
11
+ } else {
12
+ $new_th_values = $address
13
+ }
14
+ set-item wsman:\localhost\Client\TrustedHosts $new_th_values -Force
15
+ }
16
+ }
17
+
18
+ # remove $address from trusted host list
19
+ function Remove-From-Trusted($address)
20
+ {
21
+ # remove $address from trusted hosts
22
+ $trusted_hosts = get-item wsman:\localhost\Client\TrustedHosts
23
+ if ( $trusted_hosts.Value.Contains($address) )
24
+ {
25
+ $new_th_values = $trusted_hosts.Value -replace ",?$address", ""
26
+ set-item wsman:\localhost\Client\TrustedHosts $new_th_values -Force
27
+ }
28
+ }
@@ -0,0 +1,43 @@
1
+ #
2
+ $Dir = Split-Path $script:MyInvocation.MyCommand.Path
3
+ . ([System.IO.Path]::Combine($Dir, "manage_credentials.ps1"))
4
+ . ([System.IO.Path]::Combine($Dir, "manage_trusted_hosts.ps1"))
5
+
6
+ # execute script block for VMM
7
+ function execute($block, $vmm_server_address, $proxy_server_address)
8
+ {
9
+ $proxy_credential = $null
10
+ if ($proxy_server_address -ne $null )
11
+ {
12
+ $proxy_credential = Get-Creds $proxy_server_address "Credentials for proxy server: $proxy_server_address"
13
+ }
14
+ $vmm_credential = Get-Creds $vmm_server_address "Credentials for VMM server: $vmm_server_address"
15
+
16
+ #
17
+ $init_vmm_block = {
18
+ try {
19
+ ipmo 'C:\Program Files\Microsoft System Center 2012 R2\Virtual Machine Manager\bin\psModules\virtualmachinemanager'
20
+ } catch
21
+ {
22
+ write-error 'You need to install Virtual Machine Manager R2 client first.'
23
+ throw $_.Exception
24
+ }
25
+ #
26
+ $proxy_credential = $using:proxy_credential # make those available within $block as well
27
+ $vmm_server = Get-VMMServer -ComputerName $using:vmm_server_address -Credential $using:vmm_credential
28
+ }
29
+ # prepend init block to execution block
30
+ $block_to_run = [ScriptBlock]::Create($init_vmm_block.ToString() + $block.ToString())
31
+ #
32
+ if ( $proxy_server_address -eq $null )
33
+ {
34
+ $res = $(Start-Job $block_to_run | Wait-Job | Receive-Job)
35
+ } else
36
+ {
37
+ Add-To-Trusted $proxy_server_address
38
+ $so = New-PSSessionOption -IdleTimeout 240000
39
+ $res = invoke-command -ComputerName $proxy_server_address -Credential $proxy_credential -ScriptBlock $block_to_run -SessionOption $so
40
+ Remove-From-Trusted $proxy_server_address
41
+ }
42
+ return $res
43
+ }
@@ -0,0 +1,20 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the MIT License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ function Write-Error-Message($message) {
7
+ $error_message = @{
8
+ error = "$message"
9
+ }
10
+ Write-Host "===Begin-Error==="
11
+ $result = ConvertTo-json $error_message
12
+ Write-Host $result
13
+ Write-Host "===End-Error==="
14
+ }
15
+
16
+ function Write-Output-Message($message) {
17
+ Write-Host "===Begin-Output==="
18
+ Write-Host $message
19
+ Write-Host "===End-Output==="
20
+ }
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kitchen-vmm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Jaroslav Gorjatsev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-13 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: cane
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: finstyle
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: test-kitchen
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '1.4'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: '1.4'
125
+ description: Virtual Machine Manager Driver for Test-Kitchen
126
+ email:
127
+ - gjarik@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - .cane
133
+ - .gitignore
134
+ - .rubocop.yml
135
+ - .travis.yml
136
+ - CHANGELOG.md
137
+ - Gemfile
138
+ - LICENSE
139
+ - README.md
140
+ - Rakefile
141
+ - kitchen-vmm.gemspec
142
+ - lib/kitchen/driver/vmm.rb
143
+ - lib/kitchen/driver/vmm_utils.rb
144
+ - lib/kitchen/driver/vmm_version.rb
145
+ - support/delete_vm.ps1
146
+ - support/import_vm.ps1
147
+ - support/utils/manage_credentials.ps1
148
+ - support/utils/manage_trusted_hosts.ps1
149
+ - support/utils/vmm_executor.ps1
150
+ - support/utils/write_messages.ps1
151
+ homepage: https://github.com/jarig/kitchen-vmm
152
+ licenses:
153
+ - Apache 2
154
+ metadata: {}
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ! '>='
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ! '>='
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubyforge_project:
171
+ rubygems_version: 2.4.5
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: Virtual Machine Manager Driver for Test-Kitchen
175
+ test_files: []