cloudstack-cli 1.5.9 → 1.5.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3825bffdc7d610ccd33d5ea01d48804ad3caeaf
4
- data.tar.gz: 23e2821aaf38b61cbc98091a460f91e42d75ebb9
3
+ metadata.gz: 9db726fce7f2ff20082296b4e424db14497a04ab
4
+ data.tar.gz: 6d6177310113255ec6ff7b34fc56dece69ff0c66
5
5
  SHA512:
6
- metadata.gz: 2eca64f2d69c815e19fbf7696087efc5a9a0f3f743acec88c5ea26c8b6a155510f1471b977bac4d6113dd351148abf393402698dec05ab4f938997be8c30a5cb
7
- data.tar.gz: 7c43cc6ce81a7df4c7bffc94a967786fc76ff50da12951ec2eafda751e9da1541a83263c4c69870f525338e9687715b4a0b7c0f1244df99a540d680fab880ad2
6
+ metadata.gz: 2e6177a5cd286a74c2374ef3171d8c886e36e7abb94ded0e482bf1d4e86613ba56b103c00963fcfe30e6aad1bdfa49c2d659fd1bf5721a8cf81f94c0a8c89714
7
+ data.tar.gz: a09c1c2ceed2856f46f5cececfd61248bb87fd87d7b5f62d0d8fe49bedbcde4ab94b98fd6cf7b87e308cdf5a6cbeb5222a5890a215bbf1956ad36d958cda0b21
data/Gemfile.lock CHANGED
@@ -6,7 +6,7 @@ PATH
6
6
  PATH
7
7
  remote: .
8
8
  specs:
9
- cloudstack-cli (1.5.9)
9
+ cloudstack-cli (1.5.10)
10
10
  cloudstack_client (~> 1.4.3)
11
11
  thor (~> 0.19)
12
12
 
@@ -25,4 +25,4 @@ DEPENDENCIES
25
25
  rake (~> 11.3)
26
26
 
27
27
  BUNDLED WITH
28
- 1.13.2
28
+ 1.13.6
@@ -10,10 +10,13 @@ class PortRule < CloudstackCli::Base
10
10
  option :keyword, desc: "list by keyword"
11
11
  def create(server_name)
12
12
  resolve_project
13
- unless server = client.list_virtual_machines(name: server_name, project_id: options[:project_id]).first
13
+ unless server = client.list_virtual_machines(
14
+ name: server_name, project_id: options[:project_id], listall: true
15
+ ).find {|vm| vm["name"] == server_name }
14
16
  error "Server #{server_name} not found."
15
17
  exit 1
16
18
  end
19
+ ip_addr = nil
17
20
  options[:rules].each do |pf_rule|
18
21
  ip = pf_rule.split(":")[0]
19
22
  unless ip == ''
@@ -23,16 +26,13 @@ class PortRule < CloudstackCli::Base
23
26
  end
24
27
  else
25
28
  say "Assign a new IP address ", :yellow
26
- say(" OK", :green) if ip_addr = client.associate_ip_address(
27
- networkid: client.list_networks(
28
- project_id: options[:project_id]
29
- ).find {|n| n['name'] == options[:network]}['id'],
30
- project_id: options[:project_id]
31
- )
29
+ net_id = client.list_networks(project_id: options[:project_id]).find {|n| n['name'] == options[:network]}['id']
30
+ say(" OK", :green) if ip_addr = client.associate_ip_address(networkid: net_id)["ipaddress"]
32
31
  end
33
32
  port = pf_rule.split(":")[1]
34
33
  say "Create port forwarding rule #{ip_addr["ipaddress"]}:#{port} for server #{server_name} ", :yellow
