module CloudstackCli::Helper

Constants

ASYNC_STATES

Public Instance Methods

ask_number(question) click to toggle source
   # File lib/cloudstack-cli/helper.rb
 9 def ask_number(question)
10   number = ask(question).to_i - 1
11   number < 0 ? 0 : number
12 end
bootstrap_server(args = {}) click to toggle source
    # File lib/cloudstack-cli/helper.rb
139 def bootstrap_server(args = {})
140   if args[:project] && project = find_project(args[:project])
141     project_id = project["id"]
142     project_name = project['name']
143   end
144 
145   if args[:name]
146     args['displayname'] = args[:name]
147     name = args[:name]
148   elsif args[:displayname]
149     name = args[:displayname]
150   end
151 
152   unless server = client.list_virtual_machines(name: args[:name], project_id: project_id).first
153     say "Create VM #{name}...", :yellow
154     server = client.deploy_virtual_machine(args)
155     puts
156     say "VM #{name} has been created.", :green
157   else
158     say "VM #{name} already exists (#{server["state"]}).", :yellow
159   end
160 
161   if args[:port_rules] && args[:port_rules].size > 0
162     create_port_rules(server, args[:port_rules])
163   end
164   server
165 end
bootstrap_server_interactive() click to toggle source
    # File lib/cloudstack-cli/helper.rb
241 def bootstrap_server_interactive
242   zones = client.list_zones
243   if zones.size > 1
244     say "Select a availability zone:", :yellow
245     print_options(zones)
246     zone = ask_number("Zone Nr.: ")
247   else
248     zone = 0
249   end
250 
251   projects = client.list_projects
252   project_id = nil
253   if projects.size > 0
254     if yes?("Do you want to deploy your VM within a project? (y/N)") && projects.size > 0
255       say "Select a project", :yellow
256       print_options(projects)
257       project = ask_number("Project Nr.: ")
258       project_id = projects[project]['id'] rescue nil
259     end
260   end
261 
262   say "Please provide a name for the new VM", :yellow
263   say "(spaces or special characters are NOT allowed)"
264   server_name = ask("Server name: ")
265 
266   server_offerings = client.list_service_offerings
267   say "Select a computing offering:", :yellow
268   print_options(server_offerings)
269   service_offering = ask_number("Offering Nr.: ")
270 
271   templates = client.list_templates(project_id: project_id, zone_id: zones[zone]["id"], template_filter: "executable")
272   say "Select a template:", :yellow
273   print_options(templates)
274   template = ask_number("Template Nr.: ")
275 
276   networks = client.list_networks(project_id: project_id, zone_id: zones[zone]["id"])
277   if networks.size > 1
278     say "Select a network:", :yellow
279     print_options(networks)
280     network = ask_number("Network Nr.: ")
281   else
282     network = 0
283   end
284 
285   say "You entered the following configuration:", :yellow
286   table =  [["Zone", zones[zone]["name"]]]
287   table << ["VM Name", server_name]
288   table << ["Template", templates[template]["name"]]
289   table << ["Offering", server_offerings[service_offering]["name"]]
290   table << ["Network", networks[network]["name"]]
291   table << ["Project", projects[project]["name"]] if project
292   print_table table
293 
294   if yes? "Do you want to deploy this VM? (y/N)"
295     bootstrap_server(
296       name: server_name,
297       zone_id: zones[zone]["id"],
298       template_id: templates[template]["id"],
299       serviceoffering_id: server_offerings[service_offering]["id"],
300       network_ids: network ? networks[network]["id"] : nil,
301       project_id: project_id
302     )
303   end
304 end
create_port_rules(server, port_rules, async = true) click to toggle source
    # File lib/cloudstack-cli/helper.rb
178 def create_port_rules(server, port_rules, async = true)
179   frontendip_id = nil
180   jobs = []
181   client.verbose = async
182   project_id = server['projectid'] || nil
183   port_rules.each do |pf_rule|
184     pf_rule = pf_rule_to_object(pf_rule)
185     if pf_rule[:ipaddress]
186       pub_ip = client.list_public_ip_addresses(
187         network_id: get_server_default_nic(server)["networkid"],
188         project_id: project_id,
189         ipaddress: pf_rule[:ipaddress]
190       )
191       ip_addr = pub_ip.find { |addr| addr['ipaddress'] == pf_rule[:ipaddress]} if pub_ip
192       if ip_addr
193         frontendip = ip_addr['id']
194       else
195         say "Error: IP #{pf_rule[:ipaddress]} not found.", :red
196         next
197       end
198     end
199 
200     # check if there is already an existing rule
201     rules = client.list_port_forwarding_rules(
202       networkid: get_server_default_nic(server)["networkid"],
203       ipaddressid: frontendip_id,
204       projectid: project_id
205     )
206     existing_pf_rules = rules.find do |rule|
207       # remember matching address for additional rules
208       frontendip_id = rule['ipaddressid'] if rule['virtualmachineid'] == server['id']
209 
210       rule['virtualmachineid'] == server['id'] &&
211       rule['publicport'] == pf_rule[:publicport] &&
212       rule['privateport'] == pf_rule[:privateport] &&
213       rule['protocol'] == pf_rule[:protocol]
214     end
215 
216     if existing_pf_rules
217       say "Port forwarding rule on port #{pf_rule[:privateport]} for VM #{server["name"]} already exists.", :yellow
218     else
219       unless frontendip_id
220         frontendip_id = client.associate_ip_address(
221           network_id: get_server_default_nic(server)["networkid"],
222           project_id: project_id
223         )['ipaddress']['id']
224       end
225       args = pf_rule.merge({
226         ipaddressid: frontendip_id,
227         virtualmachineid: server["id"]
228       })
229       if async
230         say "Create port forwarding rule #{pf_rule[:ipaddress]}:#{port} for VM #{server["name"]}.", :yellow
231         client.create_port_forwarding_rule(args)
232         return
233       else
234         jobs << client.create_port_forwarding_rule(args, {sync: true})['jobid']
235       end
236     end
237   end
238   jobs
239 end
create_server(args = {}) click to toggle source
    # File lib/cloudstack-cli/helper.rb
