cloudstack-cli 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +5 -1
- data/lib/cloudstack-cli/base.rb +3 -2
- data/lib/cloudstack-cli/commands/server.rb +12 -34
- data/lib/cloudstack-cli/commands/stack.rb +14 -7
- data/lib/cloudstack-cli/helper.rb +10 -22
- data/lib/cloudstack-cli/version.rb +1 -1
- data/lib/cloudstack-client/client.rb +4 -3
- data/lib/cloudstack-client/commands/network.rb +14 -0
- data/lib/cloudstack-client/commands/server.rb +2 -0
- data/lib/cloudstack-client/version.rb +1 -1
- data/test/stack_example.json +6 -3
- metadata +1 -1
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -55,6 +55,8 @@ An example stackfile looks like this
|
|
55
55
|
"description": "Web Application Stack",
|
56
56
|
"version": "1.0",
|
57
57
|
"zone": "DC-BIE-1",
|
58
|
+
"group": "my_web_stack",
|
59
|
+
"keypair": "mykeypair",
|
58
60
|
"servers": [
|
59
61
|
{
|
60
62
|
"name": "web-d1, web-d2",
|
@@ -67,7 +69,9 @@ An example stackfile looks like this
|
|
67
69
|
{
|
68
70
|
"name": "db-01",
|
69
71
|
"description": "PostgreSQL Master",
|
70
|
-
"
|
72
|
+
"iso": "CentOS-6.4-x86_64-swisstxt-v15",
|
73
|
+
"disk_offering": "Perf Storage",
|
74
|
+
"disk_size": "5",
|
71
75
|
"offering": "2cpu_4gb",
|
72
76
|
"networks": "server_network, storage_network"
|
73
77
|
}
|
data/lib/cloudstack-cli/base.rb
CHANGED
@@ -18,12 +18,13 @@ module CloudstackCli
|
|
18
18
|
end
|
19
19
|
|
20
20
|
no_commands do
|
21
|
-
def client
|
21
|
+
def client(opts = {})
|
22
22
|
@config ||= CloudstackClient::ConnectionHelper.load_configuration(options[:config])
|
23
23
|
@client ||= CloudstackClient::Connection.new(
|
24
24
|
@config[:url],
|
25
25
|
@config[:api_key],
|
26
|
-
@config[:secret_key]
|
26
|
+
@config[:secret_key],
|
27
|
+
opts
|
27
28
|
)
|
28
29
|
end
|
29
30
|
|
@@ -33,44 +33,22 @@ class Server < CloudstackCli::Base
|
|
33
33
|
end
|
34
34
|
|
35
35
|
desc "create NAME", "create a server"
|
36
|
-
option :template, desc: "name of the template"
|
37
|
-
option :iso, desc: "name of the iso"
|
38
|
-
option :offering, required: true
|
39
|
-
option :networks, type: :array
|
40
|
-
option :zone
|
41
|
-
option :project
|
42
|
-
option :port_rules, type: :array,
|
36
|
+
option :template, aliases: '-t', desc: "name of the template"
|
37
|
+
option :iso, desc: "name of the iso", desc: "name of the iso template"
|
38
|
+
option :offering, aliases: '-o', required: true, desc: "computing offering name"
|
39
|
+
option :networks, aliases: '-n', type: :array, desc: "network names"
|
40
|
+
option :zone, aliases: '-z', desc: "availability zone name"
|
41
|
+
option :project, aliases: '-p', desc: "project name"
|
42
|
+
option :port_rules, aliases: '-pr', type: :array,
|
43
43
|
default: [],
|
44
44
|
desc: "Port Forwarding Rules [public_ip]:port ..."
|
45
|
-
option :disk_offering
|
45
|
+
option :disk_offering, desc: "disk offering - data disk for template, root disk for iso"
|
46
46
|
option :disk_size, desc: "disk size in GB"
|
47
47
|
option :hypervisor, desc: "only used for iso deployments, default: vmware"
|
48
48
|
option :keypair, desc: "the name of the ssh keypair to use"
|
49
|
+
option :group, desc: "group name"
|
49
50
|
def create(name)
|
50
|
-
|
51
|
-
project_id = project["id"]
|
52
|
-
end
|
53
|
-
server = client.get_server(name, project_id)
|
54
|
-
unless server
|
55
|
-
say "Create server #{name}...", :yellow
|
56
|
-
server = client.create_server(
|
57
|
-
options.merge({name: name})
|
58
|
-
)
|
59
|
-
puts
|
60
|
-
say "Server #{name} has been created.", :green
|
61
|
-
client.wait_for_server_state(server["id"], "Running")
|
62
|
-
say "Server #{name} is running.", :green
|
63
|
-
else
|
64
|
-
say "Server #{name} already exists.", :yellow
|
65
|
-
# TODO: check status of server
|
66
|
-
end
|
67
|
-
|
68
|
-
if options[:port_rules] && options[:port_rules].size > 0
|
69
|
-
invoke "port_rule:create", name,
|
70
|
-
project: options[:project],
|
71
|
-
network: options[:networks].first,
|
72
|
-
rules: options[:port_rules]
|
73
|
-
end
|
51
|
+
bootstrap_server(options.merge({name: name}))
|
74
52
|
end
|
75
53
|
|
76
54
|
desc "destroy NAME [NAME2 ..]", "destroy a server"
|
@@ -85,8 +63,8 @@ class Server < CloudstackCli::Base
|
|
85
63
|
say "Server #{server_name} not found.", :red
|
86
64
|
else
|
87
65
|
ask = "Destroy #{server_name} (#{server['state']})?"
|
88
|
-
if options[:force] == true || yes?(ask)
|
89
|
-
say "
|
66
|
+
if options[:force] == true || yes?(ask, :yellow)
|
67
|
+
say "destroying #{server_name} "
|
90
68
|
client.destroy_server(server["id"])
|
91
69
|
puts
|
92
70
|
end
|
@@ -10,13 +10,19 @@ class Stack < CloudstackCli::Base
|
|
10
10
|
server["name"].split(', ').each_with_index do |name, i|
|
11
11
|
threads << Thread.new(i) {
|
12
12
|
bootstrap_server(
|
13
|
-
name,
|
14
|
-
server["
|
15
|
-
server["
|
16
|
-
server["
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
name: name,
|
14
|
+
displayname: server["decription"],
|
15
|
+
zone: server["zone"] || stack["zone"],
|
16
|
+
template: server["template"],
|
17
|
+
iso: server["iso"] ,
|
18
|
+
offering: server["offering"],
|
19
|
+
networks: server["networks"] ? server["networks"].split(', ') : nil,
|
20
|
+
port_rules: server["port_rules"] ? server["port_rules"].split(', ') : nil,
|
21
|
+
project: stack["project"],
|
22
|
+
disk_offering: server["disk_offering"],
|
23
|
+
disk_size: server["disk_size"],
|
24
|
+
group: server["group"] || stack["group"],
|
25
|
+
keypair: server["keypair"] || stack["keypair"]
|
20
26
|
)
|
21
27
|
}
|
22
28
|
end
|
@@ -37,6 +43,7 @@ class Stack < CloudstackCli::Base
|
|
37
43
|
server["name"].split(', ').each {|name| servers << name}
|
38
44
|
end
|
39
45
|
say "Destroy stack #{stack["name"]}...", :yellow
|
46
|
+
puts
|
40
47
|
invoke "server:destroy", servers, project: stack["project"], force: options[:force]
|
41
48
|
end
|
42
49
|
|
@@ -11,50 +11,38 @@ module CloudstackCli
|
|
11
11
|
number < 0 ? 0 : number
|
12
12
|
end
|
13
13
|
|
14
|
-
def bootstrap_server(
|
15
|
-
if project = client.get_project(project)
|
14
|
+
def bootstrap_server(args = {})
|
15
|
+
if args[:project] && project = client(quiet: true).get_project(args[:project])
|
16
16
|
project_id = project["id"]
|
17
17
|
project_name = project['name']
|
18
18
|
end
|
19
|
-
server = client.get_server(name, project_id)
|
19
|
+
server = client(quiet: true).get_server(args[:name], project_id)
|
20
20
|
unless server
|
21
|
-
say "Create server #{name}..."
|
22
|
-
server = client.create_server(
|
23
|
-
name: name,
|
24
|
-
offering: offering,
|
25
|
-
template: template,
|
26
|
-
zone: zone,
|
27
|
-
networks: networks,
|
28
|
-
project: project_name
|
29
|
-
)
|
30
|
-
puts
|
21
|
+
say "Create server #{args[:name]}...", :yellow
|
22
|
+
server = client.create_server(args)
|
31
23
|
say "Server #{server["name"]} has been created.", :green
|
32
24
|
client.wait_for_server_state(server["id"], "Running")
|
33
25
|
say "Server #{server["name"]} is running.", :green
|
34
26
|
else
|
35
|
-
say "Server #{name} already exists.", :yellow
|
27
|
+
say "Server #{args[:name]} already exists (#{server['state']}).", :yellow
|
36
28
|
end
|
37
29
|
|
38
|
-
if
|
39
|
-
puts
|
30
|
+
if args[:port_rules] && args[:port_rules].size > 0
|
40
31
|
frontendip = nil
|
41
|
-
|
32
|
+
args[:port_rules].each do |pf_rule|
|
42
33
|
ip = pf_rule.split(":")[0]
|
43
34
|
if ip != ''
|
44
35
|
ip_addr = client.get_public_ip_address(ip)
|
45
36
|
else
|
46
37
|
ip_addr = frontendip ||= client.associate_ip_address(
|
47
|
-
|
38
|
+
server["nic"].first["networkid"]
|
48
39
|
)
|
49
40
|
end
|
50
41
|
port = pf_rule.split(":")[1]
|
51
|
-
|
52
|
-
say "Create port forwarding rule #{ip}:#{port} ", :yellow
|
42
|
+
say "Create port forwarding rule #{ip_addr['ipaddress']}:#{port} for server #{args[:name]}.", :yellow
|
53
43
|
client.create_port_forwarding_rule(ip_addr["id"], port, 'TCP', port, server["id"])
|
54
|
-
puts
|
55
44
|
end
|
56
45
|
end
|
57
|
-
puts
|
58
46
|
end
|
59
47
|
|
60
48
|
def bootstrap_server_interactive
|
@@ -20,11 +20,12 @@ module CloudstackClient
|
|
20
20
|
include Object.const_get("CloudstackClient").const_get(module_name)
|
21
21
|
end
|
22
22
|
|
23
|
-
def initialize(api_url, api_key, secret_key)
|
23
|
+
def initialize(api_url, api_key, secret_key, opts = {})
|
24
24
|
@api_url = api_url
|
25
25
|
@api_key = api_key
|
26
26
|
@secret_key = secret_key
|
27
27
|
@use_ssl = api_url.start_with? "https"
|
28
|
+
@verbose = !opts[:quiet]
|
28
29
|
end
|
29
30
|
|
30
31
|
##
|
@@ -91,12 +92,12 @@ module CloudstackClient
|
|
91
92
|
json = send_request(params)
|
92
93
|
status = json['jobstatus']
|
93
94
|
|
94
|
-
print "."
|
95
|
+
print "." if @verbose
|
95
96
|
|
96
97
|
if status == 1 then
|
97
98
|
return json['jobresult']
|
98
99
|
elsif status == 2 then
|
99
|
-
|
100
|
+
puts
|
100
101
|
puts "Request failed (#{json['jobresultcode']}): #{json['jobresult']}"
|
101
102
|
exit 1
|
102
103
|
end
|
@@ -2,6 +2,20 @@ module CloudstackClient
|
|
2
2
|
|
3
3
|
module Network
|
4
4
|
|
5
|
+
##
|
6
|
+
# Finds the network with the specified name.
|
7
|
+
|
8
|
+
def networkid_to_name(id, project_id=nil)
|
9
|
+
params = {
|
10
|
+
'command' => 'listNetworks',
|
11
|
+
'id' => id
|
12
|
+
}
|
13
|
+
params['projectid'] = project_id if project_id
|
14
|
+
json = send_request(params)
|
15
|
+
|
16
|
+
json['network'] ? json['network'].first['name'] : nil
|
17
|
+
end
|
18
|
+
|
5
19
|
##
|
6
20
|
# Finds the network with the specified name.
|
7
21
|
|
@@ -206,6 +206,8 @@ module CloudstackClient
|
|
206
206
|
params['hypervisor'] = (args[:hypervisor] || 'vmware') if iso
|
207
207
|
params['keypair'] = args[:keypair] if args[:keypair]
|
208
208
|
params['size'] = args[:disk_size] if args[:disk_size]
|
209
|
+
params['group'] = args[:group] if args[:group]
|
210
|
+
params['displayname'] = args[:displayname] if args[:displayname]
|
209
211
|
|
210
212
|
json = send_async_request(params)
|
211
213
|
json['virtualmachine']
|
data/test/stack_example.json
CHANGED
@@ -4,9 +4,10 @@
|
|
4
4
|
"version": "1.0",
|
5
5
|
"zone": "BIEL_CU01",
|
6
6
|
"project": "Playground",
|
7
|
+
"group": "my_web_stack",
|
7
8
|
"servers": [
|
8
9
|
{
|
9
|
-
"name": "web-
|
10
|
+
"name": "web-001, web-002",
|
10
11
|
"description": "Web nodes",
|
11
12
|
"template": "CentOS-6.4-x64-v1.2",
|
12
13
|
"offering": "1cpu_1gb",
|
@@ -14,9 +15,11 @@
|
|
14
15
|
"port_rules": ":80, :443"
|
15
16
|
},
|
16
17
|
{
|
17
|
-
"name": "db-
|
18
|
+
"name": "db-001",
|
18
19
|
"description": "PostgreSQL Master",
|
19
|
-
"
|
20
|
+
"iso": "CentOS-6.4-x86_64-swisstxt-v15",
|
21
|
+
"disk_offering": "Perf Storage",
|
22
|
+
"disk_size": "5",
|
20
23
|
"offering": "2cpu_4gb",
|
21
24
|
"networks": "M_PLAY"
|
22
25
|
}
|