cloudstack-cli 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,9 @@
1
+ class Publicip < Thor
2
+
3
+ desc "remove ID", "remove public IP address"
4
+ def remove(id)
5
+ cs_cli = CloudstackCli::Helper.new
6
+ puts "OK" if cs_cli.remove_publicip(id)
7
+ end
8
+
9
+ 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