cloudstack-cli 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/lib/cloudstack-cli/base.rb +6 -1
- data/lib/cloudstack-cli/cli.rb +7 -1
- data/lib/cloudstack-cli/commands/disk_offering.rb +22 -0
- data/lib/cloudstack-cli/commands/iso.rb +30 -0
- data/lib/cloudstack-cli/commands/network.rb +38 -4
- data/lib/cloudstack-cli/commands/offering.rb +2 -11
- data/lib/cloudstack-cli/commands/server.rb +6 -4
- data/lib/cloudstack-cli/commands/template.rb +10 -4
- data/lib/cloudstack-cli/helper.rb +1 -1
- data/lib/cloudstack-cli/version.rb +1 -1
- data/lib/cloudstack-client/client.rb +133 -12
- metadata +3 -1
data/Gemfile.lock
CHANGED
data/lib/cloudstack-cli/base.rb
CHANGED
@@ -9,6 +9,11 @@ module CloudstackCli
|
|
9
9
|
exit!
|
10
10
|
}
|
11
11
|
|
12
|
+
# exit with return code 1 in case of a error
|
13
|
+
def self.exit_on_failure?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
12
17
|
no_commands do
|
13
18
|
def client
|
14
19
|
@config ||= CloudstackClient::ConnectionHelper.load_configuration(options[:config])
|
@@ -29,7 +34,7 @@ module CloudstackCli
|
|
29
34
|
end
|
30
35
|
|
31
36
|
def filter_by(objects, tag_name, tag)
|
32
|
-
objects.select {|r| r[tag_name].downcase == tag }
|
37
|
+
objects.select {|r| r[tag_name].downcase == tag.downcase }
|
33
38
|
end
|
34
39
|
end
|
35
40
|
end
|
data/lib/cloudstack-cli/cli.rb
CHANGED
@@ -65,6 +65,9 @@ module CloudstackCli
|
|
65
65
|
desc "offering SUBCOMMAND ...ARGS", "Manage offerings"
|
66
66
|
subcommand "offering", Offering
|
67
67
|
|
68
|
+
desc "disk_offering SUBCOMMAND ...ARGS", "Manage disk offerings"
|
69
|
+
subcommand "disk_offering", DiskOffering
|
70
|
+
|
68
71
|
desc "network SUBCOMMAND ...ARGS", "Manage networks"
|
69
72
|
subcommand "network", Network
|
70
73
|
|
@@ -74,9 +77,12 @@ module CloudstackCli
|
|
74
77
|
desc "load_balancer SUBCOMMAND ...ARGS", "Manage load balancing rules"
|
75
78
|
subcommand "load_balancer", LoadBalancer
|
76
79
|
|
77
|
-
desc "template SUBCOMMAND ...ARGS", "Manage
|
80
|
+
desc "template SUBCOMMAND ...ARGS", "Manage templates"
|
78
81
|
subcommand "template", Template
|
79
82
|
|
83
|
+
desc "iso SUBCOMMAND ...ARGS", "Manage iso's"
|
84
|
+
subcommand "iso", Iso
|
85
|
+
|
80
86
|
desc "router SUBCOMMAND ...ARGS", "Manage virtual routers"
|
81
87
|
subcommand "router", Router
|
82
88
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class DiskOffering < CloudstackCli::Base
|
2
|
+
|
3
|
+
desc 'list', 'list disk offerings'
|
4
|
+
option :domain
|
5
|
+
def list
|
6
|
+
offerings = client.list_disk_offerings(options[:domain])
|
7
|
+
if offerings.size < 1
|
8
|
+
puts "No offerings found"
|
9
|
+
else
|
10
|
+
table = [["Name", "Displaytext", "Domain", "ID"]]
|
11
|
+
offerings.each do |offering|
|
12
|
+
table << [
|
13
|
+
offering["name"],
|
14
|
+
offering["displaytext"],
|
15
|
+
offering["domain"],
|
16
|
+
offering["id"]
|
17
|
+
]
|
18
|
+
end
|
19
|
+
print_table table
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Iso < CloudstackCli::Base
|
2
|
+
|
3
|
+
desc 'list [TYPE]', "list iso's by type [featured|self|self-executable|executable|community]"
|
4
|
+
option :project
|
5
|
+
option :zone
|
6
|
+
option :account
|
7
|
+
def list(type='featured')
|
8
|
+
project = find_project if options[:project]
|
9
|
+
unless %w(featured self self-executable executable community).include? type
|
10
|
+
say "unsupported iso type '#{type}'", :red
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
zone = client.get_zone(options[:zone]) if options[:zone]
|
14
|
+
isos = client.list_isos(
|
15
|
+
type: type,
|
16
|
+
project_id: project ? project['id'] : nil,
|
17
|
+
zone_id: zone ? zone['id'] : nil
|
18
|
+
)
|
19
|
+
if isos.size < 1
|
20
|
+
puts "No iso's found"
|
21
|
+
else
|
22
|
+
table = [["Name", "Zone", "Bootable"]]
|
23
|
+
isos.each do |iso|
|
24
|
+
table << [iso['name'], iso['zonename'], iso['bootable']]
|
25
|
+
end
|
26
|
+
print_table(table)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -5,10 +5,31 @@ class Network < CloudstackCli::Base
|
|
5
5
|
# TODO
|
6
6
|
end
|
7
7
|
|
8
|
+
desc "default", "get the default network"
|
9
|
+
option :zone
|
10
|
+
def default
|
11
|
+
network = client.get_default_network(options[:zone])
|
12
|
+
unless network
|
13
|
+
puts "No default network found."
|
14
|
+
else
|
15
|
+
table = [["Name", "Displaytext", "Domain", "Zone"]]
|
16
|
+
table[0] << "ID" if options[:showid]
|
17
|
+
table << [
|
18
|
+
network["name"],
|
19
|
+
network["displaytext"],
|
20
|
+
network["domain"],
|
21
|
+
network["zonename"]
|
22
|
+
]
|
23
|
+
table[-1] << network["id"] if options[:showid]
|
24
|
+
print_table table
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
8
28
|
desc "list", "list networks"
|
9
29
|
option :project
|
10
30
|
option :account
|
11
31
|
option :showid, type: :boolean
|
32
|
+
option :isdefault, type: :boolean
|
12
33
|
def list
|
13
34
|
project = find_project if options[:project]
|
14
35
|
networks = []
|
@@ -17,13 +38,13 @@ class Network < CloudstackCli::Base
|
|
17
38
|
elsif options[:account]
|
18
39
|
networks = client.list_networks(account: options[:account])
|
19
40
|
else
|
20
|
-
networks = client.list_networks(project_id: -1)
|
41
|
+
networks = client.list_networks(project_id: -1, isdefault: options[:isdefault])
|
21
42
|
end
|
22
43
|
|
23
44
|
if networks.size < 1
|
24
|
-
puts "No networks found"
|
45
|
+
puts "No networks found."
|
25
46
|
else
|
26
|
-
table = [["Name", "Displaytext", "Account", "Project", "Domain", "State"]]
|
47
|
+
table = [["Name", "Displaytext", "Account", "Project", "Domain", "State", "Type"]]
|
27
48
|
table[0] << "ID" if options[:showid]
|
28
49
|
networks.each do |network|
|
29
50
|
table << [
|
@@ -32,7 +53,8 @@ class Network < CloudstackCli::Base
|
|
32
53
|
network["account"],
|
33
54
|
network["project"],
|
34
55
|
network["domain"],
|
35
|
-
network["state"]
|
56
|
+
network["state"],
|
57
|
+
network["type"]
|
36
58
|
]
|
37
59
|
table[-1] << network["id"] if options[:showid]
|
38
60
|
end
|
@@ -40,4 +62,16 @@ class Network < CloudstackCli::Base
|
|
40
62
|
end
|
41
63
|
end
|
42
64
|
|
65
|
+
desc "delete NAME", "delete network"
|
66
|
+
def delete(name)
|
67
|
+
network = client.get_network(name, -1)
|
68
|
+
unless network
|
69
|
+
say "Network #{name} not found."
|
70
|
+
exit 1
|
71
|
+
end
|
72
|
+
if yes? "Destroy network #{network['name']} - #{network['name']}?"
|
73
|
+
p client.delete_network(network['id'])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
43
77
|
end
|
@@ -1,18 +1,9 @@
|
|
1
1
|
class Offering < CloudstackCli::Base
|
2
2
|
|
3
|
-
desc 'list', 'list offerings
|
3
|
+
desc 'list', 'list compute offerings'
|
4
4
|
option :domain
|
5
|
-
def list
|
5
|
+
def list
|
6
6
|
offerings = client.list_service_offerings(options[:domain])
|
7
|
-
|
8
|
-
offerings.group_by{|o| o["domain"]}.each_value do |offers|
|
9
|
-
offers.sort {
|
10
|
-
|oa, ob| [oa["cpunumber"], oa["memory"]] <=> [ob["cpunumber"], ob["memory"]]
|
11
|
-
}.each do |offer|
|
12
|
-
puts "#{offer['domain']} - #{offer["displaytext"]}"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
7
|
if offerings.size < 1
|
17
8
|
puts "No offerings found"
|
18
9
|
else
|
@@ -34,14 +34,15 @@ class Server < CloudstackCli::Base
|
|
34
34
|
|
35
35
|
desc "create NAME", "create a server"
|
36
36
|
option :zone, required: true
|
37
|
-
option :template, required: true
|
37
|
+
option :template, required: true, desc: "name of template or iso"
|
38
38
|
option :offering, required: true
|
39
39
|
option :networks, type: :array, required: true
|
40
40
|
option :project
|
41
41
|
option :port_rules, type: :array,
|
42
42
|
default: [],
|
43
43
|
desc: "Port Forwarding Rules [public_ip]:port ..."
|
44
|
-
option :
|
44
|
+
option :disk_offering
|
45
|
+
option :hypervisor, desc: "only used for iso deployments, defaults to vmware"
|
45
46
|
def create(name)
|
46
47
|
if project = find_project
|
47
48
|
project_id = project["id"]
|
@@ -51,14 +52,15 @@ class Server < CloudstackCli::Base
|
|
51
52
|
say "Create server #{name}...", :yellow
|
52
53
|
server = client.create_server(
|
53
54
|
name, options[:offering], options[:template],
|
54
|
-
options[:zone], options[:networks], options[:project]
|
55
|
+
options[:zone], options[:networks], options[:project],
|
56
|
+
options[:disk_offering], options[:hypervisor]
|
55
57
|
)
|
56
58
|
puts
|
57
59
|
say "Server #{name} has been created.", :green
|
58
60
|
client.wait_for_server_state(server["id"], "Running")
|
59
61
|
say "Server #{name} is running.", :green
|
60
62
|
else
|
61
|
-
say "Server #{name} already exists.", :
|
63
|
+
say "Server #{name} already exists.", :yellow
|
62
64
|
# TODO: check status of server
|
63
65
|
end
|
64
66
|
|
@@ -1,20 +1,26 @@
|
|
1
1
|
class Template < CloudstackCli::Base
|
2
2
|
|
3
|
-
desc 'list', 'list templates by type [featured|self|self-executable|executable|community]'
|
3
|
+
desc 'list [TYPE]', 'list templates by type [featured|self|self-executable|executable|community]'
|
4
4
|
option :project
|
5
|
+
option :zone
|
5
6
|
def list(type='featured')
|
6
7
|
project = find_project if options[:project]
|
7
8
|
unless %w(featured self self-executable executable community).include? type
|
8
9
|
say "unsupported template type '#{type}'", :red
|
9
10
|
exit 1
|
10
11
|
end
|
11
|
-
|
12
|
+
zone = client.get_zone(options[:zone]) if options[:zone]
|
13
|
+
templates = client.list_templates(
|
14
|
+
type: type,
|
15
|
+
project_id: project ? project['id'] : nil,
|
16
|
+
zone_id: zone ? zone['id'] : nil
|
17
|
+
)
|
12
18
|
if templates.size < 1
|
13
19
|
puts "No templates found"
|
14
20
|
else
|
15
|
-
table = [["Name", "Zone"]]
|
21
|
+
table = [["Name", "Zone", "Format"]]
|
16
22
|
templates.each do |template|
|
17
|
-
table << [template['name'], template['zonename']]
|
23
|
+
table << [template['name'], template['zonename'], template['format']]
|
18
24
|
end
|
19
25
|
print_table(table)
|
20
26
|
end
|
@@ -28,7 +28,7 @@ module CloudstackCli
|
|
28
28
|
client.wait_for_server_state(server["id"], "Running")
|
29
29
|
say "Server #{server["name"]} is running.", :green
|
30
30
|
else
|
31
|
-
say "Server #{name} already exists.", :
|
31
|
+
say "Server #{name} already exists.", :yellow
|
32
32
|
end
|
33
33
|
|
34
34
|
if pf_rules && pf_rules.size > 0
|
@@ -143,7 +143,8 @@ module CloudstackClient
|
|
143
143
|
##
|
144
144
|
# Deploys a new server using the specified parameters.
|
145
145
|
|
146
|
-
def create_server(host_name, service_name, template_name, zone_name=nil,
|
146
|
+
def create_server(host_name, service_name, template_name, zone_name=nil,
|
147
|
+
network_names=[], project_name=nil, disk_offering=nil, hypervisor=nil)
|
147
148
|
if host_name then
|
148
149
|
if get_server(host_name) then
|
149
150
|
puts "Error: Server '#{host_name}' already exists."
|
@@ -159,8 +160,11 @@ module CloudstackClient
|
|
159
160
|
|
160
161
|
template = get_template(template_name)
|
161
162
|
if !template then
|
162
|
-
|
163
|
-
|
163
|
+
template = get_iso(template_name)
|
164
|
+
if !template then
|
165
|
+
puts "Error: Template '#{template_name}' is invalid"
|
166
|
+
exit 1
|
167
|
+
end
|
164
168
|
end
|
165
169
|
|
166
170
|
zone = zone_name ? get_zone(zone_name) : get_default_zone
|
@@ -199,6 +203,16 @@ module CloudstackClient
|
|
199
203
|
network['id']
|
200
204
|
}
|
201
205
|
|
206
|
+
if disk_offering
|
207
|
+
disk_offering = get_disk_offering(disk_offering)
|
208
|
+
unless disk_offering
|
209
|
+
msg = zone_name ? "Zone '#{zone_name}' is invalid" : "No default zone found"
|
210
|
+
puts "Error: #{msg}"
|
211
|
+
exit 1
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
202
216
|
params = {
|
203
217
|
'command' => 'deployVirtualMachine',
|
204
218
|
'serviceOfferingId' => service['id'],
|
@@ -208,6 +222,8 @@ module CloudstackClient
|
|
208
222
|
}
|
209
223
|
params['name'] = host_name if host_name
|
210
224
|
params['projectid'] = project['id'] if project_name
|
225
|
+
params['diskofferingid'] = disk_offering['id'] if disk_offering
|
226
|
+
params['hypervisor'] = hypervisor || 'vmware' if disk_offering
|
211
227
|
|
212
228
|
json = send_async_request(params)
|
213
229
|
json['virtualmachine']
|
@@ -310,7 +326,6 @@ module CloudstackClient
|
|
310
326
|
return s
|
311
327
|
end
|
312
328
|
}
|
313
|
-
|
314
329
|
nil
|
315
330
|
end
|
316
331
|
|
@@ -380,6 +395,47 @@ module CloudstackClient
|
|
380
395
|
json['serviceoffering']
|
381
396
|
end
|
382
397
|
|
398
|
+
##
|
399
|
+
# Lists all available disk offerings.
|
400
|
+
|
401
|
+
def list_disk_offerings(domain = nil)
|
402
|
+
params = {
|
403
|
+
'command' => 'listDiskOfferings'
|
404
|
+
}
|
405
|
+
|
406
|
+
if domain
|
407
|
+
params['domainid'] = list_domains(domain).first["id"]
|
408
|
+
end
|
409
|
+
|
410
|
+
json = send_request(params)
|
411
|
+
json['diskoffering'] || []
|
412
|
+
end
|
413
|
+
|
414
|
+
##
|
415
|
+
# Get disk offering by name.
|
416
|
+
|
417
|
+
def get_disk_offering(name)
|
418
|
+
|
419
|
+
# TODO: use name parameter
|
420
|
+
# listServiceOfferings in CloudStack 2.2 doesn't seem to work
|
421
|
+
# when the name parameter is specified. When this is fixed,
|
422
|
+
# the name parameter should be added to the request.
|
423
|
+
params = {
|
424
|
+
'command' => 'listDiskOfferings'
|
425
|
+
}
|
426
|
+
json = send_request(params)
|
427
|
+
|
428
|
+
services = json['diskoffering']
|
429
|
+
return nil unless services
|
430
|
+
|
431
|
+
services.each { |s|
|
432
|
+
if s['name'] == name then
|
433
|
+
return s
|
434
|
+
end
|
435
|
+
}
|
436
|
+
nil
|
437
|
+
end
|
438
|
+
|
383
439
|
##
|
384
440
|
# Finds the template with the specified name.
|
385
441
|
|
@@ -433,6 +489,59 @@ module CloudstackClient
|
|
433
489
|
json['template'] || []
|
434
490
|
end
|
435
491
|
|
492
|
+
##
|
493
|
+
# Lists all isos that match the specified filter.
|
494
|
+
#
|
495
|
+
# Allowable filter values are:
|
496
|
+
#
|
497
|
+
# * featured - isos that are featured and are public
|
498
|
+
# * self - isos that have been registered/created by the owner
|
499
|
+
# * self-executable - isos that have been registered/created by the owner that can be used to deploy a new VM
|
500
|
+
# * executable - all isos that can be used to deploy a new VM
|
501
|
+
# * community - isos that are public
|
502
|
+
|
503
|
+
def list_isos(args = {})
|
504
|
+
filter = args[:filter] || 'featured'
|
505
|
+
params = {
|
506
|
+
'command' => 'listIsos',
|
507
|
+
'templateFilter' => filter
|
508
|
+
}
|
509
|
+
params['projectid'] = args[:project_id] if args[:project_id]
|
510
|
+
params['zoneid'] = args[:zone_id] if args[:zone_id]
|
511
|
+
|
512
|
+
json = send_request(params)
|
513
|
+
json['iso'] || []
|
514
|
+
end
|
515
|
+
|
516
|
+
##
|
517
|
+
# Finds the template with the specified name.
|
518
|
+
|
519
|
+
def get_iso(name)
|
520
|
+
|
521
|
+
# TODO: use name parameter
|
522
|
+
# listIsos in CloudStack 2.2 doesn't seem to work
|
523
|
+
# when the name parameter is specified. When this is fixed,
|
524
|
+
# the name parameter should be added to the request.
|
525
|
+
params = {
|
526
|
+
'command' => 'listIsos',
|
527
|
+
'templateFilter' => 'executable'
|
528
|
+
}
|
529
|
+
json = send_request(params)
|
530
|
+
|
531
|
+
isos = json['iso']
|
532
|
+
if !isos then
|
533
|
+
return nil
|
534
|
+
end
|
535
|
+
|
536
|
+
isos.each { |t|
|
537
|
+
if t['name'] == name then
|
538
|
+
return t
|
539
|
+
end
|
540
|
+
}
|
541
|
+
|
542
|
+
nil
|
543
|
+
end
|
544
|
+
|
436
545
|
##
|
437
546
|
# Finds the network with the specified name.
|
438
547
|
|
@@ -458,27 +567,26 @@ module CloudstackClient
|
|
458
567
|
##
|
459
568
|
# Finds the default network.
|
460
569
|
|
461
|
-
def get_default_network
|
570
|
+
def get_default_network(zone = nil)
|
462
571
|
params = {
|
463
572
|
'command' => 'listNetworks',
|
464
573
|
'isDefault' => true
|
465
574
|
}
|
575
|
+
if zone
|
576
|
+
params['zoneid'] = get_zone(zone)['id']
|
577
|
+
end
|
466
578
|
json = send_request(params)
|
467
579
|
|
468
580
|
networks = json['network']
|
469
581
|
return nil if !networks || networks.empty?
|
470
|
-
|
471
|
-
default = networks.first
|
472
|
-
return default if networks.length == 1
|
582
|
+
return networks.first if networks.length == 1
|
473
583
|
|
474
584
|
networks.each { |n|
|
475
585
|
if n['type'] == 'Direct' then
|
476
|
-
|
477
|
-
break
|
586
|
+
return n
|
478
587
|
end
|
479
588
|
}
|
480
|
-
|
481
|
-
default
|
589
|
+
nil
|
482
590
|
end
|
483
591
|
|
484
592
|
##
|
@@ -491,6 +599,7 @@ module CloudstackClient
|
|
491
599
|
}
|
492
600
|
params['projectid'] = args[:project_id] if args[:project_id]
|
493
601
|
params['zoneid'] = args[:zone_id] if args[:zone_id]
|
602
|
+
params['isDefault'] = true if args[:isdefault]
|
494
603
|
if args[:account]
|
495
604
|
domain = list_accounts(name: args[:account])
|
496
605
|
if domain.size > 0
|
@@ -504,6 +613,18 @@ module CloudstackClient
|
|
504
613
|
json['network'] || []
|
505
614
|
end
|
506
615
|
|
616
|
+
##
|
617
|
+
# Delete network.
|
618
|
+
|
619
|
+
def delete_network(id)
|
620
|
+
params = {
|
621
|
+
'command' => 'deleteNetwork',
|
622
|
+
'id' => id,
|
623
|
+
}
|
624
|
+
p json = send_async_request(params)
|
625
|
+
json['network']
|
626
|
+
end
|
627
|
+
|
507
628
|
##
|
508
629
|
# Lists all physical networks.
|
509
630
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudstack-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -95,8 +95,10 @@ files:
|
|
95
95
|
- lib/cloudstack-cli/cli.rb
|
96
96
|
- lib/cloudstack-cli/commands/account.rb
|
97
97
|
- lib/cloudstack-cli/commands/capacity.rb
|
98
|
+
- lib/cloudstack-cli/commands/disk_offering.rb
|
98
99
|
- lib/cloudstack-cli/commands/domain.rb
|
99
100
|
- lib/cloudstack-cli/commands/ip_address.rb
|
101
|
+
- lib/cloudstack-cli/commands/iso.rb
|
100
102
|
- lib/cloudstack-cli/commands/load_balancer.rb
|
101
103
|
- lib/cloudstack-cli/commands/network.rb
|
102
104
|
- lib/cloudstack-cli/commands/offering.rb
|