knife-xapi 0.3.6 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|