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 +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
|