cloudstack-cli 1.5.9 → 1.5.10
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/lib/cloudstack-cli/commands/port_rule.rb +8 -8
- data/lib/cloudstack-cli/commands/router.rb +3 -3
- data/lib/cloudstack-cli/commands/stack.rb +56 -23
- data/lib/cloudstack-cli/commands/virtual_machine.rb +23 -15
- data/lib/cloudstack-cli/helper.rb +16 -7
- data/lib/cloudstack-cli/option_resolver.rb +1 -0
- data/lib/cloudstack-cli/version.rb +1 -1
- data/test/stack_example_b.yml +14 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9db726fce7f2ff20082296b4e424db14497a04ab
|
4
|
+
data.tar.gz: 6d6177310113255ec6ff7b34fc56dece69ff0c66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e6177a5cd286a74c2374ef3171d8c886e36e7abb94ded0e482bf1d4e86613ba56b103c00963fcfe30e6aad1bdfa49c2d659fd1bf5721a8cf81f94c0a8c89714
|
7
|
+
data.tar.gz: a09c1c2ceed2856f46f5cececfd61248bb87fd87d7b5f62d0d8fe49bedbcde4ab94b98fd6cf7b87e308cdf5a6cbeb5222a5890a215bbf1956ad36d958cda0b21
|
data/Gemfile.lock
CHANGED
@@ -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(
|
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
|
-
|
27
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
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(
|
18
|
-
|
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:
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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(
|
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] ||
|
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(
|
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
|
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,
|
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 = {
|
111
|
+
job = {name: "Create virtual machine #{name}", status: 3}
|
110
112
|
else
|
111
113
|
job = {
|
112
|
-
|
113
|
-
name: "Create
|
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
|
-
|
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
|
-
|
124
|
-
vm =
|
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
|
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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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
|
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
|
-
|
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.
|
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
|
-
|
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.
|
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
|
-
|
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.
|
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,
|
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.
|
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
|
@@ -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.
|
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-
|
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
|