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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cloudstack-cli (0.1.4)
4
+ cloudstack-cli (0.1.5)
5
5
  net-ssh (~> 2.6.7)
6
6
  thor (~> 0.18.1)
7
7
 
@@ -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
@@ -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 template"
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 by type [compute|network|storage]'
3
+ desc 'list', 'list compute offerings'
4
4
  option :domain
5
- def list(type='compute')
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 :interactive, type: :boolean
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.", :green
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
- templates = client.list_templates(type: type, project_id: project ? project['id'] : nil)
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.", :green
31
+ say "Server #{name} already exists.", :yellow
32
32
  end
33
33
 
34
34
  if pf_rules && pf_rules.size > 0
@@ -1,3 +1,3 @@
1
1
  module CloudstackCli
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -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, network_names=[], project_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
- puts "Error: Template '#{template_name}' is invalid"
163
- exit 1
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
- default = n
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.5
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