cloudstack-cli 0.1.5 → 0.1.6
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/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
|