167 def create_server(args = {})
168   if args[:project] && project = find_project(args[:project])
169     project_id = project["id"]
170     project_name = project['name']
171   end
172   unless server = client.list_virtual_machines(name: args[:name], project_id: project_id)
173     server = client.deploy_virtual_machine(args)
174   end
175   server
176 end
get_server_default_nic(server) click to toggle source
    # File lib/cloudstack-cli/helper.rb
306 def get_server_default_nic(server)
307   server['nic'].each do |nic|
308     return nic if nic['isdefault']
309   end
310 end
pf_rule_to_object(pf_rule) click to toggle source
    # File lib/cloudstack-cli/helper.rb
312 def pf_rule_to_object(pf_rule)
313   pf_rule = pf_rule.split(":")
314   {
315     ipaddress: (pf_rule[0] == '' ? nil : pf_rule[0]),
316     privateport: pf_rule[1],
317     publicport: (pf_rule[2] || pf_rule[1]),
318     protocol: (pf_rule[3] || 'tcp').downcase
319   }
320 end
print_job_status(jobs, spinner, opts = {t_start: Time.now}) click to toggle source
print_options(options, attr = 'name') click to toggle source
run_background_jobs(jobs, command) click to toggle source
   # File lib/cloudstack-cli/helper.rb
64 def run_background_jobs(jobs, command)
65   view_thread = Thread.new do
66     chars = %w(| / - \\)
67     call = 0
68     opts = {t_start: Time.now}
69 
70     while jobs.count{|job| job[:status] < 1 } > 0 do
71       if call.modulo(40) == 0
72         t = Thread.new { jobs = update_jobs(jobs, command) }
73         while t.alive?
74           chars = print_job_status(jobs, chars,
75             call == 0 ? opts.merge(no_clear: true) : opts
76           )
77           call += 1
78         end
79         t.join
80       else
81         chars = print_job_status(jobs, chars,
82           call == 0 ? opts.merge(no_clear: true) : opts
83         )
84         call += 1
85       end
86     end
87     print_job_status(jobs, chars,
88       call == 0 ? opts.merge(no_clear: true) : opts
89     )
90   end
91   view_thread.join
92 end
update_job_status(jobs) click to toggle source
   # File lib/cloudstack-cli/helper.rb
49 def update_job_status(jobs)
50   jobs.each do |job|
51     job[:status] = 0 unless job[:status]
52     if job[:status] == 0
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
59     end
60   end
61   jobs
62 end
update_jobs(jobs, command) click to toggle source
    # File lib/cloudstack-cli/helper.rb
 94 def update_jobs(jobs, command)
 95   # update running job status
 96   threads = jobs.select{|job| job[:status] == 0 }.map do |job|
 97     Thread.new do
 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
103     end
104   end
105   threads.each(&:join)
106 
107   # launch new jobs if required and possible
108   launch_capacity = (options[:concurrency] ||= 10) - jobs.count{|job| job[:status] == 0 }
109   threads = []
110   jobs.select{|job| job[:status] == -1 }.each do |job|
111     if launch_capacity > 0
112       threads << Thread.new do
113         job[:job_id] = client.send(
114           command, job[:args], { sync: true }
115         )['jobid']
116         job[:status] = 0
117       end
118       launch_capacity -= 1
119     end
120   end
121   threads.each(&:join)
122   jobs
123 end
watch_jobs(jobs) click to toggle source
   # File lib/cloudstack-cli/helper.rb
22 def watch_jobs(jobs)
23   chars = %w(| / - \\)
24   call = 0
25   opts = {t_start: Time.now}
26   jobs = update_job_status(jobs)
27   while jobs.count{|job| job[:status].to_i < 1 } > 0 do
28     if call.modulo(40) == 0
29       t = Thread.new { jobs = update_job_status(jobs) }
30       while t.alive?
31         chars = print_job_status(jobs, chars,
32           call == 0 ? opts.merge(no_clear: true) : opts
33         )
34         call += 1
35       end
36       t.join
37     else
38       chars = print_job_status(jobs, chars,
39         call == 0 ? opts.merge(no_clear: true) : opts
40       )
41       call += 1
42     end
43   end
44   print_job_status(jobs, chars,
45     call == 0 ? opts.merge(no_clear: true) : opts
46   )
47 end