knife-cloudstack 0.0.16 → 0.0.17
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.rdoc +7 -0
- data/lib/chef/knife/cs_server_create.rb +11 -5
- data/lib/chef/knife/cs_server_delete.rb +1 -1
- data/lib/chef/knife/cs_server_list.rb +9 -4
- data/lib/chef/knife/cs_stack_create.rb +10 -1
- data/lib/chef/knife/cs_stack_delete.rb +9 -18
- data/lib/chef/knife/cs_template_register.rb +7 -0
- data/lib/knife-cloudstack/connection.rb +16 -18
- metadata +36 -36
data/CHANGES.rdoc
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
= Changes
|
2
2
|
|
3
|
+
== 2014-03-04 (0.0.17)
|
4
|
+
* Added support for --isdynamicallyscalable for <tt>cs template register</tt> (Sander Botman, 3 Apr 2014)
|
5
|
+
* Added support for --anti-affinity-groups for <tt>cs server create</tt> (John E. Vincent, 2 Apr 2014)
|
6
|
+
* Bugfix: on winrm bootstrap (Sander van Harmelen, 26 Mar 2014)
|
7
|
+
* Added support for --expunge for destroying server (Ian Southam, 19 Mar 2014)
|
8
|
+
* Bugfix: cosmetic changes on error output (Sander Botman, 5 Mar 2014)
|
9
|
+
|
3
10
|
== 2014-02-12 (0.0.16)
|
4
11
|
* Added support for --no-public-ip for <tt>cs server list</tt> (Sander Botman, 12 Feb 2014)
|
5
12
|
* Added support for secret and secret_file in <tt>cs server create</tt> (Jeremy Baumont, 10 Feb 2014)
|
@@ -205,6 +205,11 @@ module KnifeCloudstack
|
|
205
205
|
:proc => lambda { |o| o.split(/[\s,]+/) },
|
206
206
|
:default => []
|
207
207
|
|
208
|
+
option :aag,
|
209
|
+
:long => "--anti-affinity-groups GROUP_NAME",
|
210
|
+
:description => "Comma separated list of anti-affinity group names",
|
211
|
+
:default => false
|
212
|
+
|
208
213
|
option :fw_rules,
|
209
214
|
:short => "-f PORT_RULES",
|
210
215
|
:long => "--fw-rules PORT_RULES",
|
@@ -241,7 +246,7 @@ module KnifeCloudstack
|
|
241
246
|
|
242
247
|
# This little peace of code sets the Chef node-name to the VM name when a node-name is not specifically given
|
243
248
|
unless locate_config_value :chef_node_name
|
244
|
-
|
249
|
+
config[:chef_node_name] = @name_args.first
|
245
250
|
end
|
246
251
|
|
247
252
|
if @windows_image and locate_config_value(:kerberos_realm)
|
@@ -268,8 +273,9 @@ module KnifeCloudstack
|
|
268
273
|
params['hypervisor'] = locate_config_value(:cloudstack_hypervisor) if locate_config_value(:cloudstack_hypervisor)
|
269
274
|
|
270
275
|
params['keypair'] = locate_config_value :keypair if locate_config_value :keypair
|
276
|
+
params['affinitygroupnames'] = locate_config_value :aag if locate_config_value :aag
|
271
277
|
params['displayname'] = if locate_config_value :set_display_name and locate_config_value :chef_node_name then locate_config_value :chef_node_name else hostname end
|
272
|
-
params['ipaddress'] = locate_config_value(:ik_private_ip) if locate_config_value(:ik_private_ip)
|
278
|
+
params['ipaddress'] = locate_config_value(:ik_private_ip) if locate_config_value(:ik_private_ip)
|
273
279
|
|
274
280
|
server = connection.create_server(
|
275
281
|
hostname,
|
@@ -585,9 +591,9 @@ module KnifeCloudstack
|
|
585
591
|
ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
|
586
592
|
exit 1
|
587
593
|
end
|
588
|
-
bootstrap.config[:chef_node_name] =
|
589
|
-
bootstrap.config[:encrypted_data_bag_secret] =
|
590
|
-
bootstrap.config[:encrypted_data_bag_secret_file] =
|
594
|
+
bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server["name"]
|
595
|
+
bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:secret)
|
596
|
+
bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:secret_file)
|
591
597
|
bootstrap_common_params(bootstrap)
|
592
598
|
end
|
593
599
|
|
@@ -58,7 +58,7 @@ module KnifeCloudstack
|
|
58
58
|
if result
|
59
59
|
print "#{ui.color("Waiting for deletion", :magenta)}"
|
60
60
|
disassociate_virtual_ip_address server
|
61
|
-
connection.delete_server
|
61
|
+
connection.delete_server(hostname, false)
|
62
62
|
puts "\n"
|
63
63
|
ui.msg("Deleted server #{hostname}")
|
64
64
|
|
@@ -45,7 +45,10 @@ module KnifeCloudstack
|
|
45
45
|
:short => "-a ACTION",
|
46
46
|
:long => "--action ACTION",
|
47
47
|
:description => "start, stop or destroy the instances in your result"
|
48
|
-
|
48
|
+
|
49
|
+
option :expunge,
|
50
|
+
:long => "--expunge",
|
51
|
+
:description => "If used with --action destroy, will cause the server to be expunged"
|
49
52
|
option :public_ip,
|
50
53
|
:long => "--[no-]public-ip",
|
51
54
|
:description => "Show or don't show the public IP for server in your result",
|
@@ -70,7 +73,9 @@ module KnifeCloudstack
|
|
70
73
|
params['listall'] = locate_config_value(:listall) if locate_config_value(:listall)
|
71
74
|
params['keyword'] = locate_config_value(:keyword) if locate_config_value(:keyword)
|
72
75
|
params['name'] = locate_config_value(:name) if locate_config_value(:name)
|
73
|
-
|
76
|
+
params['expunge'] = locate_config_value(:expunge) if locate_config_value(:expunge)
|
77
|
+
params['expunge'] = false if params['expunge'].nil?
|
78
|
+
|
74
79
|
##
|
75
80
|
# Get the public IP address if possible, except when the option --no-public-ip is given.
|
76
81
|
|
@@ -89,7 +94,7 @@ module KnifeCloudstack
|
|
89
94
|
# Executing actions against the list results that are returned.
|
90
95
|
|
91
96
|
if locate_config_value(:action)
|
92
|
-
|
97
|
+
result.each do |r|
|
93
98
|
hostname = r['name']
|
94
99
|
case locate_config_value(:action).downcase
|
95
100
|
when "start" then
|
@@ -115,7 +120,7 @@ module KnifeCloudstack
|
|
115
120
|
result = confirm_action("Do you really want to destroy this server ")
|
116
121
|
if result then
|
117
122
|
print "#{ui.color("Waiting for demolition", :magenta)}"
|
118
|
-
connection.delete_server(hostname)
|
123
|
+
connection.delete_server(hostname, params['expunge'])
|
119
124
|
puts "\n"
|
120
125
|
ui.msg("Destroyed server #{hostname}")
|
121
126
|
end
|
@@ -60,7 +60,10 @@ module KnifeCloudstack
|
|
60
60
|
|
61
61
|
def run
|
62
62
|
validate_base_options
|
63
|
-
|
63
|
+
if @name_args.first.nil?
|
64
|
+
ui.error "Please specify json file eg: knife cs stack create JSON_FILE"
|
65
|
+
exit 1
|
66
|
+
end
|
64
67
|
file_path = File.expand_path(@name_args.first)
|
65
68
|
unless File.exist?(file_path) then
|
66
69
|
ui.error "Stack file '#{file_path}' not found. Please check the path."
|
@@ -98,6 +101,12 @@ module KnifeCloudstack
|
|
98
101
|
cmd = KnifeCloudstack::CsServerCreate.new([server[:name]])
|
99
102
|
# configure and run command
|
100
103
|
# TODO: validate parameters
|
104
|
+
cmd.config[:cloudstack_url] = config[:cloudstack_url]
|
105
|
+
cmd.config[:cloudstack_api_key] = config[:cloudstack_api_key]
|
106
|
+
cmd.config[:cloudstack_secret_key] = config[:cloudstack_secret_key]
|
107
|
+
cmd.config[:cloudstack_proxy] = config[:cloudstack_proxy]
|
108
|
+
cmd.config[:cloudstack_no_ssl_verify] = config[:cloudstack_no_ssl_verify]
|
109
|
+
cmd.config[:cloudstack_project] = config[:cloudstack_project]
|
101
110
|
cmd.config[:ssh_user] = config[:ssh_user]
|
102
111
|
cmd.config[:ssh_password] = config[:ssh_password]
|
103
112
|
cmd.config[:ssh_port] = config[:ssh_port] || "22" # Chef::Config[:knife][:ssh_port]
|
@@ -16,9 +16,13 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
+
require 'chef/knife/cs_base'
|
20
|
+
|
19
21
|
module KnifeCloudstack
|
20
22
|
class CsStackDelete < Chef::Knife
|
21
23
|
|
24
|
+
include Chef::Knife::KnifeCloudstackBase
|
25
|
+
|
22
26
|
deps do
|
23
27
|
require 'chef/json_compat'
|
24
28
|
require 'chef/mash'
|
@@ -30,25 +34,11 @@ module KnifeCloudstack
|
|
30
34
|
|
31
35
|
banner "knife cs stack delete JSON_FILE (options)"
|
32
36
|
|
33
|
-
option :cloudstack_url,
|
34
|
-
:short => "-U URL",
|
35
|
-
:long => "--cloudstack-url URL",
|
36
|
-
:description => "The CloudStack endpoint URL",
|
37
|
-
:proc => Proc.new { |url| Chef::Config[:knife][:cloudstack_url] = url }
|
38
|
-
|
39
|
-
option :cloudstack_api_key,
|
40
|
-
:short => "-A KEY",
|
41
|
-
:long => "--cloudstack-api-key KEY",
|
42
|
-
:description => "Your CloudStack API key",
|
43
|
-
:proc => Proc.new { |key| Chef::Config[:knife][:cloudstack_api_key] = key }
|
44
|
-
|
45
|
-
option :cloudstack_secret_key,
|
46
|
-
:short => "-K SECRET",
|
47
|
-
:long => "--cloudstack-secret-key SECRET",
|
48
|
-
:description => "Your CloudStack secret key",
|
49
|
-
:proc => Proc.new { |key| Chef::Config[:knife][:cloudstack_secret_key] = key }
|
50
|
-
|
51
37
|
def run
|
38
|
+
if @name_args.first.nil?
|
39
|
+
ui.error "Please specify json file eg: knife cs stack delete JSON_FILE"
|
40
|
+
exit 1
|
41
|
+
end
|
52
42
|
file_path = File.expand_path(@name_args.first)
|
53
43
|
unless File.exist?(file_path) then
|
54
44
|
ui.error "Stack file '#{file_path}' not found. Please check the path."
|
@@ -80,6 +70,7 @@ module KnifeCloudstack
|
|
80
70
|
def delete_server(server_name)
|
81
71
|
cmd = KnifeCloudstack::CsServerDelete.new([server_name])
|
82
72
|
cmd.config[:yes] = true
|
73
|
+
cmd.config[:expunge] = true
|
83
74
|
cmd.run_with_pretty_exceptions
|
84
75
|
end
|
85
76
|
|
@@ -73,6 +73,12 @@ module KnifeCloudstack
|
|
73
73
|
:boolean => true,
|
74
74
|
:default => false
|
75
75
|
|
76
|
+
option :isdynamicallyscalable,
|
77
|
+
:long => "--isdynamicallyscalable",
|
78
|
+
:description => "Is the template dynamically scalable. Default: NO",
|
79
|
+
:boolean => true,
|
80
|
+
:default => false
|
81
|
+
|
76
82
|
option :featured,
|
77
83
|
:long => "--[no-]featured",
|
78
84
|
:description => "Is the tempalte featured? Default: NO",
|
@@ -159,6 +165,7 @@ module KnifeCloudstack
|
|
159
165
|
'zoneid' => zoneid,
|
160
166
|
'bits' => locate_config_value(:bits),
|
161
167
|
}
|
168
|
+
params['isdynamicallyscalable'] = locate_config_value(:isdynamicallyscalable) if locate_config_value(:isdynamicallyscalable)
|
162
169
|
params['isextractable'] = locate_config_value(:isextractable) if locate_config_value(:isextractable)
|
163
170
|
params['ispublic'] = locate_config_value(:public) if locate_config_value(:public)
|
164
171
|
params['isfeatured'] = locate_config_value(:featured) if locate_config_value(:featured)
|
@@ -81,17 +81,14 @@ module CloudstackClient
|
|
81
81
|
'command' => 'listVirtualMachines',
|
82
82
|
'name' => name
|
83
83
|
}
|
84
|
-
# if @project_id
|
85
|
-
# params['projectId'] = @project_id
|
86
|
-
# end
|
87
84
|
json = send_request(params)
|
88
85
|
machines = json['virtualmachine']
|
89
86
|
|
90
87
|
if !machines || machines.empty? then
|
91
88
|
return nil
|
92
89
|
end
|
93
|
-
|
94
|
-
|
90
|
+
machine = machines.select { |item| name == item['name'] }
|
91
|
+
machine.first
|
95
92
|
end
|
96
93
|
|
97
94
|
##
|
@@ -174,14 +171,14 @@ module CloudstackClient
|
|
174
171
|
|
175
172
|
if host_name then
|
176
173
|
if get_server(host_name) then
|
177
|
-
puts "
|
174
|
+
puts "\nError: Server '#{host_name}' already exists."
|
178
175
|
exit 1
|
179
176
|
end
|
180
177
|
end
|
181
178
|
|
182
179
|
service = get_service_offering(service_name)
|
183
180
|
if !service then
|
184
|
-
puts "
|
181
|
+
puts "\nError: Service offering '#{service_name}' is invalid"
|
185
182
|
exit 1
|
186
183
|
end
|
187
184
|
|
@@ -189,14 +186,14 @@ module CloudstackClient
|
|
189
186
|
template = get_iso(template_name, zone_name) unless template
|
190
187
|
|
191
188
|
if !template then
|
192
|
-
puts "
|
189
|
+
puts "\nError: Template / ISO name: '#{template_name}' is invalid"
|
193
190
|
exit 1
|
194
191
|
end
|
195
192
|
|
196
193
|
if disk_name then
|
197
194
|
disk = get_disk_offering(disk_name)
|
198
195
|
if !disk then
|
199
|
-
puts "
|
196
|
+
puts "\nError: Disk offering '#{disk_name}' is invalid"
|
200
197
|
exit 1
|
201
198
|
end
|
202
199
|
end
|
@@ -204,7 +201,7 @@ module CloudstackClient
|
|
204
201
|
zone = zone_name ? get_zone(zone_name) : get_default_zone
|
205
202
|
if !zone then
|
206
203
|
msg = zone_name ? "Zone '#{zone_name}' is invalid" : "No default zone found"
|
207
|
-
puts "
|
204
|
+
puts "\nError: #{msg}"
|
208
205
|
exit 1
|
209
206
|
end
|
210
207
|
|
@@ -218,7 +215,7 @@ module CloudstackClient
|
|
218
215
|
network_names.each do |name|
|
219
216
|
network = get_network(name)
|
220
217
|
if !network then
|
221
|
-
puts "
|
218
|
+
puts "\nError: Network '#{name}' not found"
|
222
219
|
end
|
223
220
|
networks << get_network(name)
|
224
221
|
end
|
@@ -228,7 +225,7 @@ module CloudstackClient
|
|
228
225
|
networks << get_default_network(zone['id'])
|
229
226
|
end
|
230
227
|
if networks.empty? then
|
231
|
-
puts "No default network found"
|
228
|
+
puts "\nError: No default network found"
|
232
229
|
exit 1
|
233
230
|
end
|
234
231
|
network_ids = networks.map { |network|
|
@@ -267,16 +264,17 @@ module CloudstackClient
|
|
267
264
|
# Deletes the server with the specified name.
|
268
265
|
#
|
269
266
|
|
270
|
-
def delete_server(name)
|
267
|
+
def delete_server(name, expunge)
|
271
268
|
server = get_server(name)
|
272
269
|
if !server || !server['id'] then
|
273
|
-
puts "
|
270
|
+
puts "\nError: Virtual machine '#{name}' does not exist"
|
274
271
|
exit 1
|
275
272
|
end
|
276
273
|
|
277
274
|
params = {
|
278
275
|
'command' => 'destroyVirtualMachine',
|
279
|
-
'id' => server['id']
|
276
|
+
'id' => server['id'],
|
277
|
+
'expunge' => expunge
|
280
278
|
}
|
281
279
|
|
282
280
|
json = send_async_request(params)
|
@@ -290,7 +288,7 @@ module CloudstackClient
|
|
290
288
|
def stop_server(name, forced=nil)
|
291
289
|
server = get_server(name)
|
292
290
|
if !server || !server['id'] then
|
293
|
-
puts "
|
291
|
+
puts "\nError: Virtual machine '#{name}' does not exist"
|
294
292
|
exit 1
|
295
293
|
end
|
296
294
|
|
@@ -311,7 +309,7 @@ module CloudstackClient
|
|
311
309
|
def start_server(name)
|
312
310
|
server = get_server(name)
|
313
311
|
if !server || !server['id'] then
|
314
|
-
puts "
|
312
|
+
puts "\nError: Virtual machine '#{name}' does not exist"
|
315
313
|
exit 1
|
316
314
|
end
|
317
315
|
|
@@ -331,7 +329,7 @@ module CloudstackClient
|
|
331
329
|
def reboot_server(name)
|
332
330
|
server = get_server(name)
|
333
331
|
if !server || !server['id'] then
|
334
|
-
puts "
|
332
|
+
puts "\nError: Virtual machine '#{name}' does not exist"
|
335
333
|
exit 1
|
336
334
|
end
|
337
335
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-cloudstack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.17
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2014-
|
16
|
+
date: 2014-04-03 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: chef
|
@@ -64,50 +64,50 @@ files:
|
|
64
64
|
- CHANGES.rdoc
|
65
65
|
- README.rdoc
|
66
66
|
- LICENSE
|
67
|
-
- lib/chef/knife/
|
68
|
-
- lib/chef/knife/
|
69
|
-
- lib/chef/knife/
|
70
|
-
- lib/chef/knife/
|
71
|
-
- lib/chef/knife/
|
72
|
-
- lib/chef/knife/
|
67
|
+
- lib/chef/knife/cs_iso_list.rb
|
68
|
+
- lib/chef/knife/cs_server_add_nic.rb
|
69
|
+
- lib/chef/knife/cs_template_register.rb
|
70
|
+
- lib/chef/knife/cs_cluster_list.rb
|
71
|
+
- lib/chef/knife/cs_template_create.rb
|
72
|
+
- lib/chef/knife/cs_disk_list.rb
|
73
|
+
- lib/chef/knife/cs_template_extract.rb
|
74
|
+
- lib/chef/knife/cs_server_list.rb
|
75
|
+
- lib/chef/knife/cs_aag_list.rb
|
73
76
|
- lib/chef/knife/cs_host_list.rb
|
74
|
-
- lib/chef/knife/
|
77
|
+
- lib/chef/knife/cs_network_list.rb
|
78
|
+
- lib/chef/knife/cs_oscategory_list.rb
|
75
79
|
- lib/chef/knife/cs_config_list.rb
|
76
|
-
- lib/chef/knife/
|
77
|
-
- lib/chef/knife/cs_server_create.rb
|
80
|
+
- lib/chef/knife/cs_domain_list.rb
|
78
81
|
- lib/chef/knife/cs_hosts.rb
|
79
|
-
- lib/chef/knife/cs_keypair_create.rb
|
80
|
-
- lib/chef/knife/cs_server_start.rb
|
81
|
-
- lib/chef/knife/cs_disk_list.rb
|
82
|
-
- lib/chef/knife/cs_router_list.rb
|
83
|
-
- lib/chef/knife/cs_server_stop.rb
|
84
|
-
- lib/chef/knife/cs_publicip_list.rb
|
85
82
|
- lib/chef/knife/cs_pod_list.rb
|
86
|
-
- lib/chef/knife/
|
87
|
-
- lib/chef/knife/
|
88
|
-
- lib/chef/knife/cs_server_reboot.rb
|
83
|
+
- lib/chef/knife/cs_volume_create.rb
|
84
|
+
- lib/chef/knife/cs_ostype_list.rb
|
89
85
|
- lib/chef/knife/cs_base.rb
|
90
|
-
- lib/chef/knife/cs_iso_list.rb
|
91
|
-
- lib/chef/knife/cs_stack_create.rb
|
92
|
-
- lib/chef/knife/cs_volume_list.rb
|
93
|
-
- lib/chef/knife/cs_template_extract.rb
|
94
86
|
- lib/chef/knife/cs_service_list.rb
|
87
|
+
- lib/chef/knife/cs_server_create.rb
|
88
|
+
- lib/chef/knife/cs_server_delete.rb
|
89
|
+
- lib/chef/knife/cs_template_list.rb
|
90
|
+
- lib/chef/knife/cs_publicip_list.rb
|
95
91
|
- lib/chef/knife/cs_zone_list.rb
|
96
|
-
- lib/chef/knife/
|
92
|
+
- lib/chef/knife/cs_server_reboot.rb
|
93
|
+
- lib/chef/knife/cs_server_remove_nic.rb
|
94
|
+
- lib/chef/knife/cs_keypair_delete.rb
|
95
|
+
- lib/chef/knife/cs_baselist.rb
|
96
|
+
- lib/chef/knife/cs_router_list.rb
|
97
97
|
- lib/chef/knife/cs_firewallrule_create.rb
|
98
|
-
- lib/chef/knife/cs_forwardrule_create.rb
|
99
|
-
- lib/chef/knife/cs_template_create.rb
|
100
|
-
- lib/chef/knife/cs_oscategory_list.rb
|
101
|
-
- lib/chef/knife/cs_server_list.rb
|
102
|
-
- lib/chef/knife/cs_stack_delete.rb
|
103
98
|
- lib/chef/knife/cs_account_list.rb
|
104
|
-
- lib/chef/knife/
|
105
|
-
- lib/chef/knife/cs_server_delete.rb
|
106
|
-
- lib/chef/knife/cs_domain_list.rb
|
107
|
-
- lib/chef/knife/cs_server_add_nic.rb
|
99
|
+
- lib/chef/knife/cs_server_start.rb
|
108
100
|
- lib/chef/knife/cs_keypair_list.rb
|
101
|
+
- lib/chef/knife/cs_server_stop.rb
|
102
|
+
- lib/chef/knife/cs_stack_delete.rb
|
109
103
|
- lib/chef/knife/cs_project_list.rb
|
110
|
-
- lib/chef/knife/
|
104
|
+
- lib/chef/knife/cs_user_list.rb
|
105
|
+
- lib/chef/knife/cs_volume_list.rb
|
106
|
+
- lib/chef/knife/cs_stack_create.rb
|
107
|
+
- lib/chef/knife/cs_keypair_create.rb
|
108
|
+
- lib/chef/knife/cs_firewallrule_list.rb
|
109
|
+
- lib/chef/knife/cs_forwardrule_create.rb
|
110
|
+
- lib/chef/knife/cs_securitygroup_list.rb
|
111
111
|
- lib/knife-cloudstack/connection.rb
|
112
112
|
homepage: http://cloudstack.org/
|
113
113
|
licenses: []
|
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
129
|
version: '0'
|
130
130
|
requirements: []
|
131
131
|
rubyforge_project:
|
132
|
-
rubygems_version: 1.8.
|
132
|
+
rubygems_version: 1.8.25
|
133
133
|
signing_key:
|
134
134
|
specification_version: 3
|
135
135
|
summary: A knife plugin for the CloudStack API
|