chef-metal-vsphere 0.2.0 → 0.3.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +27 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +3 -0
- data/{LICENSE → LICENSE.txt} +4 -2
- data/README.md +29 -42
- data/Rakefile +31 -22
- data/TODO.md +41 -0
- data/chef-metal-vpshere.gemspec +34 -0
- data/lib/chef_metal/driver_init/vsphere.rb +3 -0
- data/lib/chef_metal_vsphere.rb +1 -11
- data/lib/chef_metal_vsphere/version.rb +1 -1
- data/lib/chef_metal_vsphere/vsphere_driver.rb +325 -0
- data/spec/driver_spec.rb +21 -0
- data/spec/spec_helper.rb +2 -0
- data/test/.chef/knife.rb +4 -0
- data/test/cookbooks/test/libraries/vmonkey_helper.rb +34 -0
- data/test/cookbooks/test/recipes/destroy_all.rb +8 -0
- data/test/cookbooks/test/recipes/simple.rb +11 -0
- data/test/cookbooks/test/recipes/vagrant.rb +11 -0
- data/test/cookbooks/test/recipes/vsphere.rb +18 -0
- metadata +111 -34
- data/lib/chef_metal/provisioner_init/vsphere_init.rb +0 -3
- data/lib/chef_metal_vsphere/vsphere_helpers.rb +0 -168
- data/lib/chef_metal_vsphere/vsphere_provisioner.rb +0 -310
data/spec/driver_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe ChefMetalVsphere::VsphereDriver do
|
4
|
+
describe '::canonicalize_url' do
|
5
|
+
let(:vmonkey_config) do
|
6
|
+
{
|
7
|
+
host: 'spec_host',
|
8
|
+
datacenter: 'spec_datacenter',
|
9
|
+
cluster: 'spec_cluster'
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
allow(VMonkey).to receive(:default_opts) { vmonkey_config }
|
15
|
+
end
|
16
|
+
|
17
|
+
subject { described_class::canonicalize_url('vsphere', {}) }
|
18
|
+
|
19
|
+
it { should include('vsphere:spec_host:spec_datacenter:spec_cluster') }
|
20
|
+
end
|
21
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/test/.chef/knife.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module VmonkeyHelper
|
2
|
+
@instructions = "
|
3
|
+
For the test coobook to run with the vsphere driver, you need:
|
4
|
+
- On the machine running the specs:
|
5
|
+
+ #{ENV['VMONKEY_YML']} (see below)
|
6
|
+
|
7
|
+
- On your vSphere system
|
8
|
+
+ A VM or Template from which VMs will be cloned (:bootstrap_options => :template)
|
9
|
+
+ A working Folder into which VMs will be cloned (:bootstrap_options => :working_folder)
|
10
|
+
+ Clones of the Template must provide SSH port 22 with root password authentication (:ssh_options => :password)
|
11
|
+
|
12
|
+
Place the following in #{ENV['VMONKEY_YML']}
|
13
|
+
host: vcenter_host_name
|
14
|
+
user: vcenter_user_name
|
15
|
+
password: your_mothers_maiden_name
|
16
|
+
insecure: true
|
17
|
+
ssl: true
|
18
|
+
datacenter: datacenter_name
|
19
|
+
cluster: cluster_name
|
20
|
+
test:
|
21
|
+
:bootstrap_options:
|
22
|
+
template: /path/to/a/vm/template
|
23
|
+
folder: /path/to/a/folder/to/place/new/vms
|
24
|
+
:ssh_options:
|
25
|
+
password: your_first_pet
|
26
|
+
"
|
27
|
+
|
28
|
+
def self.config
|
29
|
+
yml_path = File.expand_path( ENV['VMONKEY_YML'] )
|
30
|
+
YAML::load_file(yml_path).inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
31
|
+
rescue
|
32
|
+
raise @instructions
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'chef_metal_vagrant'
|
2
|
+
test_dir = File.expand_path('../../../../..', File.dirname(__FILE__))
|
3
|
+
with_driver "vagrant:#{test_dir}/.vagrant"
|
4
|
+
|
5
|
+
vagrant_box 'precise64' do
|
6
|
+
url 'http://files.vagrantup.com/precise64.box'
|
7
|
+
end
|
8
|
+
|
9
|
+
with_machine_options :vagrant_options => {
|
10
|
+
'vm.box' => 'precise64'
|
11
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'chef_metal_vsphere'
|
2
|
+
config = VmonkeyHelper.config
|
3
|
+
|
4
|
+
with_driver 'vsphere'
|
5
|
+
|
6
|
+
with_machine_options({
|
7
|
+
bootstrap_options: {
|
8
|
+
template: config[:test][:bootstrap_options][:template],
|
9
|
+
folder: config[:test][:bootstrap_options][:folder]
|
10
|
+
},
|
11
|
+
ssh_options: {
|
12
|
+
user: 'root',
|
13
|
+
password: config[:test][:ssh_options][:password],
|
14
|
+
port: 22,
|
15
|
+
user_known_hosts_file: '/dev/null',
|
16
|
+
paranoid: false
|
17
|
+
}
|
18
|
+
})
|
metadata
CHANGED
@@ -1,88 +1,157 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-metal-vsphere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0.beta.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Brian Dupras
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05
|
11
|
+
date: 2014-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '11.12'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '11.12'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: chef-metal
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
33
|
+
version: '0.11'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '0.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: vmonkey
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: rspec
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
|
-
- -
|
73
|
+
- - ~>
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
75
|
+
version: '3.0'
|
48
76
|
type: :development
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
|
-
- -
|
80
|
+
- - ~>
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
82
|
+
version: '3.0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rake
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
|
-
- -
|
87
|
+
- - ~>
|
60
88
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
89
|
+
version: '10.3'
|
62
90
|
type: :development
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
|
-
- -
|
94
|
+
- - ~>
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
69
|
-
|
70
|
-
|
96
|
+
version: '10.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mixlib-shellout
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.4.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.4.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: chef-metal-vagrant
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.4'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.4'
|
125
|
+
description: chef-metal vSphere driver
|
126
|
+
email:
|
127
|
+
- brian@duprasville.com
|
71
128
|
executables: []
|
72
129
|
extensions: []
|
73
130
|
extra_rdoc_files:
|
74
131
|
- README.md
|
75
|
-
- LICENSE
|
132
|
+
- LICENSE.txt
|
76
133
|
files:
|
77
|
-
-
|
134
|
+
- .gitignore
|
135
|
+
- CHANGELOG.md
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE.txt
|
78
138
|
- README.md
|
79
139
|
- Rakefile
|
80
|
-
-
|
140
|
+
- TODO.md
|
141
|
+
- chef-metal-vpshere.gemspec
|
142
|
+
- lib/chef_metal/driver_init/vsphere.rb
|
81
143
|
- lib/chef_metal_vsphere.rb
|
82
144
|
- lib/chef_metal_vsphere/version.rb
|
83
|
-
- lib/chef_metal_vsphere/
|
84
|
-
-
|
85
|
-
|
145
|
+
- lib/chef_metal_vsphere/vsphere_driver.rb
|
146
|
+
- spec/driver_spec.rb
|
147
|
+
- spec/spec_helper.rb
|
148
|
+
- test/.chef/knife.rb
|
149
|
+
- test/cookbooks/test/libraries/vmonkey_helper.rb
|
150
|
+
- test/cookbooks/test/recipes/destroy_all.rb
|
151
|
+
- test/cookbooks/test/recipes/simple.rb
|
152
|
+
- test/cookbooks/test/recipes/vagrant.rb
|
153
|
+
- test/cookbooks/test/recipes/vsphere.rb
|
154
|
+
homepage: https://github.com/vmtricks/chef-metal-vsphere
|
86
155
|
licenses:
|
87
156
|
- MIT
|
88
157
|
metadata: {}
|
@@ -92,18 +161,26 @@ require_paths:
|
|
92
161
|
- lib
|
93
162
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
163
|
requirements:
|
95
|
-
- -
|
164
|
+
- - '>='
|
96
165
|
- !ruby/object:Gem::Version
|
97
166
|
version: '0'
|
98
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
168
|
requirements:
|
100
|
-
- -
|
169
|
+
- - '>'
|
101
170
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
171
|
+
version: 1.3.1
|
103
172
|
requirements: []
|
104
173
|
rubyforge_project:
|
105
|
-
rubygems_version: 2.
|
174
|
+
rubygems_version: 2.1.11
|
106
175
|
signing_key:
|
107
176
|
specification_version: 4
|
108
|
-
summary:
|
109
|
-
test_files:
|
177
|
+
summary: chef-metal vSphere driver
|
178
|
+
test_files:
|
179
|
+
- spec/driver_spec.rb
|
180
|
+
- spec/spec_helper.rb
|
181
|
+
- test/.chef/knife.rb
|
182
|
+
- test/cookbooks/test/libraries/vmonkey_helper.rb
|
183
|
+
- test/cookbooks/test/recipes/destroy_all.rb
|
184
|
+
- test/cookbooks/test/recipes/simple.rb
|
185
|
+
- test/cookbooks/test/recipes/vagrant.rb
|
186
|
+
- test/cookbooks/test/recipes/vsphere.rb
|
@@ -1,168 +0,0 @@
|
|
1
|
-
module ChefMetalVsphere
|
2
|
-
module Helpers
|
3
|
-
|
4
|
-
def vim
|
5
|
-
# reconnect on every call - connections may silently timeout during long operations (e.g. cloning)
|
6
|
-
conn_opts = {
|
7
|
-
:host => connect_options['vsphere_host'],
|
8
|
-
:port => connect_options['vsphere_port'],
|
9
|
-
:path => connect_options['vshere_path'],
|
10
|
-
:use_ssl => connect_options['vsphere_ssl'],
|
11
|
-
:insecure => connect_options['vsphere_insecure'],
|
12
|
-
:proxyHost => connect_options['proxy_host'],
|
13
|
-
:proxyPort => connect_options['proxy_port'],
|
14
|
-
:user => connect_options['vsphere_user'],
|
15
|
-
:password => connect_options['vsphere_password']
|
16
|
-
}
|
17
|
-
|
18
|
-
vim = RbVmomi::VIM.connect conn_opts
|
19
|
-
return vim
|
20
|
-
end
|
21
|
-
|
22
|
-
def find_vm(dc_name, vm_folder, vm_name)
|
23
|
-
folder = find_folder(dc_name, vm_folder) or raise("vSphere Folder not found [#{vm_folder}] for vm #{vm_name}")
|
24
|
-
vm = folder.find(vm_name, RbVmomi::VIM::VirtualMachine)
|
25
|
-
end
|
26
|
-
|
27
|
-
def vm_started?(vm, wait_on_port = 22)
|
28
|
-
return false if vm.nil?
|
29
|
-
state = vm.runtime.powerState
|
30
|
-
return false unless state == 'poweredOn'
|
31
|
-
return false unless port_ready?(vm, wait_on_port)
|
32
|
-
return true
|
33
|
-
end
|
34
|
-
|
35
|
-
def vm_stopped?(vm)
|
36
|
-
return true if vm.nil?
|
37
|
-
state = vm.runtime.powerState
|
38
|
-
return false unless state == 'poweredOff'
|
39
|
-
return false
|
40
|
-
end
|
41
|
-
|
42
|
-
def start_vm(vm, wait_on_port = 22)
|
43
|
-
state = vm.runtime.powerState
|
44
|
-
unless state == 'poweredOn'
|
45
|
-
vm.PowerOnVM_Task.wait_for_completion
|
46
|
-
end
|
47
|
-
|
48
|
-
sleep 1 until port_ready?(vm, wait_on_port)
|
49
|
-
end
|
50
|
-
|
51
|
-
def stop_vm(vm)
|
52
|
-
begin
|
53
|
-
vm.ShutdownGuest
|
54
|
-
sleep 2 until vm.runtime.powerState == 'poweredOff'
|
55
|
-
rescue
|
56
|
-
vm.PowerOffVM_Task.wait_for_completion
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def port_ready?(vm, port)
|
61
|
-
vm_ip = vm.guest.ipAddress
|
62
|
-
return false if vm_ip.nil?
|
63
|
-
|
64
|
-
begin
|
65
|
-
tcp_socket = TCPSocket.new(vm_ip, port)
|
66
|
-
readable = IO.select([tcp_socket], nil, nil, 5)
|
67
|
-
if readable
|
68
|
-
true
|
69
|
-
else
|
70
|
-
false
|
71
|
-
end
|
72
|
-
rescue Errno::ETIMEDOUT
|
73
|
-
false
|
74
|
-
rescue Errno::EPERM
|
75
|
-
false
|
76
|
-
rescue Errno::ECONNREFUSED
|
77
|
-
false
|
78
|
-
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
79
|
-
false
|
80
|
-
ensure
|
81
|
-
tcp_socket && tcp_socket.close
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
#folder could be like: /Level1/Level2/folder_name
|
86
|
-
def find_folder(dc_name, folder_name)
|
87
|
-
#dc(dc_name).vmFolder.childEntity.grep(RbVmomi::VIM::Folder).find { |x| x.name == folder_name }
|
88
|
-
baseEntity = dc(dc_name).vmFolder
|
89
|
-
entityArray = folder_name.split('/')
|
90
|
-
entityArray.each do |entityArrItem|
|
91
|
-
if entityArrItem != ''
|
92
|
-
baseEntity = baseEntity.childEntity.grep(RbVmomi::VIM::Folder).find { |f| f.name == entityArrItem }
|
93
|
-
end
|
94
|
-
end
|
95
|
-
baseEntity
|
96
|
-
end
|
97
|
-
|
98
|
-
def dc(dc_name)
|
99
|
-
vim.serviceInstance.find_datacenter(dc_name) or raise("vSphere Datacenter not found [#{datacenter}]")
|
100
|
-
end
|
101
|
-
|
102
|
-
def do_vm_clone(dc_name, vm_template, vm_name, options)
|
103
|
-
pool = options['resource_pool'] ? find_pool(dc(dc_name), options['resource_pool']) : vm_template.resourcePool
|
104
|
-
raise ':resource_pool must be specified when cloning from a VM Template' if pool.nil?
|
105
|
-
|
106
|
-
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
107
|
-
location: RbVmomi::VIM.VirtualMachineRelocateSpec(pool: pool),
|
108
|
-
powerOn: false,
|
109
|
-
template: false
|
110
|
-
)
|
111
|
-
|
112
|
-
clone_spec.config = RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange => Array.new)
|
113
|
-
|
114
|
-
unless options['customization_spec'].to_s.empty?
|
115
|
-
clone_spec.customization = find_customization_spec(options['customization_spec'])
|
116
|
-
end
|
117
|
-
|
118
|
-
unless options['annotation'].to_s.nil?
|
119
|
-
clone_spec.config.annotation = options['annotation']
|
120
|
-
end
|
121
|
-
|
122
|
-
unless options['num_cpus'].to_s.nil?
|
123
|
-
clone_spec.config.numCPUs = options['num_cpus']
|
124
|
-
end
|
125
|
-
|
126
|
-
unless options['memory_mb'].to_s.nil?
|
127
|
-
clone_spec.config.memoryMB = options['memory_mb']
|
128
|
-
end
|
129
|
-
|
130
|
-
vm_template.CloneVM_Task(
|
131
|
-
name: vm_name,
|
132
|
-
folder: find_folder(dc_name, options['vm_folder']),
|
133
|
-
spec: clone_spec
|
134
|
-
).wait_for_completion
|
135
|
-
end
|
136
|
-
|
137
|
-
def find_pool(dc, pool_name)
|
138
|
-
baseEntity = dc.hostFolder
|
139
|
-
entityArray = pool_name.split('/')
|
140
|
-
entityArray.each do |entityArrItem|
|
141
|
-
if entityArrItem != ''
|
142
|
-
if baseEntity.is_a? RbVmomi::VIM::Folder
|
143
|
-
baseEntity = baseEntity.childEntity.find { |f| f.name == entityArrItem } or nil
|
144
|
-
elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource or baseEntity.is_a? RbVmomi::VIM::ComputeResource
|
145
|
-
baseEntity = baseEntity.resourcePool.resourcePool.find { |f| f.name == entityArrItem } or nil
|
146
|
-
elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool
|
147
|
-
baseEntity = baseEntity.resourcePool.find { |f| f.name == entityArrItem } or nil
|
148
|
-
else
|
149
|
-
baseEntity = nil
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
raise "vSphere ResourcePool not found [#{pool_name}]" if baseEntity.nil?
|
155
|
-
|
156
|
-
baseEntity = baseEntity.resourcePool if not baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and baseEntity.respond_to?(:resourcePool)
|
157
|
-
baseEntity
|
158
|
-
end
|
159
|
-
|
160
|
-
def find_customization_spec(customization_spec)
|
161
|
-
csm = vim.serviceContent.customizationSpecManager
|
162
|
-
csi = csm.GetCustomizationSpec(:name => customization_spec)
|
163
|
-
spec = csi.spec
|
164
|
-
raise "Customization Spec not found [#{customization_spec}]" if spec.nil?
|
165
|
-
spec
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|