kitchen-vmm 0.1.1

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