knife-xapi 0.3.6 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/chef/knife/xapi_base.rb +155 -67
- data/lib/chef/knife/xapi_guest_create.rb +80 -77
- data/lib/chef/knife/xapi_guest_delete.rb +57 -13
- data/lib/chef/knife/xapi_vdi_create.rb +90 -0
- data/lib/chef/knife/xapi_vdi_delete.rb +131 -0
- data/lib/chef/knife/xapi_vdi_list.rb +60 -0
- data/lib/knife-xapi/version.rb +1 -1
- metadata +6 -3
data/lib/chef/knife/xapi_base.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Xapi Base Module
|
2
2
|
#
|
3
|
-
# Description:: Setup the Session and auth for xapi
|
3
|
+
# Description:: Setup the Session and auth for xapi
|
4
4
|
# other common methods used for talking with the xapi
|
5
5
|
#
|
6
6
|
# Author:: Jesse Nelson <spheromak@gmail.com>
|
@@ -21,27 +21,6 @@
|
|
21
21
|
# See the License for the specific language governing permissions and
|
22
22
|
# limitations under the License.
|
23
23
|
|
24
|
-
# ruby 1.8.7 doesn't like ||= with Constants
|
25
|
-
unless defined?(XAPI_TEMP_REGEX)
|
26
|
-
XAPI_TEMP_REGEX = /^CentOS 5.*\(64-bit\)/
|
27
|
-
end
|
28
|
-
|
29
|
-
unless defined?(XAPI_DEFAULTS)
|
30
|
-
XAPI_DEFAULTS = {
|
31
|
-
:domain => "",
|
32
|
-
:ssh_user => "root",
|
33
|
-
:ssh_port => "22",
|
34
|
-
:install_repo => "http://isoredirect.centos.org/centos/6/os/x86_64/",
|
35
|
-
:xapi_disk_size => "graphical utf8",
|
36
|
-
:xapi_disk_size => "8g",
|
37
|
-
:xapi_cpus => "1g",
|
38
|
-
:xapi_mem => "1g",
|
39
|
-
:bootstrap_template => "ubuntu10.04-gems",
|
40
|
-
:template_file => false,
|
41
|
-
:run_list => [],
|
42
|
-
:json_attributes => {}
|
43
|
-
}
|
44
|
-
end
|
45
24
|
|
46
25
|
require 'chef/knife'
|
47
26
|
require 'units/standard'
|
@@ -50,15 +29,17 @@ require 'xenapi'
|
|
50
29
|
class Chef::Knife
|
51
30
|
module XapiBase
|
52
31
|
|
32
|
+
attr :defaults
|
53
33
|
|
54
34
|
def self.included(includer)
|
55
35
|
includer.class_eval do
|
36
|
+
|
56
37
|
deps do
|
57
38
|
require 'xenapi'
|
58
39
|
require 'highline'
|
59
40
|
require 'highline/import'
|
60
|
-
require 'readline'
|
61
|
-
end
|
41
|
+
require 'readline'
|
42
|
+
end
|
62
43
|
|
63
44
|
option :xapi_host,
|
64
45
|
:short => "-h SERVER_URL",
|
@@ -77,36 +58,51 @@ class Chef::Knife
|
|
77
58
|
:long => "--xapi-username USERNAME",
|
78
59
|
:proc => Proc.new { |key| Chef::Config[:knife][:xapi_username] = key },
|
79
60
|
:description => "Your xenserver username"
|
80
|
-
|
61
|
+
|
81
62
|
option :domain,
|
82
63
|
:short => "-f Name",
|
83
64
|
:long => "--domain Name",
|
84
65
|
:description => "the domain name for the guest",
|
85
66
|
:proc => Proc.new { |key| Chef::Config[:knife][:domain] = key }
|
86
|
-
|
87
67
|
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
def self.set_defaults(config)
|
73
|
+
@defaults ||= Hash.new
|
74
|
+
@defaults.merge!(config)
|
75
|
+
end
|
76
|
+
|
77
|
+
# set the default template
|
78
|
+
self.set_defaults( { :template_regex => /^CentOS 5.*\(64-bit\)/ } )
|
79
|
+
|
80
|
+
def self.defaults
|
81
|
+
@defaults ||= Hash.new
|
82
|
+
end
|
88
83
|
|
84
|
+
def self.get_default(key)
|
85
|
+
@defaults[key] || nil
|
89
86
|
end
|
90
87
|
|
91
|
-
# highline setup
|
92
88
|
def h
|
93
89
|
@highline ||= ui.highline
|
94
|
-
end
|
90
|
+
end
|
95
91
|
|
96
92
|
# setup and return an authed xen api instance
|
97
93
|
def xapi
|
98
|
-
@xapi ||= begin
|
94
|
+
@xapi ||= begin
|
99
95
|
|
100
96
|
ui.fatal "Must provide a xapi host with --host "unless locate_config_value(:xapi_host)
|
101
97
|
session = XenApi::Client.new( locate_config_value(:xapi_host) )
|
102
|
-
|
98
|
+
|
103
99
|
# get the password from the user
|
104
100
|
password = locate_config_value(:xapi_password) || nil
|
105
101
|
username = locate_config_value(:xapi_username) || "root"
|
106
102
|
if password.nil? or password.empty?
|
107
103
|
password = h.ask("Enter password for user #{username}: " ) { |input| input.echo = "*" }
|
108
104
|
end
|
109
|
-
session.login_with_password(username, password)
|
105
|
+
session.login_with_password(username, password)
|
110
106
|
|
111
107
|
session
|
112
108
|
end
|
@@ -114,7 +110,7 @@ class Chef::Knife
|
|
114
110
|
|
115
111
|
def locate_config_value(key)
|
116
112
|
key = key.to_sym
|
117
|
-
config[key] || Chef::Config[:knife][key] ||
|
113
|
+
config[key] || Chef::Config[:knife][key] || Chef::Knife::XapiBase.get_default(key)
|
118
114
|
end
|
119
115
|
|
120
116
|
# get template by name_label
|
@@ -123,12 +119,13 @@ class Chef::Knife
|
|
123
119
|
end
|
124
120
|
|
125
121
|
#
|
126
|
-
# find a template matching what the user provided
|
127
|
-
#
|
122
|
+
# find a template matching what the user provided
|
123
|
+
#
|
128
124
|
# returns a ref to the vm or nil if nothing found
|
129
|
-
#
|
130
|
-
def find_template(template
|
131
|
-
|
125
|
+
#
|
126
|
+
def find_template(template)
|
127
|
+
template = locate_config_value(:template_regex) if template.nil?
|
128
|
+
# if we got a string then try to find that template exact
|
132
129
|
# if no exact template matches, search
|
133
130
|
if template.is_a?(String)
|
134
131
|
found = get_template(template)
|
@@ -137,23 +134,23 @@ class Chef::Knife
|
|
137
134
|
|
138
135
|
# make sure our nil template gets set to default
|
139
136
|
if template.nil?
|
140
|
-
template =
|
141
|
-
end
|
137
|
+
template = locate_config_value(:template_regex)
|
138
|
+
end
|
142
139
|
|
143
140
|
Chef::Log.debug "Name: #{template.class}"
|
144
141
|
# quick and dirty string to regex
|
145
142
|
unless template.is_a?(Regexp)
|
146
|
-
template = /#{template}/
|
143
|
+
template = /#{template}/
|
147
144
|
end
|
148
145
|
|
149
|
-
# loop over all vm's and find the template
|
146
|
+
# loop over all vm's and find the template
|
150
147
|
# Wish there was a better API method for this, and there might be
|
151
148
|
# but i couldn't find it
|
152
149
|
Chef::Log.debug "Using regex: #{template}"
|
153
150
|
xapi.VM.get_all_records().each_value do |vm|
|
154
151
|
if vm["is_a_template"] and vm["name_label"] =~ template
|
155
152
|
Chef::Log.debug "Matched: #{h.color(vm["name_label"], :yellow )}"
|
156
|
-
found = vm # we're gonna go with the last found
|
153
|
+
found = vm # we're gonna go with the last found
|
157
154
|
end
|
158
155
|
end
|
159
156
|
|
@@ -164,26 +161,67 @@ class Chef::Knife
|
|
164
161
|
end
|
165
162
|
return nil
|
166
163
|
end
|
167
|
-
|
168
|
-
# present a list of options for a user to select
|
164
|
+
|
165
|
+
# present a list of options for a user to select
|
169
166
|
# return the selected item
|
170
167
|
def user_select(items)
|
171
|
-
choose do |menu|
|
168
|
+
h.choose do |menu|
|
172
169
|
menu.index = :number
|
173
170
|
menu.prompt = "Please Choose One:"
|
174
171
|
menu.select_by = :index_or_name
|
175
172
|
items.each do |item|
|
176
|
-
menu.choice item.to_sym do |command|
|
177
|
-
|
173
|
+
menu.choice item.to_sym do |command|
|
174
|
+
ui.msg "Using: #{command}"
|
178
175
|
selected = command.to_s
|
179
176
|
end
|
180
177
|
end
|
178
|
+
menu.choice :all do return :all end
|
181
179
|
menu.choice :exit do exit 1 end
|
182
180
|
end
|
183
181
|
end
|
184
182
|
|
183
|
+
# destroy/remove VM refs and exit
|
184
|
+
def cleanup(vm_ref)
|
185
|
+
# shutdown and dest
|
186
|
+
unless xapi.VM.get_power_state(vm_ref) == "Halted"
|
187
|
+
ui.msg "Shutting down Guest"
|
188
|
+
task = xapi.Async.VM.hard_shutdown(vm_ref)
|
189
|
+
get_task_ref(task) unless task == "Halted"
|
190
|
+
end
|
191
|
+
|
192
|
+
ui.msg "Removing disks attached to Guest"
|
193
|
+
Chef::Log.debug "getting vbds attached to #{vm_ref}"
|
194
|
+
wait_tasks = []
|
195
|
+
xapi.VM.get_VBDs(vm_ref).to_a.each do |vbd|
|
196
|
+
next unless vbd
|
197
|
+
|
198
|
+
Chef::Log.debug "removing vbd: #{vbd}"
|
199
|
+
wait_tasks << xapi.Async.VDI.destroy( xapi.VBD.get_record(vbd)["VDI"] )
|
200
|
+
wait_tasks << xapi.Async.VBD.destroy(vbd)
|
201
|
+
end
|
202
|
+
|
203
|
+
# wait for disk cleanup to finish up
|
204
|
+
unless wait_tasks.empty?
|
205
|
+
ui.msg "waiting for disks to cleanup"
|
206
|
+
wait_tasks.each do |task|
|
207
|
+
wait_on_task(task)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
ui.msg "Destroying Guest"
|
212
|
+
task = xapi.Async.VM.destroy(vm_ref)
|
213
|
+
wait_on_task(task)
|
214
|
+
end
|
215
|
+
|
216
|
+
# cleanup a vm and exit (fail)
|
217
|
+
def fail(ref=nil)
|
218
|
+
ui.warn "Error encountered clenaing up and exiting"
|
219
|
+
cleanup ref if ref
|
220
|
+
exit 1
|
221
|
+
end
|
222
|
+
|
185
223
|
# generate a random mac address
|
186
|
-
def generate_mac
|
224
|
+
def generate_mac
|
187
225
|
("%02x"%(rand(64)*4|2))+(0..4).inject(""){|s,x|s+":%02x"%rand(256)}
|
188
226
|
end
|
189
227
|
|
@@ -191,19 +229,19 @@ class Chef::Knife
|
|
191
229
|
def add_vif_by_name(vm_ref, dev_num, net_name)
|
192
230
|
Chef::Log.debug "Looking up vif for: #{h.color(net_name, :cyan)}"
|
193
231
|
network_ref = xapi.network.get_by_name_label(net_name).first
|
194
|
-
if network_ref.nil?
|
195
|
-
if net_name =~ /Network (\d)+$/ # special handing for 'Network X' As displayed by XenCenter
|
232
|
+
if network_ref.nil?
|
233
|
+
if net_name =~ /Network (\d)+$/ # special handing for 'Network X' As displayed by XenCenter
|
196
234
|
add_vif_by_name(vm_ref, dev_num, "Pool-wide network associated with eth#{$1}")
|
197
235
|
else
|
198
236
|
ui.warn "#{h.color(net_name,:red)} not found, moving on"
|
199
237
|
end
|
200
|
-
return
|
238
|
+
return
|
201
239
|
end
|
202
240
|
|
203
241
|
mac = generate_mac
|
204
242
|
Chef::Log.debug "Provisioning: #{h.color(net_name, :cyan)}, #{h.color(mac,:green)}, #{h.color(network_ref, :yellow)}"
|
205
243
|
|
206
|
-
vif = {
|
244
|
+
vif = {
|
207
245
|
'device' => dev_num.to_s,
|
208
246
|
'network' => network_ref,
|
209
247
|
'VM' => vm_ref,
|
@@ -227,7 +265,7 @@ class Chef::Knife
|
|
227
265
|
|
228
266
|
# returns sr_ref to the default sr on pool
|
229
267
|
def find_default_sr()
|
230
|
-
xapi.pool.get_default_SR( xapi.pool.get_all()[0] )
|
268
|
+
xapi.pool.get_default_SR( xapi.pool.get_all()[0] )
|
231
269
|
end
|
232
270
|
|
233
271
|
# return an SR record from the name_label
|
@@ -259,7 +297,7 @@ class Chef::Knife
|
|
259
297
|
def create_vdi(name, sr_ref, size)
|
260
298
|
vdi_record = {
|
261
299
|
"name_label" => "#{name}",
|
262
|
-
"name_description" => "Root disk for #{name} created by knfie xapi",
|
300
|
+
"name_description" => "Root disk for #{name} created by #{ENV['USER']} with knfie xapi",
|
263
301
|
"SR" => sr_ref,
|
264
302
|
"virtual_size" => input_to_bytes(size).to_s,
|
265
303
|
"type" => "system",
|
@@ -267,7 +305,7 @@ class Chef::Knife
|
|
267
305
|
"read_only" => false,
|
268
306
|
"other_config" => {},
|
269
307
|
}
|
270
|
-
|
308
|
+
|
271
309
|
# Async create the VDI
|
272
310
|
task = xapi.Async.VDI.create(vdi_record)
|
273
311
|
ui.msg "waiting for VDI Create"
|
@@ -282,35 +320,41 @@ class Chef::Knife
|
|
282
320
|
sleep 1
|
283
321
|
end
|
284
322
|
end
|
285
|
-
|
323
|
+
|
286
324
|
# return the opaque ref of the task that was run by a task record if it succeded.
|
287
|
-
# else it returns nil
|
325
|
+
# else it returns nil
|
288
326
|
def get_task_ref(task)
|
327
|
+
Chef::Log.debug "Waiting on task #{task}"
|
289
328
|
wait_on_task(task)
|
290
|
-
|
329
|
+
status_ = xapi.task.get_status(task)
|
330
|
+
|
331
|
+
case status_
|
291
332
|
when "success"
|
292
|
-
#
|
333
|
+
puts "#{h.color "#{status_}", :green }"
|
334
|
+
# xapi task record returns result as <value>OpaqueRef:....</value>
|
293
335
|
# we want the ref. this way it will work if they fix it to return jsut the ref
|
294
336
|
ref = xapi.task.get_result(task).match(/OpaqueRef:[^<]+/).to_s
|
337
|
+
|
295
338
|
#cleanup our task
|
296
339
|
xapi.task.destroy(task)
|
297
340
|
return ref
|
298
|
-
else
|
299
|
-
ui.msg( "#{h.color
|
300
|
-
|
341
|
+
else
|
342
|
+
ui.msg( "#{h.color "#{status_}", :red } ")
|
343
|
+
ui.msg( "#{h.color 'ERROR:', :red } #{xapi.task.get_error_info(task)}" )
|
301
344
|
end
|
302
345
|
end
|
303
346
|
|
304
347
|
|
305
|
-
# create vbd and return a ref
|
306
|
-
|
348
|
+
# create vbd and return a ref
|
349
|
+
# defaults to bootable
|
350
|
+
def create_vbd(vm_ref, vdi_ref, position, boot=true)
|
307
351
|
vbd_record = {
|
308
352
|
"VM" => vm_ref,
|
309
353
|
"VDI" => vdi_ref,
|
310
354
|
"empty" => false,
|
311
355
|
"other_config" => {"owner"=>""},
|
312
356
|
"userdevice" => position.to_s,
|
313
|
-
"bootable" =>
|
357
|
+
"bootable" => boot,
|
314
358
|
"mode" => "RW",
|
315
359
|
"qos_algorithm_type" => "",
|
316
360
|
"qos_algorithm_params" => {},
|
@@ -320,7 +364,7 @@ class Chef::Knife
|
|
320
364
|
|
321
365
|
task = xapi.Async.VBD.create(vbd_record)
|
322
366
|
ui.msg "Waiting for VBD create"
|
323
|
-
vbd_ref = get_task_ref(task)
|
367
|
+
vbd_ref = get_task_ref(task)
|
324
368
|
end
|
325
369
|
|
326
370
|
# try to get a guest ip and return it
|
@@ -334,7 +378,51 @@ class Chef::Knife
|
|
334
378
|
end
|
335
379
|
end
|
336
380
|
return guest_ip
|
337
|
-
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def get_vbds_from_vdi(vdi_ref)
|
384
|
+
return xapi.VDI.get_VBDs(vdi_ref)
|
385
|
+
end
|
386
|
+
|
387
|
+
def get_all_vdis()
|
388
|
+
return xapi.VDI.get_all()
|
389
|
+
end
|
338
390
|
|
391
|
+
def get_vdi_by_uuid(id)
|
392
|
+
return xapi.VDI.get_by_uuid(id)
|
393
|
+
end
|
394
|
+
|
395
|
+
def get_vdi_by_name_label(name)
|
396
|
+
return xapi.VDI.get_by_name_label(name)
|
397
|
+
end
|
398
|
+
|
399
|
+
def print_vdi_info(vdi_ref)
|
400
|
+
puts "#{h.color "VDI name: " + xapi.VDI.get_name_label(vdi_ref), :green}"
|
401
|
+
puts " -Description: " + xapi.VDI.get_name_description(vdi_ref)
|
402
|
+
puts " -Type: " + xapi.VDI.get_type(vdi_ref)
|
403
|
+
end
|
404
|
+
|
405
|
+
def yes_no_prompt(str)
|
406
|
+
print str
|
407
|
+
choice = STDIN.gets
|
408
|
+
|
409
|
+
while !(choice.match(/^yes$|^no$/))
|
410
|
+
puts "Invalid input! Type \'yes\' or \'no\':"
|
411
|
+
choice = STDIN.gets
|
412
|
+
end
|
413
|
+
|
414
|
+
if choice.match('yes')
|
415
|
+
return true
|
416
|
+
else
|
417
|
+
return false
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
def destroy_vdi(vdi_ref)
|
422
|
+
task = xapi.Async.VDI.destroy(vdi_ref)
|
423
|
+
print "Destroying volume "
|
424
|
+
puts "#{h.color xapi.VDI.get_name_label(vdi_ref), :cyan}"
|
425
|
+
task_ref = get_task_ref(task)
|
426
|
+
end
|
339
427
|
end
|
340
428
|
end
|
@@ -8,9 +8,9 @@
|
|
8
8
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
9
|
# you may not use this file except in compliance with the License.
|
10
10
|
# You may obtain a copy of the License at
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# Unless required by applicable law or agreed to in writing, software
|
15
15
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
16
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -24,17 +24,30 @@ require 'chef/knife/xapi_base'
|
|
24
24
|
class Chef
|
25
25
|
class Knife
|
26
26
|
class XapiGuestCreate < Knife
|
27
|
+
require 'timeout'
|
27
28
|
include Chef::Knife::XapiBase
|
28
29
|
|
29
|
-
|
30
|
+
Chef::Knife::XapiBase.set_defaults( {
|
31
|
+
:domain => "",
|
32
|
+
:ssh_user => "root",
|
33
|
+
:ssh_port => "22",
|
34
|
+
:ping_timeout => 600,
|
35
|
+
:install_repo => "http://isoredirect.centos.org/centos/6/os/x86_64/",
|
36
|
+
:kernel_params => "graphical utf8",
|
37
|
+
:xapi_disk_size => "8g",
|
38
|
+
:xapi_cpus => "1",
|
39
|
+
:xapi_mem => "1g",
|
40
|
+
:bootstrap_template => "ubuntu10.04-gems",
|
41
|
+
:template_file => false,
|
42
|
+
:run_list => [],
|
43
|
+
:json_attributes => {}
|
44
|
+
})
|
30
45
|
|
31
46
|
deps do
|
32
47
|
require 'chef/knife/bootstrap'
|
33
48
|
Chef::Knife::Bootstrap.load_deps
|
34
49
|
end
|
35
50
|
|
36
|
-
|
37
|
-
|
38
51
|
banner "knife xapi guest create NAME [NETWORKS] (options)"
|
39
52
|
|
40
53
|
option :xapi_vm_template,
|
@@ -107,6 +120,10 @@ class Chef
|
|
107
120
|
:long => "--ssh-port PORT",
|
108
121
|
:description => "The ssh port"
|
109
122
|
|
123
|
+
option :ping_timeout,
|
124
|
+
:long => "--ping-timeout",
|
125
|
+
:description => "Seconds to timeout waiting for ip from guest"
|
126
|
+
|
110
127
|
option :bootstrap_version,
|
111
128
|
:long => "--bootstrap-version VERSION",
|
112
129
|
:description => "The version of Chef to install"
|
@@ -120,7 +137,7 @@ class Chef
|
|
120
137
|
:short => "-F FILEPATH",
|
121
138
|
:long => "--template-file TEMPLATE",
|
122
139
|
:description => "Full path to location of template to use"
|
123
|
-
|
140
|
+
|
124
141
|
option :json_attributes,
|
125
142
|
:short => "-j JSON_ATTRIBS",
|
126
143
|
:long => "--json-attributes",
|
@@ -153,7 +170,6 @@ class Chef
|
|
153
170
|
rescue Errno::ECONNREFUSED
|
154
171
|
sleep 2
|
155
172
|
false
|
156
|
-
# This happens on EC2 quite often
|
157
173
|
rescue Errno::EHOSTUNREACH
|
158
174
|
sleep 2
|
159
175
|
false
|
@@ -163,11 +179,11 @@ class Chef
|
|
163
179
|
|
164
180
|
def wait_for_guest_ip(vm_ref)
|
165
181
|
begin
|
166
|
-
timeout(
|
167
|
-
ui.msg "Waiting for guest ip address"
|
182
|
+
timeout( locate_config_value(:ping_timeout).to_i ) do
|
183
|
+
ui.msg "Waiting for guest ip address"
|
168
184
|
guest_ip = ""
|
169
185
|
while guest_ip.empty?
|
170
|
-
print(".")
|
186
|
+
print(".")
|
171
187
|
sleep @initial_sleep_delay ||= 10
|
172
188
|
vgm = xapi.VM.get_guest_metrics(vm_ref)
|
173
189
|
next if "OpaqueRef:NULL" == vgm
|
@@ -176,56 +192,41 @@ class Chef
|
|
176
192
|
guest_ip = networks["0/ip"]
|
177
193
|
end
|
178
194
|
end
|
179
|
-
puts "\n"
|
195
|
+
puts "\n"
|
180
196
|
return guest_ip
|
181
|
-
end
|
197
|
+
end
|
182
198
|
rescue Timeout::Error
|
183
199
|
ui.msg "Timeout waiting for XAPI to report IP address "
|
184
200
|
end
|
185
201
|
end
|
186
202
|
|
187
|
-
# destroy/remove VM refs and exit
|
188
|
-
def cleanup(vm_ref)
|
189
|
-
ui.warn "Cleaning up work and exiting"
|
190
|
-
# shutdown and dest
|
191
|
-
unless xapi.VM.get_power_state(vm_ref) == "Halted"
|
192
|
-
print "Shutting down Guest"
|
193
|
-
task = xapi.Async.VM.hard_shutdown(vm_ref)
|
194
|
-
wait_on_task(task)
|
195
|
-
print " #{h.color "Done", :green} \n"
|
196
|
-
end
|
197
|
-
|
198
|
-
print "Destroying Guest"
|
199
|
-
task = xapi.Async.VM.destroy(vm_ref)
|
200
|
-
wait_on_task(task)
|
201
|
-
print " #{h.color "Done", :green} \n"
|
202
|
-
exit 1
|
203
|
-
end
|
204
|
-
|
205
203
|
|
206
|
-
def run
|
204
|
+
def run
|
207
205
|
server_name = @name_args[0]
|
208
206
|
domainname = locate_config_value(:domain)
|
209
207
|
if domainname.empty?
|
210
208
|
fqdn = server_name
|
211
|
-
else
|
209
|
+
else
|
212
210
|
fqdn = "#{server_name}.#{domainname}"
|
213
211
|
end
|
214
|
-
|
212
|
+
|
215
213
|
# get the template vm we are going to build from
|
216
214
|
template_ref = find_template( locate_config_value(:xapi_vm_template) )
|
217
215
|
|
218
|
-
Chef::Log.debug "Cloning Guest from Template: #{h.color(template_ref, :bold, :cyan )}"
|
219
|
-
|
216
|
+
Chef::Log.debug "Cloning Guest from Template: #{h.color(template_ref, :bold, :cyan )}"
|
217
|
+
task = xapi.Async.VM.clone(template_ref, fqdn)
|
218
|
+
ui.msg "Waiting on Template Clone"
|
219
|
+
vm_ref = get_task_ref(task)
|
220
|
+
|
221
|
+
Chef::Log.debug "New VM ref: #{vm_ref}"
|
220
222
|
|
221
223
|
# TODO: lift alot of this
|
222
224
|
begin
|
223
|
-
xapi.VM.set_name_description(vm_ref, "VM from knife-xapi as #{server_name}")
|
225
|
+
xapi.VM.set_name_description(vm_ref, "VM from knife-xapi as #{server_name} by #{ENV['USER']}")
|
224
226
|
|
225
227
|
# configure the install repo
|
226
228
|
repo = locate_config_value(:install_repo)
|
227
229
|
xapi.VM.set_other_config(vm_ref, { "install-repository" => repo } )
|
228
|
-
|
229
230
|
|
230
231
|
cpus = locate_config_value( :xapi_cpus ).to_s
|
231
232
|
|
@@ -234,84 +235,88 @@ class Chef
|
|
234
235
|
|
235
236
|
memory_size = input_to_bytes( locate_config_value(:xapi_mem) ).to_s
|
236
237
|
# static-min <= dynamic-min = dynamic-max = static-max
|
237
|
-
xapi.VM.set_memory_limits(vm_ref, memory_size, memory_size, memory_size, memory_size)
|
238
|
+
xapi.VM.set_memory_limits(vm_ref, memory_size, memory_size, memory_size, memory_size)
|
238
239
|
|
239
|
-
#
|
240
|
+
#
|
240
241
|
# setup the Boot args
|
241
242
|
#
|
242
|
-
boot_args = locate_config_value(:kernel_params)
|
243
|
+
boot_args = locate_config_value(:kernel_params)
|
243
244
|
|
244
245
|
# if no hostname param set hostname to given vm name
|
245
|
-
boot_args << " hostname=#{server_name}" unless boot_args.match(/hostname=.+\s?/)
|
246
|
+
boot_args << " hostname=#{server_name}" unless boot_args.match(/hostname=.+\s?/)
|
246
247
|
# if domainname is supplied we put that in there as well
|
247
|
-
boot_args << "
|
248
|
+
boot_args << " dnsdomain=#{domainname}" unless boot_args.match(/dnsdomain=.+\s?/)
|
248
249
|
|
249
|
-
xapi.VM.set_PV_args( vm_ref, boot_args )
|
250
|
+
xapi.VM.set_PV_args( vm_ref, boot_args )
|
250
251
|
|
251
252
|
# TODO: validate that the vm gets a network here
|
252
253
|
networks = @name_args[1..-1]
|
253
254
|
# if the user has provided networks
|
254
|
-
if networks.length >= 1
|
255
|
+
if networks.length >= 1
|
255
256
|
clear_vm_vifs( xapi.VM.get_record( vm_ref ) )
|
256
|
-
networks.each_with_index do |net, index|
|
257
|
+
networks.each_with_index do |net, index|
|
257
258
|
add_vif_by_name(vm_ref, index, net)
|
258
259
|
end
|
259
260
|
end
|
260
261
|
|
261
262
|
if locate_config_value(:xapi_sr)
|
262
|
-
sr_ref = get_sr_by_name( locate_config_value(:xapi_sr) )
|
263
|
+
sr_ref = get_sr_by_name( locate_config_value(:xapi_sr) )
|
263
264
|
else
|
264
265
|
sr_ref = find_default_sr
|
265
266
|
end
|
266
267
|
|
267
268
|
if sr_ref.nil?
|
268
269
|
ui.error "SR specified not found or can't be used Aborting"
|
269
|
-
|
270
|
-
end
|
271
|
-
Chef::Log.debug "SR: #{h.color sr_ref, :cyan}"
|
272
|
-
|
273
|
-
#
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
270
|
+
fail(vm_ref) if sr_ref.nil?
|
271
|
+
end
|
272
|
+
Chef::Log.debug "SR: #{h.color sr_ref, :cyan}"
|
273
|
+
|
274
|
+
# setup disks
|
275
|
+
if locate_config_value(:xapi_disk_size)
|
276
|
+
# when a template already has disks, we decide the position number based on it.
|
277
|
+
position = xapi.VM.get_VBDs(vm_ref).length
|
278
|
+
|
279
|
+
# Create the VDI
|
280
|
+
vdi_ref = create_vdi("#{server_name}-root", sr_ref, locate_config_value(:xapi_disk_size) )
|
281
|
+
fail(vm_ref) unless vdi_ref
|
282
|
+
|
283
|
+
# Attach the VDI to the VM
|
284
|
+
# if its position is 0 set it bootable
|
285
|
+
vbd_ref = create_vbd(vm_ref, vdi_ref, position, position == 0)
|
286
|
+
fail(vm_ref) unless vbd_ref
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
ui.msg "Provisioning new Guest: #{h.color(fqdn, :bold, :cyan )}"
|
285
291
|
ui.msg "Boot Args: #{h.color boot_args,:bold, :cyan}"
|
286
292
|
ui.msg "Install Repo: #{ h.color(repo,:bold, :cyan)}"
|
287
|
-
ui.msg "Memory: #{ h.color( locate_config_value(:xapi_mem).to_s, :bold, :cyan)}"
|
293
|
+
ui.msg "Memory: #{ h.color( locate_config_value(:xapi_mem).to_s, :bold, :cyan)}"
|
288
294
|
ui.msg "CPUs: #{ h.color( locate_config_value(:xapi_cpus).to_s, :bold, :cyan)}"
|
289
295
|
ui.msg "Disk: #{ h.color( locate_config_value(:xapi_disk_size).to_s, :bold, :cyan)}"
|
290
296
|
provisioned = xapi.VM.provision(vm_ref)
|
291
297
|
|
292
298
|
ui.msg "Starting new Guest #{h.color( provisioned, :cyan)} "
|
293
299
|
task = xapi.Async.VM.start(vm_ref, false, true)
|
294
|
-
wait_on_task(task)
|
300
|
+
wait_on_task(task)
|
295
301
|
ui.msg( "#{ h.color "OK!", :green}" )
|
296
302
|
|
297
|
-
exit 0 unless locate_config_value(:run_list)
|
303
|
+
exit 0 unless locate_config_value(:run_list)
|
298
304
|
rescue Exception => e
|
299
305
|
ui.msg "#{h.color 'ERROR:'} #{h.color( e.message, :red )}"
|
300
306
|
# have to use join here to pass a string to highline
|
301
307
|
puts "Nested backtrace:"
|
302
308
|
ui.msg "#{h.color( e.backtrace.join("\n"), :yellow)}"
|
303
|
-
|
304
|
-
cleanup(vm_ref)
|
309
|
+
fail(vm_ref)
|
305
310
|
end
|
306
311
|
|
307
312
|
if locate_config_value(:run_list).empty? or ! locate_config_value(:template_file)
|
308
|
-
exit 0
|
313
|
+
exit 0
|
309
314
|
end
|
310
315
|
|
311
316
|
guest_addr = wait_for_guest_ip(vm_ref)
|
312
317
|
if guest_addr.nil? or guest_addr.empty?
|
313
318
|
ui.msg("ip seems wrong using host+domain name instead")
|
314
|
-
guest_addr = "#{
|
319
|
+
guest_addr = "#{server_name}.#{domainname}"
|
315
320
|
end
|
316
321
|
ui.msg "Trying to connect to guest @ #{guest_addr} "
|
317
322
|
|
@@ -323,12 +328,11 @@ class Chef
|
|
323
328
|
}
|
324
329
|
end
|
325
330
|
rescue Timeout::Error
|
326
|
-
ui.msg "Timeout trying to login
|
327
|
-
|
331
|
+
ui.msg "Timeout trying to login Wont bootstrap"
|
332
|
+
fail
|
328
333
|
end
|
329
334
|
|
330
|
-
|
331
|
-
begin
|
335
|
+
begin
|
332
336
|
bootstrap = Chef::Knife::Bootstrap.new
|
333
337
|
bootstrap.name_args = [ guest_addr ]
|
334
338
|
bootstrap.config[:run_list] = locate_config_value(:run_list)
|
@@ -345,15 +349,14 @@ class Chef
|
|
345
349
|
bootstrap.config[:environment] = config[:environment]
|
346
350
|
bootstrap.config[:host_key_verify] = false
|
347
351
|
bootstrap.config[:run_list] = locate_config_value(:run_list)
|
348
|
-
|
352
|
+
|
349
353
|
bootstrap.run
|
350
|
-
rescue Exception => e
|
354
|
+
rescue Exception => e
|
351
355
|
ui.msg "#{h.color 'ERROR:'} #{h.color( e.message, :red )}"
|
352
356
|
puts "Nested backtrace:"
|
353
357
|
ui.msg "#{h.color( e.backtrace.join("\n"), :yellow)}"
|
354
|
-
|
358
|
+
fail
|
355
359
|
end
|
356
|
-
|
357
360
|
end
|
358
361
|
|
359
362
|
end
|
@@ -26,6 +26,11 @@ class Chef
|
|
26
26
|
class XapiGuestDelete < Knife
|
27
27
|
include Chef::Knife::XapiBase
|
28
28
|
|
29
|
+
deps do
|
30
|
+
require 'chef/api_client'
|
31
|
+
require 'chef/json_compat'
|
32
|
+
end
|
33
|
+
|
29
34
|
banner "knife xapi guest delete NAME_LABEL (options)"
|
30
35
|
|
31
36
|
option :uuid,
|
@@ -33,9 +38,30 @@ class Chef
|
|
33
38
|
:long => "--uuid",
|
34
39
|
:description => "Treat the label as a UUID not a name label"
|
35
40
|
|
41
|
+
option :keep_client,
|
42
|
+
:short => "-C",
|
43
|
+
:long => "--keep-client",
|
44
|
+
:description => "Keep client info on the chef-server"
|
45
|
+
|
46
|
+
option :keep_node,
|
47
|
+
:short => "-N",
|
48
|
+
:long => "--keep-node",
|
49
|
+
:description => "Keep node info on the chef-server"
|
50
|
+
|
36
51
|
def run
|
37
52
|
server_name = @name_args[0]
|
38
53
|
|
54
|
+
if server_name.nil?
|
55
|
+
puts "Error: No VM Name specified..."
|
56
|
+
puts "Usage: " + banner
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
|
60
|
+
name = server_name
|
61
|
+
if config[:uuid]
|
62
|
+
name = get_name_label(vm)
|
63
|
+
end
|
64
|
+
|
39
65
|
vms = []
|
40
66
|
if config[:uuid]
|
41
67
|
vms << xapi.VM.get_by_uuid(server_name)
|
@@ -45,30 +71,48 @@ class Chef
|
|
45
71
|
vms.flatten!
|
46
72
|
|
47
73
|
if vms.empty?
|
48
|
-
|
74
|
+
puts "VM not found: #{h.color server_name, :red}"
|
49
75
|
exit 1
|
50
76
|
elsif vms.length > 1
|
51
|
-
|
77
|
+
puts "Multiple VM matches found use guest list if you are unsure"
|
52
78
|
vm = user_select(vms)
|
53
79
|
else
|
54
80
|
vm = vms.first
|
55
81
|
end
|
82
|
+
|
83
|
+
# Cleanup the VM
|
84
|
+
if vm == :all
|
85
|
+
vms.each {|vm| cleanup(vm) }
|
86
|
+
else
|
87
|
+
cleanup(vm)
|
88
|
+
end
|
56
89
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
90
|
+
#############################################
|
91
|
+
# Delete client and node on the chef server #
|
92
|
+
#############################################
|
93
|
+
unless config[:keep_client]
|
94
|
+
client_list = Chef::ApiClient.list
|
95
|
+
|
96
|
+
if client_list.has_key?(name)
|
97
|
+
ui.msg "Removing client #{h.color name, :cyan} from chef"
|
98
|
+
delete_object(Chef::ApiClient, name)
|
99
|
+
else
|
100
|
+
puts "Client not found on the chef server.. Nothing to delete.."
|
101
|
+
end
|
63
102
|
end
|
64
103
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
104
|
+
unless config[:keep_node]
|
105
|
+
env = Chef::Config[:environment]
|
106
|
+
node_list = env ? Chef::Node.list_by_environment(env) : Chef::Node.list
|
107
|
+
if node_list.has_key?(name)
|
108
|
+
ui.msg "Removing node #{h.color name, :cyan} from chef "
|
109
|
+
delete_object(Chef::Node, name)
|
110
|
+
else
|
111
|
+
puts "Node not found on the chef server.. Nothing to delete.."
|
112
|
+
end
|
113
|
+
end
|
69
114
|
end
|
70
115
|
|
71
116
|
end
|
72
117
|
end
|
73
118
|
end
|
74
|
-
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Jesse Nelson (<spheromak@gmail.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright (c) 2012 Jesse Nelson
|
5
|
+
#
|
6
|
+
# License:: Apache License, Version 2.0
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
#
|
20
|
+
|
21
|
+
|
22
|
+
require 'chef/knife/xapi_base'
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class Knife
|
26
|
+
class XapiVdiCreate < Knife
|
27
|
+
require 'timeout'
|
28
|
+
include Chef::Knife::XapiBase
|
29
|
+
|
30
|
+
banner "knife xapi vdi create NAME (options)"
|
31
|
+
|
32
|
+
option :xapi_sr,
|
33
|
+
:short => "-S Storage repo to provision VM from",
|
34
|
+
:long => "--xapi-sr",
|
35
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:xapi_sr] = key },
|
36
|
+
:description => "The Xen SR to use, If blank will use pool/hypervisor default"
|
37
|
+
|
38
|
+
option :xapi_disk_size,
|
39
|
+
:short => "-D Size of disk. 1g 512m etc",
|
40
|
+
:long => "--xapi-disk-size",
|
41
|
+
:description => "The size of the root disk, use 'm' 'g' 't' if no unit specified assumes g",
|
42
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:xapi_disk_size] = key.to_s }
|
43
|
+
|
44
|
+
def run
|
45
|
+
disk_name = @name_args[0]
|
46
|
+
if disk_name.nil?
|
47
|
+
puts "Error: No Disk Name specified..."
|
48
|
+
puts "Usage: " + banner
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
|
52
|
+
begin
|
53
|
+
if locate_config_value(:xapi_sr)
|
54
|
+
sr_ref = get_sr_by_name( locate_config_value(:xapi_sr) )
|
55
|
+
else
|
56
|
+
sr_ref = find_default_sr
|
57
|
+
end
|
58
|
+
|
59
|
+
if sr_ref.nil?
|
60
|
+
ui.error "SR specified not found or can't be used Aborting"
|
61
|
+
end
|
62
|
+
Chef::Log.debug "SR: #{h.color sr_ref, :cyan}"
|
63
|
+
|
64
|
+
size = locate_config_value(:xapi_disk_size)
|
65
|
+
|
66
|
+
vdi_record = {
|
67
|
+
"name_label" => disk_name,
|
68
|
+
"name_description" => "#{disk_name} created by #{ENV['USER']}",
|
69
|
+
"SR" => sr_ref,
|
70
|
+
"virtual_size" => input_to_bytes(size).to_s,
|
71
|
+
"type" => "system",
|
72
|
+
"sharable" => false,
|
73
|
+
"read_only" => false,
|
74
|
+
"other_config" => {},
|
75
|
+
}
|
76
|
+
|
77
|
+
# Async create the VDI
|
78
|
+
task = xapi.Async.VDI.create(vdi_record)
|
79
|
+
ui.msg "waiting for VDI Create.."
|
80
|
+
vdi_ref = get_task_ref(task)
|
81
|
+
|
82
|
+
ui.msg "Disk Name: #{ h.color( disk_name, :bold, :cyan)}"
|
83
|
+
ui.msg "Disk Size: #{ h.color( size.to_s, :bold, :cyan)}"
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Jesse Nelson (<spheromak@gmail.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright (c) 2012 Jesse Nelson
|
5
|
+
#
|
6
|
+
# License:: Apache License, Version 2.0
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
#
|
20
|
+
|
21
|
+
|
22
|
+
require 'chef/knife/xapi_base'
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class Knife
|
26
|
+
class XapiVdiDelete < Knife
|
27
|
+
include Chef::Knife::XapiBase
|
28
|
+
|
29
|
+
banner "knife xapi vdi delete NAME_LABEL (options)"
|
30
|
+
|
31
|
+
option :uuid,
|
32
|
+
:short => "-U",
|
33
|
+
:long => "--uuid",
|
34
|
+
:description => "Treat the label as a UUID not a name label"
|
35
|
+
|
36
|
+
option :cleanup,
|
37
|
+
:short => "-C",
|
38
|
+
:long => "--cleanup",
|
39
|
+
:description => "Clean up all orphaned volumes."
|
40
|
+
|
41
|
+
option :interactive,
|
42
|
+
:short => "-I",
|
43
|
+
:long => "--interactive",
|
44
|
+
:description => "Interactive clean-up of orphaned volumes"
|
45
|
+
|
46
|
+
def run
|
47
|
+
if config[:interactive]
|
48
|
+
# Get all VDIs known to the system
|
49
|
+
vdis = get_all_vdis()
|
50
|
+
first = true
|
51
|
+
|
52
|
+
for vdi_ in vdis do
|
53
|
+
vbds = get_vbds_from_vdi(vdi_)
|
54
|
+
if vbds.empty? and xapi.VDI.get_type(vdi_).match('system')
|
55
|
+
if first
|
56
|
+
puts "================================================"
|
57
|
+
first = false
|
58
|
+
end
|
59
|
+
|
60
|
+
print_vdi_info(vdi_)
|
61
|
+
ret = yes_no_prompt(" No VM attached! Do you want to destroy this volume? (Type \'yes\' or \'no\'): ")
|
62
|
+
|
63
|
+
if ret
|
64
|
+
destroy_vdi(vdi_)
|
65
|
+
end
|
66
|
+
puts "================================================"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
elsif config[:cleanup]
|
71
|
+
orphaned_vdis = []
|
72
|
+
vdis = get_all_vdis()
|
73
|
+
|
74
|
+
for vdi_ in vdis do
|
75
|
+
vbds = get_vbds_from_vdi(vdi_)
|
76
|
+
if vbds.empty? and xapi.VDI.get_type(vdi_).match('system')
|
77
|
+
orphaned_vdis << vdi_
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
for item in orphaned_vdis do
|
82
|
+
print_vdi_info(item)
|
83
|
+
end
|
84
|
+
|
85
|
+
unless orphaned_vdis.empty?
|
86
|
+
ret = yes_no_prompt("Do you want to destroy all these volumes? (Type \'yes\' or \'no\'): ")
|
87
|
+
if ret
|
88
|
+
for item in orphaned_vdis do
|
89
|
+
destroy_vdi(item)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
else
|
95
|
+
vdi_name = @name_args[0]
|
96
|
+
if vdi_name.nil?
|
97
|
+
puts "Error: No VDI Name specified..."
|
98
|
+
puts "Usage: " + banner
|
99
|
+
exit 1
|
100
|
+
end
|
101
|
+
|
102
|
+
vdis = []
|
103
|
+
if config[:uuid]
|
104
|
+
vdis << get_vdi_by_uuid(vdi_name)
|
105
|
+
else
|
106
|
+
vdis << get_vdi_by_name_label(vdi_name)
|
107
|
+
end
|
108
|
+
vdis.flatten!
|
109
|
+
|
110
|
+
if vdis.empty?
|
111
|
+
puts "VDI not found: #{h.color vdi_name, :red}"
|
112
|
+
exit 1
|
113
|
+
elsif vdis.length > 1
|
114
|
+
puts "Multiple VDI matches found. Use vdi list if you are unsure"
|
115
|
+
vdi = user_select(vdis)
|
116
|
+
else
|
117
|
+
vdi = vdis.first
|
118
|
+
end
|
119
|
+
|
120
|
+
vbds = get_vbds_from_vdi(vdi)
|
121
|
+
|
122
|
+
if vbds.empty?
|
123
|
+
destroy_vdi(vdi)
|
124
|
+
else
|
125
|
+
puts "ERROR! The VDI is still in use."
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Jesse Nelson (<spheromak@gmail.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright (c) 2012 Jesse Nelson
|
5
|
+
#
|
6
|
+
# License:: Apache License, Version 2.0
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
#
|
20
|
+
|
21
|
+
|
22
|
+
require 'chef/knife/xapi_base'
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class Knife
|
26
|
+
class XapiVdiList < Knife
|
27
|
+
include Chef::Knife::XapiBase
|
28
|
+
|
29
|
+
banner "knife xapi vdi list"
|
30
|
+
|
31
|
+
def run
|
32
|
+
# Get all VDIs known to the system
|
33
|
+
vdis = xapi.VDI.get_all()
|
34
|
+
|
35
|
+
puts "================================================"
|
36
|
+
for vdi_ in vdis do
|
37
|
+
puts "#{h.color "VDI name: " + xapi.VDI.get_name_label(vdi_), :green}"
|
38
|
+
puts " -UUID: " + xapi.VDI.get_uuid(vdi_)
|
39
|
+
puts " -Description: " + xapi.VDI.get_name_description(vdi_)
|
40
|
+
puts " -Type: " + xapi.VDI.get_type(vdi_)
|
41
|
+
|
42
|
+
vbds = xapi.VDI.get_VBDs(vdi_)
|
43
|
+
for vbd in vbds do
|
44
|
+
vm = xapi.VBD.get_VM(vbd)
|
45
|
+
state = xapi.VM.get_power_state(vm)
|
46
|
+
puts " -VM name: " + xapi.VM.get_name_label(vm)
|
47
|
+
puts " -VM state: " + state + "\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
if vbds.empty? and xapi.VDI.get_type(vdi_).match('system')
|
51
|
+
puts " No VM attached!"
|
52
|
+
#puts " No VM attached! Use vdi delete --cleanup to delete this volume."
|
53
|
+
end
|
54
|
+
puts "================================================"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
data/lib/knife-xapi/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-xapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chef
|
@@ -87,6 +87,9 @@ files:
|
|
87
87
|
- lib/chef/knife/xapi_guest_create.rb
|
88
88
|
- lib/chef/knife/xapi_guest_delete.rb
|
89
89
|
- lib/chef/knife/xapi_guest_list.rb
|
90
|
+
- lib/chef/knife/xapi_vdi_create.rb
|
91
|
+
- lib/chef/knife/xapi_vdi_delete.rb
|
92
|
+
- lib/chef/knife/xapi_vdi_list.rb
|
90
93
|
- lib/knife-xapi/version.rb
|
91
94
|
homepage: https://github.com/spheromak/knife-xapi
|
92
95
|
licenses: []
|
@@ -108,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
111
|
version: '0'
|
109
112
|
requirements: []
|
110
113
|
rubyforge_project:
|
111
|
-
rubygems_version: 1.8.
|
114
|
+
rubygems_version: 1.8.23
|
112
115
|
signing_key:
|
113
116
|
specification_version: 3
|
114
117
|
summary: Xen API Support for Chef's Knife Command
|