cloudstack-cli 0.0.1
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.
- data/.gitignore +5 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +30 -0
- data/LICENSE.txt +7 -0
- data/README.md +40 -0
- data/bin/cs +7 -0
- data/cloudstack-cli.gemspec +25 -0
- data/config/cloudstack.example.yml +3 -0
- data/lib/cloudstack-cli/cli.rb +59 -0
- data/lib/cloudstack-cli/commands/account.rb +16 -0
- data/lib/cloudstack-cli/commands/domain.rb +16 -0
- data/lib/cloudstack-cli/commands/load_balancer.rb +58 -0
- data/lib/cloudstack-cli/commands/network.rb +74 -0
- data/lib/cloudstack-cli/commands/offering.rb +80 -0
- data/lib/cloudstack-cli/commands/project.rb +15 -0
- data/lib/cloudstack-cli/commands/publicip.rb +9 -0
- data/lib/cloudstack-cli/commands/router.rb +94 -0
- data/lib/cloudstack-cli/commands/server.rb +65 -0
- data/lib/cloudstack-cli/commands/stack.rb +16 -0
- data/lib/cloudstack-cli/commands/template.rb +25 -0
- data/lib/cloudstack-cli/commands/volume.rb +20 -0
- data/lib/cloudstack-cli/commands/zone.rb +16 -0
- data/lib/cloudstack-cli/helper.rb +236 -0
- data/lib/cloudstack-cli/version.rb +3 -0
- data/lib/cloudstack-client/client.rb +871 -0
- data/lib/cloudstack-client/helper.rb +12 -0
- data/lib/cloudstack-client/ssh_command.rb +15 -0
- data/lib/cloudstack_cli.rb +16 -0
- data/lib/cloudstack_client.rb +5 -0
- metadata +171 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
class Project < Thor
|
2
|
+
|
3
|
+
desc "list", "list projects"
|
4
|
+
def list
|
5
|
+
cs_cli = CloudstackCli::Helper.new
|
6
|
+
projects = cs_cli.projects
|
7
|
+
if projects.size < 1
|
8
|
+
puts "No projects found"
|
9
|
+
else
|
10
|
+
projects.each do |project|
|
11
|
+
puts "#{project['name']} - #{project['displaytext']} - #{project['domain']}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class Router < Thor
|
2
|
+
include CommandLineReporter
|
3
|
+
|
4
|
+
desc "list", "list virtual routers"
|
5
|
+
option :project
|
6
|
+
option :account
|
7
|
+
option :status, desc: "Running or Stopped"
|
8
|
+
option :redundant_state, desc: "MASTER, BACKUP or UNKNOWN"
|
9
|
+
option :listall, type: :boolean
|
10
|
+
option :text, type: :boolean, desc: "text output (only the instance name)"
|
11
|
+
def list
|
12
|
+
cs_cli = CloudstackCli::Helper.new
|
13
|
+
if options[:project]
|
14
|
+
project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
|
15
|
+
raise "Project '#{options[:project]}' not found" unless project
|
16
|
+
projectid = project['id']
|
17
|
+
end
|
18
|
+
|
19
|
+
routers = cs_cli.list_routers(
|
20
|
+
{
|
21
|
+
account: options[:account],
|
22
|
+
projectid: projectid,
|
23
|
+
status: options[:status],
|
24
|
+
},
|
25
|
+
options[:redundant_state]
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
if options[:listall]
|
30
|
+
projects = cs_cli.projects
|
31
|
+
projects.each do |project|
|
32
|
+
routers = routers + cs_cli.list_routers(
|
33
|
+
{
|
34
|
+
account: options[:account],
|
35
|
+
projectid: project['id'],
|
36
|
+
status: options[:status]
|
37
|
+
},
|
38
|
+
options[:redundant_state]
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if options[:text]
|
44
|
+
puts routers.map {|r| r['name']}.join(" ")
|
45
|
+
else
|
46
|
+
puts "Total number of routers: #{routers.size}"
|
47
|
+
table(border: true) do
|
48
|
+
row do
|
49
|
+
column 'ID', width: 40
|
50
|
+
column 'Name'
|
51
|
+
column 'Zone'
|
52
|
+
column 'Account', width: 14 unless options[:project]
|
53
|
+
column 'Project', width: 14 if options[:listall] || options[:project]
|
54
|
+
column 'Redundant State'
|
55
|
+
column 'Linklocal IP', width: 15
|
56
|
+
column 'Status'
|
57
|
+
end
|
58
|
+
routers.each do |router|
|
59
|
+
row do
|
60
|
+
column router["id"]
|
61
|
+
column router["name"]
|
62
|
+
column router["zonename"]
|
63
|
+
column router["account"] unless options[:project]
|
64
|
+
column router["project"] if options[:listall] || options[:project]
|
65
|
+
column router["redundantstate"]
|
66
|
+
column router["linklocalip"]
|
67
|
+
column router["state"]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "stop NAME", "stop virtual router"
|
76
|
+
option :project
|
77
|
+
|
78
|
+
def stopall
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "start NAME", "start virtual router"
|
83
|
+
option :project
|
84
|
+
def start
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
desc "destroy ID", "destroy virtual router"
|
89
|
+
def destroy(id)
|
90
|
+
cs_cli = CloudstackCli::Helper.new
|
91
|
+
puts "OK" if cs_cli.destroy_router(name)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class Server < Thor
|
2
|
+
|
3
|
+
desc "list", "list servers"
|
4
|
+
option :listall, :type => :boolean
|
5
|
+
option :text, :type => :boolean
|
6
|
+
option :project
|
7
|
+
option :account
|
8
|
+
def list
|
9
|
+
cs_cli = CloudstackCli::Helper.new
|
10
|
+
if options[:project]
|
11
|
+
project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
|
12
|
+
exit_now! "Project '#{options[:project]}' not found" unless project
|
13
|
+
options[:project_id] = project['id']
|
14
|
+
options[:account] = nil
|
15
|
+
end
|
16
|
+
servers = cs_cli.virtual_machines(options)
|
17
|
+
if servers.size < 1
|
18
|
+
puts "No servers found"
|
19
|
+
else
|
20
|
+
if options[:text]
|
21
|
+
servers.each do |server|
|
22
|
+
puts "#{server['name']} - #{server['state']} - #{server['domain']}"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
cs_cli.virtual_machines_table(servers)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "create NAME", "create a server"
|
31
|
+
option :zone, :required => true
|
32
|
+
option :template, :required => true
|
33
|
+
option :offering, :required => true
|
34
|
+
option :networks, :type => :array, :required => true
|
35
|
+
option :project
|
36
|
+
option :port_forwarding, :type => :array, :aliases => :pf, :default => [], :description => "public_ip:port"
|
37
|
+
option :interactive, :type => :boolean
|
38
|
+
def create(name)
|
39
|
+
CloudstackCli::Cli.new.bootstrap_server(
|
40
|
+
name,
|
41
|
+
options[:zone],
|
42
|
+
options[:template],
|
43
|
+
options[:offering],
|
44
|
+
options[:networks],
|
45
|
+
options[:port_forwarding],
|
46
|
+
options[:project]
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "stop NAME", "stop a server"
|
51
|
+
def stop(name)
|
52
|
+
CloudstackCli::Cli.new.stop_server(name)
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "start NAME", "start a server"
|
56
|
+
def start(name)
|
57
|
+
CloudstackCli::Cli.new.start_server(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "reboot NAME", "reboot a server"
|
61
|
+
def restart(name)
|
62
|
+
CloudstackCli::Cli.new.reboot_server(name)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Stack < Thor
|
2
|
+
|
3
|
+
desc "create STACKFILE", "create a stack of servers"
|
4
|
+
def create(stackfile)
|
5
|
+
CloudstackCli::Cli.new.bootstrap_server(
|
6
|
+
name,
|
7
|
+
options[:zone],
|
8
|
+
options[:template],
|
9
|
+
options[:offering],
|
10
|
+
options[:networks],
|
11
|
+
options[:port_forwarding],
|
12
|
+
options[:project]
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Template < Thor
|
2
|
+
|
3
|
+
desc 'list', 'list templates by type [featured|self|self-executable|executable|community]'
|
4
|
+
option :project
|
5
|
+
def list(type='featured')
|
6
|
+
cs_cli = CloudstackCli::Helper.new
|
7
|
+
|
8
|
+
if options[:project]
|
9
|
+
project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
|
10
|
+
exit_now! "Project '#{options[:project]}' not found" unless project
|
11
|
+
end
|
12
|
+
|
13
|
+
exit_now! "unsupported template type '#{type}'" unless
|
14
|
+
%w(featured self self-executable executable community).include? type
|
15
|
+
templates = cs_cli.templates(type, project ? project['id'] : nil)
|
16
|
+
if templates.size < 1
|
17
|
+
puts "No templates found"
|
18
|
+
else
|
19
|
+
templates.each do |template|
|
20
|
+
puts template['name']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Volume < Thor
|
2
|
+
desc "list", "list networks"
|
3
|
+
option :project
|
4
|
+
def list
|
5
|
+
cs_cli = CloudstackCli::Helper.new
|
6
|
+
if options[:project]
|
7
|
+
project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
|
8
|
+
raise "Project '#{options[:project]}' not found" unless project
|
9
|
+
end
|
10
|
+
|
11
|
+
networks = cs_cli.networks(project ? project['id'] : nil)
|
12
|
+
if networks.size < 1
|
13
|
+
puts "No networks found"
|
14
|
+
else
|
15
|
+
networks.each do |network|
|
16
|
+
puts "#{network['name']} - #{network['displaytext']} #{' - Default' if network['isdefault']}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Zone < Thor
|
2
|
+
|
3
|
+
desc "list", "list zones"
|
4
|
+
def list
|
5
|
+
cs_cli = CloudstackCli::Helper.new
|
6
|
+
zones = cs_cli.zones
|
7
|
+
if zones.size < 1
|
8
|
+
puts "No projects found"
|
9
|
+
else
|
10
|
+
zones.each do |zone|
|
11
|
+
puts "#{zone['name']} - #{zone['description']}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
module CloudstackCli
|
2
|
+
class Helper
|
3
|
+
include CommandLineReporter
|
4
|
+
|
5
|
+
attr_reader :cs
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@cs = CloudstackClient::Connection.new(
|
9
|
+
options[:cloudstack_url],
|
10
|
+
options[:cloudstack_api_key],
|
11
|
+
options[:cloudstack_secret_key]
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove_publicip(id)
|
16
|
+
@cs.disassociate_ip_address(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def domains(name = nil)
|
20
|
+
@cs.list_domains(name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def server_offerings(domain = nil)
|
24
|
+
@server_offerings ||= @cs.list_service_offerings(domain)
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_offering(params)
|
28
|
+
@cs.create_offering(params)
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete_offering(id)
|
32
|
+
@cs.delete_offering(id)
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_offering(args)
|
36
|
+
@cs.update_offering(args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def templates(type = 'featured', project_id)
|
40
|
+
@templates ||= @cs.list_templates(type, project_id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def projects
|
44
|
+
@projects ||= @cs.list_projects
|
45
|
+
end
|
46
|
+
|
47
|
+
def zones
|
48
|
+
@zones ||= @cs.list_zones
|
49
|
+
end
|
50
|
+
|
51
|
+
def networks(project_id = nil)
|
52
|
+
@cs.list_networks(project_id)
|
53
|
+
end
|
54
|
+
|
55
|
+
def physical_networks
|
56
|
+
@cs.list_physical_networks
|
57
|
+
end
|
58
|
+
|
59
|
+
def volumes(project_id = nil)
|
60
|
+
@cs.list_volumes(project_id)
|
61
|
+
end
|
62
|
+
|
63
|
+
def virtual_machines(options = {})
|
64
|
+
@cs.list_servers(options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def virtual_machines_table(vms)
|
68
|
+
table(border: true) do
|
69
|
+
row do
|
70
|
+
column 'Name', width: 20
|
71
|
+
column 'State'
|
72
|
+
column 'Offering', align: 'right'
|
73
|
+
column 'Template', align: 'right', width: 30
|
74
|
+
column 'IP\'s', width: 14
|
75
|
+
column 'Project'
|
76
|
+
column 'Account'
|
77
|
+
end
|
78
|
+
vms.each do |vm|
|
79
|
+
row do
|
80
|
+
column vm['name']
|
81
|
+
column vm['state']
|
82
|
+
column vm['serviceofferingname']
|
83
|
+
column vm['templatename']
|
84
|
+
column vm['nic'].map { |nic| nic['ipaddress']}.join(" ")
|
85
|
+
column vm['project']
|
86
|
+
column vm['account']
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def bootstrap_server(name, zone, template, offering, networks, pf_rules = [], project = nil)
|
93
|
+
puts "Create server #{name}...".color(:yellow)
|
94
|
+
server = @cs.create_server(
|
95
|
+
name,
|
96
|
+
offering,
|
97
|
+
template,
|
98
|
+
zone,
|
99
|
+
networks,
|
100
|
+
project
|
101
|
+
)
|
102
|
+
|
103
|
+
puts
|
104
|
+
puts "Server #{server["name"]} has been created.".color(:green)
|
105
|
+
puts
|
106
|
+
puts "Make sure the server is running...".color(:yellow)
|
107
|
+
@cs.wait_for_server_state(server["id"], "Running")
|
108
|
+
puts "OK!".color(:green)
|
109
|
+
puts
|
110
|
+
puts "Get the fqdn of the server...".color(:yellow)
|
111
|
+
server_fqdn = @cs.get_server_fqdn(server)
|
112
|
+
puts "FQDN is #{server_fqdn}".color(:green)
|
113
|
+
|
114
|
+
if pf_rules.size > 0
|
115
|
+
puts
|
116
|
+
pf_rules.each do |pf_rule|
|
117
|
+
ip = pf_rule.split(":")[0]
|
118
|
+
ip_addr = @cs.get_public_ip_address(ip)
|
119
|
+
port = pf_rule.split(":")[1]
|
120
|
+
print "Create port forwarding rule #{ip}:#{port} ".color(:yellow)
|
121
|
+
@cs.create_port_forwarding_rule(ip_addr["id"], port, 'TCP', port, server["id"])
|
122
|
+
puts
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
puts
|
127
|
+
puts "Complete!".color(:green)
|
128
|
+
end
|
129
|
+
|
130
|
+
def stop_server(name)
|
131
|
+
@cs.stop_server(name)
|
132
|
+
end
|
133
|
+
|
134
|
+
def start_server(name)
|
135
|
+
@cs.start_server(name)
|
136
|
+
end
|
137
|
+
|
138
|
+
def reboot_server(name)
|
139
|
+
@cs.reboot_server(name)
|
140
|
+
end
|
141
|
+
|
142
|
+
def list_accounts(name = nil)
|
143
|
+
@cs.list_accounts({ name: name })
|
144
|
+
end
|
145
|
+
|
146
|
+
def list_load_balancer_rules(project = nil)
|
147
|
+
@cs.list_load_balancer_rules(project)
|
148
|
+
end
|
149
|
+
|
150
|
+
def create_load_balancer_rule(name, ip, private_port, public_port, options = {})
|
151
|
+
puts "Create rule #{name}...".color(:yellow)
|
152
|
+
@cs.create_load_balancer_rule(name, ip, private_port, public_port, options = {})
|
153
|
+
puts "OK!".color(:green)
|
154
|
+
end
|
155
|
+
|
156
|
+
def assign_to_load_balancer_rule(id, names)
|
157
|
+
puts "Add #{names.join(', ')} to rule #{id}...".color(:yellow)
|
158
|
+
rule = @cs.assign_to_load_balancer_rule(id, names)
|
159
|
+
if rule['success']
|
160
|
+
puts "OK!".color(:green)
|
161
|
+
else
|
162
|
+
puts "Failed!".color(:red)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def list_routers(args, redundant_state = nil)
|
167
|
+
routers = @cs.list_routers(args)
|
168
|
+
if redundant_state
|
169
|
+
return routers.select {|r| r['redundantstate'].downcase == redundant_state.downcase }
|
170
|
+
end
|
171
|
+
routers
|
172
|
+
end
|
173
|
+
|
174
|
+
def destroy_router(id)
|
175
|
+
@cs.destroy_router(id)
|
176
|
+
end
|
177
|
+
|
178
|
+
def options
|
179
|
+
@options ||= CloudstackClient::ConnectionHelper.load_configuration()
|
180
|
+
end
|
181
|
+
|
182
|
+
def print_options(options, attr = 'name')
|
183
|
+
options.to_enum.with_index(1).each do |option, i|
|
184
|
+
puts "#{i}: #{option[attr]}"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def interactive
|
189
|
+
ARGV.clear
|
190
|
+
puts
|
191
|
+
puts %{We are going to deploy a new server and...
|
192
|
+
- assign a public IP address
|
193
|
+
- create a firewall rule for SSH and HTTP access
|
194
|
+
- connect to the server and install the puppet client}.color(:magenta)
|
195
|
+
puts
|
196
|
+
|
197
|
+
print "Please provide a name for the new server".background(:blue)
|
198
|
+
puts " (spaces or special characters are NOT allowed): "
|
199
|
+
server_name = gets.chomp
|
200
|
+
|
201
|
+
if projects.size > 0
|
202
|
+
puts "Select a project".background(:blue)
|
203
|
+
print_options(projects)
|
204
|
+
project = gets.chomp.to_i - 1
|
205
|
+
end
|
206
|
+
|
207
|
+
puts "Select a computing offering:".background(:blue)
|
208
|
+
print_options(server_offerings)
|
209
|
+
service_offering = gets.chomp.to_i - 1
|
210
|
+
|
211
|
+
puts "Select a template:".background(:blue)
|
212
|
+
print_options(templates)
|
213
|
+
template = gets.chomp.to_i - 1
|
214
|
+
|
215
|
+
puts "Select a availability zone:".background(:blue)
|
216
|
+
print_options(zones)
|
217
|
+
zone = gets.chomp.to_i - 1
|
218
|
+
|
219
|
+
# FIXME: show only networks in selected zone
|
220
|
+
puts "Select a network:".background(:blue)
|
221
|
+
project_id = projects[project]['id'] rescue nil
|
222
|
+
networks = @cs.list_networks(project_id)
|
223
|
+
print_options(networks)
|
224
|
+
network = gets.chomp.to_i - 1
|
225
|
+
|
226
|
+
bootstrap_server(
|
227
|
+
server_name,
|
228
|
+
zones[zone]["name"],
|
229
|
+
templates[template]["name"],
|
230
|
+
server_offerings[service_offering]["name"],
|
231
|
+
[networks[network]["name"]],
|
232
|
+
projects[project]["name"]
|
233
|
+
)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|