35
- say(" OK.", :green) if client.create_port_forwarding_rule(
34
+
35
+ say(" OK", :green) if client.create_port_forwarding_rule(
36
36
  ipaddress_id: ip_addr["id"],
37
37
  public_port: port,
38
38
  private_port: port,
@@ -13,7 +13,7 @@ class Router < CloudstackCli::Base
13
13
  desc: "command to execute for each router",
14
14
  enum: %w(START STOP REBOOT STOP_START)
15
15
  option :concurrency, type: :numeric, default: 10, aliases: '-C',
16
- desc: "number of concurrent command to execute"
16
+ desc: "number of concurrent commands to execute"
17
17
  option :format, default: "table",
18
18
  enum: %w(table json yaml)
19
19
  option :showid, type: :boolean, desc: "display the router ID"
@@ -43,7 +43,7 @@ class Router < CloudstackCli::Base
43
43
  desc: "command to execute for each router",
44
44
  enum: %w(START STOP REBOOT)
45
45
  option :concurrency, type: :numeric, default: 10, aliases: '-C',
46
- desc: "number of concurrent command to execute"
46
+ desc: "number of concurrent commands to execute"
47
47
  option :format, default: "table",
48
48
  enum: %w(table json yaml)
49
49
  def list_from_file(file)
@@ -219,7 +219,7 @@ class Router < CloudstackCli::Base
219
219
  jobs = routers.map do |router|
220
220
  {
221
221
  job_id: nil,
222
- object_id: router["id"],
222
+ args: { id: router["id"] },
223
223
  name: "#{cmd.capitalize} router #{router['name']}",
224
224
  status: -1
225
225
  }
@@ -6,25 +6,28 @@ class Stack < CloudstackCli::Base
6
6
  option :skip_forwarding_rules, default: false,
7
7
  type: :boolean, aliases: '-s',
8
8
  desc: "Skip creation of port forwarding rules."
9
+ option :concurrency, type: :numeric, default: 10, aliases: '-C',
10
+ desc: "number of concurrent commands to execute"
9
11
  def create(stackfile)
10
12
  stack = parse_file(stackfile)
11
13
  project_id = find_project_by_name(stack["project"])
14
+
12
15
  say "Create stack #{stack["name"]}...", :green
13
16
  jobs = []
14
17
  stack["servers"].each do |instance|
15
18
  string_to_array(instance["name"]).each do |name|
16
19
  if !options[:limit] || options[:limit].include?(name)
17
- server = client.list_virtual_machines(name: name, project_id: project_id).first
18
- if server
20
+ if server = client.list_virtual_machines(
21
+ name: name, project_id: project_id, listall: true
22
+ ).find {|vm| vm["name"] == name }
19
23
  say "VM #{name} (#{server["state"]}) already exists.", :yellow
20
24
  jobs << {
21
25
  id: 0,
22
26
  name: "Create VM #{name}",
23
- status: 1
27
+ status: 3
24
28
  }
25
29
  else
26
30
  options.merge!({
27
- name: name,
28
31
  displayname: instance["decription"],
29
32
  zone: instance["zone"] || stack["zone"],
30
33
  project: stack["project"],
@@ -39,36 +42,55 @@ class Stack < CloudstackCli::Base
39
42
  keypair: instance["keypair"] || stack["keypair"],
40
43
  ip_address: instance["ip_address"]
41
44
  })
45
+ vm_options_to_params
42
46
  jobs << {
43
- id: client.deploy_virtual_machine(
44
- vm_options_to_params,
45
- {sync: true}
46
- )['jobid'],
47
- name: "Create VM #{name}"
47
+ job_id: nil,
48
+ args: options.merge(name: name),
49
+ name: "Create VM #{name}",
50
+ status: -1
48
51
  }
49
52
  end
50
53
  end
51
54
  end
52
55
  end
53
- watch_jobs(jobs)
54
56
 
55
- unless options[:skip_forwarding_rules]
57
+ if jobs.count{|job| job[:status] < 1 } > 0
58
+ run_background_jobs(jobs, "deploy_virtual_machine")
59
+ end
60
+
61
+ # count jobs with status 1 => Completed
62
+ successful_jobs = jobs.count {|job| job[:status] == 1 }
63
+ unless successful_jobs == 0 || options[:skip_forwarding_rules]
56
64
  say "Check for port forwarding rules...", :green
57
- jobs = []
58
- stack["servers"].each do |instance|
59
- string_to_array(instance["name"]).each do |name|
60
- if (!options[:limit] || options[:limit].include?(name)) && port_rules = string_to_array(instance["port_rules"])
61
- server = client.list_virtual_machines(name: name, project_id: project_id).first
62
- create_port_rules(server, port_rules, false).each_with_index do |job_id, index|
63
- job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{name}"
64
- jobs << {id: job_id, name: job_name}
65
- end
65
+ pjobs = []
66
+ jobs.select{|job| job[:status] == 1}.each do |job|
67
+ vm = job[:result]["virtualmachine"]
68
+ vm_def = find_vm_in_stack(vm["name"], stack)
69
+ if port_rules = string_to_array(vm_def["port_rules"])
70
+ create_port_rules(vm, port_rules, false).each_with_index do |job_id, index|
71
+ job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{vm["name"]}"
72
+ pjobs << {id: job_id, name: job_name}
66
73
  end
67
74
  end
68
75
  end
69
- watch_jobs(jobs)
76
+ watch_jobs(pjobs)
77
+ pjobs.each do |job|
78
+ if job[:result]
79
+ result = job[:result]["portforwardingrule"]
80
+ puts "Created port forwarding rule #{result['ipaddress']}:#{result['publicport']} => #{result['privateport']} for VM #{result['virtualmachinename']}"
81
+ end
82
+ end
70
83
  end
71
84
  say "Finished.", :green
85
+
86
+ if successful_jobs > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow)
87
+ pw_table = jobs.select {|job| job[:status] == 1 && job[:result] }.map do |job|
88
+ if result = job[:result]["virtualmachine"]
89
+ ["#{result["name"]}:", result["password"] || "n/a"]
90
+ end
91
+ end
92
+ print_table(pw_table) if pw_table.size > 0
93
+ end
72
94
  end
73
95
 
74
96
  desc "destroy STACKFILE", "destroy a stack of VMs"
@@ -101,10 +123,13 @@ class Stack < CloudstackCli::Base
101
123
  exit
102
124
  end
103
125
 
104
- if options[:force] || yes?("Destroy the following VM #{servers.join(', ')}? [y/N]:", :yellow)
126
+ if options[:force] ||
127
+ yes?("Destroy #{'and expunge ' if options[:expunge]}the following VM(s)? #{servers.join(', ')} [y/N]:", :yellow)
105
128
  jobs = []
106
129
  servers.each do |name|
107
- if server = client.list_virtual_machines(name: name, project_id: project_id).first
130
+ if server = client.list_virtual_machines(
131
+ name: name, project_id: project_id, listall: true
132
+ ).find {|vm| vm["name"] == name }
108
133
  jobs << {
109
134
  id: client.destroy_virtual_machine(
110
135
  { id: server['id'], expunge: options[:expunge] },
@@ -142,6 +167,14 @@ class Stack < CloudstackCli::Base
142
167
  string ? string.gsub(', ', ',').split(',') : nil
143
168
  end
144
169
 
170
+ def find_vm_in_stack(name, stack)
171
+ stack["servers"].each do |server|
172
+ if string_to_array(server["name"]).find{|n| n == name }
173
+ return server
174
+ end
175
+ end
176
+ end
177
+
145
178
  end # no_commands
146
179
 
147
180
  end
@@ -15,7 +15,7 @@ class VirtualMachine < CloudstackCli::Base
15
15
  desc: "command to execute for the given virtual machines",
16
16
  enum: %w(START STOP REBOOT)
17
17
  option :concurrency, type: :numeric, default: 10, aliases: '-C',
18
- desc: "number of concurrent command to execute"
18
+ desc: "number of concurrent commands to execute"
19
19
  option :format, default: "table",
20
20
  enum: %w(table json yaml)
21
21
  def list
@@ -78,7 +78,7 @@ class VirtualMachine < CloudstackCli::Base
78
78
  option :zone, aliases: '-z', required: true, desc: "availability zone name"
79
79
  option :networks, aliases: '-n', type: :array, desc: "network names"
80
80
  option :project, aliases: '-p', desc: "project name"
81
- option :port_rules, aliases: '-pr', type: :array,
81
+ option :port_rules, type: :array,
82
82
  default: [],
83
83
  desc: "Port Forwarding Rules [public_ip]:port ..."
84
84
  option :disk_offering, desc: "disk offering (data disk for template, root disk for iso)"
@@ -91,6 +91,8 @@ class VirtualMachine < CloudstackCli::Base
91
91
  option :ip_network_list, desc: "ip_network_list (net1:ip net2:ip...)", type: :array
92
92
  option :user_data,
93
93
  desc: "optional binary data that can be sent to the virtual machine upon a successful deployment."
94
+ option :concurrency, type: :numeric, default: 10, aliases: '-C',
95
+ desc: "number of concurrent commands to execute"
94
96
  def create(*names)
95
97
  if names.size == 0
96
98
  say "Please provide at least one virtual machine name.", :yellow
@@ -106,39 +108,45 @@ class VirtualMachine < CloudstackCli::Base
106
108
  jobs = names.map do |name|
107
109
  if virtual_machine = find_vm_by_name(name)
108
110
  say "virtual machine #{name} (#{virtual_machine["state"]}) already exists.", :yellow
109
- job = {id: 0, name: "Create virtual machine #{name}", status: 3}
111
+ job = {name: "Create virtual machine #{name}", status: 3}
110
112
  else
111
113
  job = {
112
- id: client.deploy_virtual_machine(options.merge(name: name), {sync: true})['jobid'],
113
- name: "Create virtual machine #{name}"
114
+ args: options.merge(name: name),
115
+ name: "Create VM #{name}",
116
+ status: -1
114
117
  }
115
118
  end
116
119
  job
117
120
  end
118
- watch_jobs(jobs)
121
+
122
+ if jobs.count{|job| job[:status] < 1 } > 0
123
+ run_background_jobs(jobs, "deploy_virtual_machine")
124
+ end
125
+
119
126
  successful_jobs = jobs.count {|job| job[:status] == 1 }
120
127
  if options[:port_rules].size > 0 && successful_jobs > 0
121
128
  say "Create port forwarding rules...", :green
122
129
  pjobs = []
123
- names.each do |name|
124
- vm = client.list_virtual_machines(name: name, project_id: options[:project_id]).first
130
+ jobs.select{|job| job[:status] == 1}.each do |job|
131
+ vm = job[:result]["virtualmachine"]
125
132
  create_port_rules(vm, options[:port_rules], false).each_with_index do |job_id, index|
126
133
  pjobs << {
127
134
  id: job_id,
128
- name: "Create port forwarding ##{index + 1} rules for VM #{vm['name']}"
135
+ name: "Create port forwarding rule #{options[:port_rules][index]} for VM #{vm['name']}"
129
136
  }
130
137
  end
131
138
  end
132
139
  watch_jobs(pjobs)
133
140
  end
134
141
  say "Finished.", :green
142
+
135
143
  if successful_jobs > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow)
136
- table = []
137
- jobs.each do |job|
138
- data = client.query_async_job_result(jobid: job[:id])["jobresult"]["virtualmachine"] rescue nil
139
- table << ["#{data["name"]}:", data["password"]] if data
144
+ pw_table = jobs.select {|job| job[:status] == 1 && job[:result] }.map do |job|
145
+ if result = job[:result]["virtualmachine"]
146
+ ["#{result["name"]}:", result["password"] || "n/a"]
147
+ end
140
148
  end
141
- print_table table
149
+ print_table(pw_table) if pw_table.size > 0
142
150
  end
143
151
  end
144
152
 
@@ -319,7 +327,7 @@ class VirtualMachine < CloudstackCli::Base
319
327
  jobs = virtual_machines.map do |vm|
320
328
  {
321
329
  job_id: nil,
322
- object_id: vm["id"],
330
+ args: { id: vm["id"] },
323
331
  name: "#{command.capitalize} virtual machine #{vm['name']}",
324
332
  status: -1
325
333
  }
@@ -24,7 +24,7 @@ module CloudstackCli
24
24
  call = 0
25
25
  opts = {t_start: Time.now}
26
26
  jobs = update_job_status(jobs)
27
- while jobs.select{|job| job[:status].to_i < 1 }.size > 0 do
27
+ while jobs.count{|job| job[:status].to_i < 1 } > 0 do
28
28
  if call.modulo(40) == 0
29
29
  t = Thread.new { jobs = update_job_status(jobs) }
30
30
  while t.alive?
@@ -50,7 +50,12 @@ module CloudstackCli
50
50
  jobs.each do |job|
51
51
  job[:status] = 0 unless job[:status]
52
52
  if job[:status] == 0
53
- job[:status] = client.query_async_job_result(job_id: job[:id])['jobstatus']
53
+ result = client.query_async_job_result(job_id: job[:id])
54
+ job[:status] = result["jobstatus"]
55
+ # add result information for terminated jobs
56
+ if job[:status].between?(1, 2)
57
+ job[:result] = result["jobresult"]
58
+ end
54
59
  end
55
60
  end
56
61
  jobs
@@ -62,7 +67,7 @@ module CloudstackCli
62
67
  call = 0
63
68
  opts = {t_start: Time.now}
64
69
 
65
- while jobs.select{|job| job[:status] < 1 }.size > 0 do
70
+ while jobs.count{|job| job[:status] < 1 } > 0 do
66
71
  if call.modulo(40) == 0
67
72
  t = Thread.new { jobs = update_jobs(jobs, command) }
68
73
  while t.alive?
@@ -90,19 +95,23 @@ module CloudstackCli
90
95
  # update running job status
91
96
  threads = jobs.select{|job| job[:status] == 0 }.map do |job|
92
97
  Thread.new do
93
- job[:status] = client.query_async_job_result(job_id: job[:job_id])['jobstatus']
98
+ result = client.query_async_job_result(job_id: job[:job_id])
99
+ job[:status] = result['jobstatus']
100
+ if job[:status].between?(1, 2)
101
+ job[:result] = result["jobresult"]
102
+ end
94
103
  end
95
104
  end
96
105
  threads.each(&:join)
97
106
 
98
107
  # launch new jobs if required and possible
99
- launch_capacity = options[:concurrency] - jobs.select{|job| job[:status] == 0 }.count
108
+ launch_capacity = (options[:concurrency] ||= 10) - jobs.count{|job| job[:status] == 0 }
100
109
  threads = []
101
110
  jobs.select{|job| job[:status] == -1 }.each do |job|
102
111
  if launch_capacity > 0
103
112
  threads << Thread.new do
104
113
  job[:job_id] = client.send(
105
- command, { id: job[:object_id] }, { sync: true }
114
+ command, job[:args], { sync: true }
106
115
  )['jobid']
107
116
  job[:status] = 0
108
117
  end
@@ -120,7 +129,7 @@ module CloudstackCli
120
129
  puts job[:status] == 0 ? spinner.first : ""
121
130
  end
122
131
  t_elapsed = opts[:t_start] ? (Time.now - opts[:t_start]).round(1) : 0
123
- completed = jobs.select{|j| j[:status] == 1}.size
132
+ completed = jobs.count{|j| j[:status] == 1 }
124
133
  say "Completed: #{completed} of #{jobs.size} (#{t_elapsed}s)", :magenta
125
134
  sleep opts[:sleeptime] || 0.1
126
135
  spinner.push spinner.shift
@@ -18,6 +18,7 @@ module CloudstackCli
18
18
  else
19
19
  resolve_networks
20
20
  end
21
+ options
21
22
  end
22
23
 
23
24
  def resolve_zone
@@ -1,3 +1,3 @@
1
1
  module CloudstackCli
2
- VERSION = "1.5.9"
2
+ VERSION = "1.5.10"
3
3
  end
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: "web_stack_b"
3
+ description: "Web Application Stack"
4
+ version: "1.0"
5
+ zone: "ZUERICH_EQ"
6
+ project: "Playground"
7
+ group: "my_web_stack"
8
+ servers:
9
+ - name: "webx-01, webx-02"
10
+ description: "Web nodes"
11
+ template: "CentOS-7-x86_64"
12
+ offering: "1cpu_1gb"
13
+ networks: "M_PLAY"
14
+ port_rules: ":80, :443"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudstack-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.9
4
+ version: 1.5.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nik Wolfgramm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-22 00:00:00.000000000 Z
11
+ date: 2016-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -111,6 +111,7 @@ files:
111
111
  - test/ma-test.yml
112
112
  - test/stack_example.json
113
113
  - test/stack_example.yml
114
+ - test/stack_example_b.yml
114
115
  homepage: http://github.com/niwo/cloudstack-cli
115
116
  licenses:
116
117
  - MIT
@@ -141,3 +142,4 @@ test_files:
141
142
  - test/ma-test.yml
142
143
  - test/stack_example.json
143
144
  - test/stack_example.yml
145
+ - test/stack_example_b.yml