knife-esx 0.1.5 → 0.2
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.
- data/CHANGELOG.md +81 -2
- data/knife-esx.gemspec +2 -0
- data/lib/chef/knife/esx_base.rb +1 -1
- data/lib/chef/knife/esx_vm_create.rb +168 -2
- data/lib/knife-esx/version.rb +1 -1
- metadata +30 -8
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,63 @@
|
|
1
|
-
#
|
1
|
+
# 0.2 - 2012/02/28
|
2
|
+
|
3
|
+
* Added --batch and --async options
|
4
|
+
|
5
|
+
Inspired by spiceweasel from Matt Ray (https://github.com/mattray/spiceweasel), I've added a batch mode where a YAML file describes the VMs you want to bootstrap.
|
6
|
+
|
7
|
+
knife esx vm create --batch batch.yml
|
8
|
+
|
9
|
+
Sample batch.yml file:
|
10
|
+
|
11
|
+
---
|
12
|
+
:test1:
|
13
|
+
'extra-args': --no-host-key-verify
|
14
|
+
'vm-memory': 128
|
15
|
+
'esx-host': esx-server-1
|
16
|
+
'esx-password': secret
|
17
|
+
'ssh-user': ubuntu
|
18
|
+
'ssh-password': ubuntu
|
19
|
+
'vm-disk': /home/rubiojr/mnt/mirror/virtual_appliances/ubuntu1110-x64-vmware-tools.vmdk
|
20
|
+
'datastore': datastore2
|
21
|
+
:test2:
|
22
|
+
'extra-args': --no-host-key-verify
|
23
|
+
'vm-memory': 128
|
24
|
+
'esx-host': esx-server-1
|
25
|
+
'esx-password': secret
|
26
|
+
'ssh-user': ubuntu
|
27
|
+
'ssh-password': ubuntu
|
28
|
+
'vm-disk': /home/rubiojr/mnt/mirror/virtual_appliances/ubuntu1110-x64-vmware-tools.vmdk
|
29
|
+
'datastore': datastore2
|
30
|
+
:test3:
|
31
|
+
'extra-args': --no-host-key-verify
|
32
|
+
'vm-memory': 256
|
33
|
+
'esx-host': esx-server-1
|
34
|
+
'esx-password': secret
|
35
|
+
'ssh-user': ubuntu
|
36
|
+
'ssh-password': ubuntu
|
37
|
+
'vm-disk': /home/rubiojr/mnt/mirror/virtual_appliances/ubuntu1110-x64-vmware-tools.vmdk
|
38
|
+
'datastore': datastore2
|
39
|
+
|
40
|
+
This will try to create three VMs (testvm1, testvm2 and testvm3) sequentially. VM definitions inside the batch file accept all the parameters that can be used with knife-esx.
|
41
|
+
|
42
|
+
If you want to bootstrap the VMs asynchronously, use the --async flag.
|
43
|
+
|
44
|
+
knife esx vm create --batch batch.yml --async
|
45
|
+
|
46
|
+
Standard output and error log is redirected to /tmp/knife_esx_vm_create_VMNAME.log, so if we use the deploy script from above, three log files will be created:
|
47
|
+
|
48
|
+
/tmp/knife_esx_vm_create_test1.log
|
49
|
+
/tmp/knife_esx_vm_create_test2.log
|
50
|
+
/tmp/knife_esx_vm_create_test3.log
|
51
|
+
|
52
|
+
* Added --skip-bootstrap flag. If the flag is used the VM will be created but
|
53
|
+
the bootstrap template/script won't be executed (it also means that Chef won't be installed).
|
54
|
+
|
55
|
+
* Fixed bug preventing knife-esx to create a VM when the hypervisor has an empty root password.
|
56
|
+
|
57
|
+
KNOWN ISSUES
|
58
|
+
* To use --batch without --skip-bootstrap, the ssh user (--ssh-user) needs to be able to sudo without asking for a password (i.e. adding something like 'ubuntu ALL=(ALL) NOPASSWD: ALL' to /etc/sudoers in the appliance template) otherwise the bootstraping process won't work if more than one VM is being deployed.
|
59
|
+
|
60
|
+
# 0.1.5 - 2012/02/25
|
2
61
|
|
3
62
|
* Patch from @pperezrubio adding multiple networks support
|
4
63
|
|
@@ -8,7 +67,27 @@
|
|
8
67
|
--ssh-password ubuntu \
|
9
68
|
--vm-network "VLAN-Integration,VLAN-Test"
|
10
69
|
|
11
|
-
|
12
70
|
This will create a VM with two NICs, attaching them to the VLAN-Integration and VLAN-Test networks respectively.
|
13
71
|
|
72
|
+
Fixed MAC addresses can also be assigned to each NIC using the --mac-address parameter:
|
73
|
+
|
74
|
+
knife esx vm create --vm-disk ubuntu-oneiric.vmdk \
|
75
|
+
--vm-name testvm --datastore datastore1 \
|
76
|
+
--esx-host 192.168.88.1 --ssh-user ubuntu \
|
77
|
+
--ssh-password ubuntu \
|
78
|
+
--vm-network "VLAN-Integration,VLAN-Test" \
|
79
|
+
--mac-address "00:01:02:03:04:05,00:01:02:03:04:06"
|
80
|
+
|
81
|
+
MAC address 00:01:02:03:04:05 will be assigned to VLAN-Integration NIC and 00:01:02:03:04:06 to the VLAN-Test NIC.
|
82
|
+
|
83
|
+
If a MAC address is omitted it will be dynamically generated:
|
84
|
+
|
85
|
+
knife esx vm create --vm-disk ubuntu-oneiric.vmdk \
|
86
|
+
--vm-name testvm --datastore datastore1 \
|
87
|
+
--esx-host 192.168.88.1 --ssh-user ubuntu \
|
88
|
+
--ssh-password ubuntu \
|
89
|
+
--vm-network "VLAN-Integration,VLAN-Test" \
|
90
|
+
--mac-address ",00:01:02:03:04:06"
|
91
|
+
|
92
|
+
Note that I did not specify the first MAC address, so VLAN-Integration NIC will get a random MAC.
|
14
93
|
|
data/knife-esx.gemspec
CHANGED
data/lib/chef/knife/esx_base.rb
CHANGED
@@ -61,7 +61,7 @@ class Chef
|
|
61
61
|
ui.info "#{ui.color("Connecting to ESX host #{config[:esx_host]}... ", :magenta)}"
|
62
62
|
@connection = ESX::Host.connect(Chef::Config[:knife][:esx_host],
|
63
63
|
Chef::Config[:knife][:esx_username],
|
64
|
-
Chef::Config[:knife][:esx_password])
|
64
|
+
Chef::Config[:knife][:esx_password] || '')
|
65
65
|
else
|
66
66
|
@connection
|
67
67
|
end
|
@@ -17,9 +17,121 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife/esx_base'
|
20
|
+
require 'open4'
|
21
|
+
require 'celluloid'
|
22
|
+
require 'singleton'
|
23
|
+
|
24
|
+
module KnifeESX
|
25
|
+
class DeployScript
|
26
|
+
|
27
|
+
attr_reader :job_count
|
28
|
+
|
29
|
+
# Sample job
|
30
|
+
#---
|
31
|
+
#:test1:
|
32
|
+
# 'vm-memory':
|
33
|
+
# 'extra-args':
|
34
|
+
# 'esx-host':
|
35
|
+
# 'template-file':
|
36
|
+
# 'vm-disk':
|
37
|
+
# 'ssh-user':
|
38
|
+
# 'ssh-password':
|
39
|
+
# 'run-list':
|
40
|
+
# 'network-interface':
|
41
|
+
def initialize(batch_file)
|
42
|
+
@batch_file = batch_file
|
43
|
+
@jobs = []
|
44
|
+
@job_count = 0
|
45
|
+
(YAML.load_file batch_file).each do |i|
|
46
|
+
@jobs << DeployJob.new(i)
|
47
|
+
@job_count += 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def each_job(&block)
|
52
|
+
@jobs.each do |j|
|
53
|
+
yield j
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class CLogger
|
60
|
+
include Celluloid
|
61
|
+
include Singleton
|
62
|
+
|
63
|
+
def info(msg)
|
64
|
+
puts "INFO: #{msg}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def error(msg)
|
68
|
+
$stderr.puts "ERROR: #{msg}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class DeployJob
|
73
|
+
|
74
|
+
include Celluloid
|
75
|
+
|
76
|
+
attr_reader :name
|
77
|
+
|
78
|
+
def initialize(options)
|
79
|
+
@name, @options = options
|
80
|
+
validate
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate
|
84
|
+
if @name.nil? or @name.empty?
|
85
|
+
raise Exception.new("Invalid job name")
|
86
|
+
end
|
87
|
+
if not @options['vm-disk'] or !File.exist?(@options['vm-disk'])
|
88
|
+
raise Exception.new("Invalid VM disk for job #{@name}.")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# returns [status, stdout, stderr]
|
93
|
+
def run
|
94
|
+
args = ""
|
95
|
+
extra_args = ""
|
96
|
+
@options.each do |k, v|
|
97
|
+
if k == 'extra-args'
|
98
|
+
extra_args << v
|
99
|
+
else
|
100
|
+
args << "--#{k} #{v} " unless k == 'extra-args'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
@out = ""
|
105
|
+
@err = ""
|
106
|
+
optstring = []
|
107
|
+
@options.each do |k,v|
|
108
|
+
optstring << " - #{k}:".ljust(25) + "#{v}\n" unless k =~ /password/
|
109
|
+
end
|
110
|
+
log_file = "/tmp/knife_esx_vm_create_#{@name.to_s.strip.chomp.gsub(/\s/,'_')}.log"
|
111
|
+
CLogger.instance.info! "Bootstrapping VM #{@name} \n#{optstring.join}"
|
112
|
+
CLogger.instance.info! "VM #{@name} bootstrap log: #{log_file}"
|
113
|
+
@status = Open4.popen4("knife esx vm create --vm-name #{@name} #{args} #{extra_args} > #{log_file} 2>&1") do |pid, stdin, stdout, stderr|
|
114
|
+
@out << stdout.read.strip
|
115
|
+
@err << stderr.read.strip
|
116
|
+
end
|
117
|
+
if @status == 0
|
118
|
+
CLogger.instance.info! "[#{@name}] deployment finished OK"
|
119
|
+
else
|
120
|
+
CLogger.instance.error! "[#{@name}] deployment FAILED"
|
121
|
+
@err.each_line do |l|
|
122
|
+
CLogger.instance.error! "[#{@name}] #{l.chomp}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
return @status, @out, @err
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
20
131
|
|
21
132
|
class Chef
|
22
133
|
class Knife
|
134
|
+
|
23
135
|
class EsxVmCreate < Knife
|
24
136
|
|
25
137
|
include Knife::ESXBase
|
@@ -125,7 +237,26 @@ class Chef
|
|
125
237
|
:long => "--mac-address",
|
126
238
|
:description => "Mac address list",
|
127
239
|
:default => nil
|
128
|
-
|
240
|
+
|
241
|
+
option :skip_bootstrap,
|
242
|
+
:long => "--skip-bootstrap",
|
243
|
+
:description => "Skip bootstrap process (Deploy only mode)",
|
244
|
+
:boolean => true,
|
245
|
+
:default => false,
|
246
|
+
:proc => Proc.new { true }
|
247
|
+
|
248
|
+
option :async,
|
249
|
+
:long => "--async",
|
250
|
+
:description => "Deploy the VMs asynchronously (Ignored unless combined with --batch)",
|
251
|
+
:boolean => true,
|
252
|
+
:default => false,
|
253
|
+
:proc => Proc.new { true }
|
254
|
+
|
255
|
+
option :batch,
|
256
|
+
:long => "--batch script.yml",
|
257
|
+
:description => "Use a batch file to deploy multiple VMs",
|
258
|
+
:default => nil
|
259
|
+
|
129
260
|
def tcp_test_ssh(hostname)
|
130
261
|
tcp_socket = TCPSocket.new(hostname, 22)
|
131
262
|
readable = IO.select([tcp_socket], nil, nil, 5)
|
@@ -147,6 +278,38 @@ class Chef
|
|
147
278
|
|
148
279
|
def run
|
149
280
|
$stdout.sync = true
|
281
|
+
|
282
|
+
if config[:batch]
|
283
|
+
CLogger.instance.info "Running in batch mode. Extra arguments will be ignored."
|
284
|
+
if not config[:async]
|
285
|
+
counter = 0
|
286
|
+
script = KnifeESX::DeployScript.new(config[:batch])
|
287
|
+
script.each_job do |job|
|
288
|
+
counter += 1
|
289
|
+
status, stdout, stderr = job.run
|
290
|
+
if status == 0
|
291
|
+
CLogger.instance.info 'Ok'
|
292
|
+
else
|
293
|
+
CLogger.instance.error 'Failed'
|
294
|
+
stderr.each_line do |l|
|
295
|
+
ui.error l
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
else
|
300
|
+
CLogger.instance.info! "Asynchronous boostrapping selected"
|
301
|
+
CLogger.instance.info! "Now do something productive while I finish my job ;)"
|
302
|
+
script = KnifeESX::DeployScript.new(config[:batch])
|
303
|
+
futures = []
|
304
|
+
script.each_job do |job|
|
305
|
+
futures << job.future(:run)
|
306
|
+
end
|
307
|
+
futures.each do |f|
|
308
|
+
f.value
|
309
|
+
end
|
310
|
+
end
|
311
|
+
return
|
312
|
+
end
|
150
313
|
|
151
314
|
unless config[:vm_disk]
|
152
315
|
ui.error("You have not provided a valid VMDK file. (--vm-disk)")
|
@@ -172,7 +335,7 @@ class Chef
|
|
172
335
|
destination_path = "/vmfs/volumes/#{datastore}/#{vm_name}"
|
173
336
|
|
174
337
|
connection.remote_command "mkdir #{destination_path}"
|
175
|
-
puts "#{ui.color("Creating VM... ", :magenta)}"
|
338
|
+
puts "#{ui.color("Creating VM #{vm_name}... ", :magenta)}"
|
176
339
|
puts "#{ui.color("Importing VM disk... ", :magenta)}"
|
177
340
|
|
178
341
|
connection.import_disk vm_disk, destination_path + "/#{vm_name}.vmdk"
|
@@ -186,6 +349,8 @@ class Chef
|
|
186
349
|
|
187
350
|
puts "#{ui.color("VM Name", :cyan)}: #{vm.name}"
|
188
351
|
puts "#{ui.color("VM Memory", :cyan)}: #{(vm.memory_size.to_f/1024/1024).round} MB"
|
352
|
+
|
353
|
+
return if config[:skip_bootstrap]
|
189
354
|
|
190
355
|
# wait for it to be ready to do stuff
|
191
356
|
print "\n#{ui.color("Waiting server... ", :magenta)}"
|
@@ -220,6 +385,7 @@ class Chef
|
|
220
385
|
def bootstrap_for_node(vm)
|
221
386
|
bootstrap = Chef::Knife::Bootstrap.new
|
222
387
|
bootstrap.name_args = [vm.ip_address]
|
388
|
+
bootstrap.config[:async] = config[:async]
|
223
389
|
bootstrap.config[:run_list] = config[:run_list]
|
224
390
|
bootstrap.config[:ssh_user] = config[:ssh_user]
|
225
391
|
bootstrap.config[:identity_file] = config[:identity_file]
|
data/lib/knife-esx/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-esx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.2'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: esx
|
16
|
-
requirement: &
|
16
|
+
requirement: &12088940 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.3.2
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *12088940
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: terminal-table
|
27
|
-
requirement: &
|
27
|
+
requirement: &12088520 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *12088520
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: chef
|
38
|
-
requirement: &
|
38
|
+
requirement: &12087940 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,29 @@ dependencies:
|
|
43
43
|
version: '0.10'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *12087940
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: celluloid
|
49
|
+
requirement: &12087280 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.9'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *12087280
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: open4
|
60
|
+
requirement: &12086840 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *12086840
|
47
69
|
description: ESX Support for Chef's Knife Command
|
48
70
|
email:
|
49
71
|
- rubiojr@frameos.org
|