paasio 0.3.16.beta.2

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/lib/cli/runner.rb ADDED
@@ -0,0 +1,535 @@
1
+
2
+ require 'optparse'
3
+
4
+ require File.dirname(__FILE__) + '/usage'
5
+
6
+ class VMC::Cli::Runner
7
+
8
+ attr_reader :namespace
9
+ attr_reader :action
10
+ attr_reader :args
11
+ attr_reader :options
12
+
13
+ def self.run(args)
14
+ new(args).run
15
+ end
16
+
17
+ def initialize(args=[])
18
+ @args = args
19
+ @options = { :colorize => true }
20
+ @exit_status = true
21
+ end
22
+
23
+ # Collect all the available options for all commands
24
+ # Some duplicates exists to capture all scenarios
25
+ def parse_options!
26
+ opts_parser = OptionParser.new do |opts|
27
+ opts.banner = "\nAvailable options:\n\n"
28
+
29
+ opts.on('--email EMAIL') { |email| @options[:email] = email }
30
+ opts.on('--user EMAIL') { |email| @options[:email] = email }
31
+ opts.on('--passwd PASS') { |pass| @options[:password] = pass }
32
+ opts.on('--pass PASS') { |pass| @options[:password] = pass }
33
+ opts.on('--password PASS') { |pass| @options[:password] = pass }
34
+ opts.on('--token-file TOKEN_FILE') { |token_file| @options[:token_file] = token_file }
35
+ opts.on('--app NAME') { |name| @options[:name] = name }
36
+ opts.on('--name NAME') { |name| @options[:name] = name }
37
+ opts.on('--bind BIND') { |bind| @options[:bind] = bind }
38
+ opts.on('--instance INST') { |inst| @options[:instance] = inst }
39
+ opts.on('--instances INST') { |inst| @options[:instances] = inst }
40
+ opts.on('--url URL') { |url| @options[:url] = url }
41
+ opts.on('--mem MEM') { |mem| @options[:mem] = mem }
42
+ opts.on('--path PATH') { |path| @options[:path] = path }
43
+ opts.on('--no-start') { @options[:nostart] = true }
44
+ opts.on('--nostart') { @options[:nostart] = true }
45
+ opts.on('--force') { @options[:force] = true }
46
+ opts.on('--all') { @options[:all] = true }
47
+
48
+ # generic tracing and debugging
49
+ opts.on('-t [TKEY]') { |tkey| @options[:trace] = tkey || true }
50
+ opts.on('--trace [TKEY]') { |tkey| @options[:trace] = tkey || true }
51
+
52
+ # start application in debug mode
53
+ opts.on('-d [MODE]') { |mode| @options[:debug] = mode || "run" }
54
+ opts.on('--debug [MODE]') { |mode| @options[:debug] = mode || "run" }
55
+
56
+ # override manifest file
57
+ opts.on('-m FILE') { |file| @options[:manifest] = file }
58
+ opts.on('--manifest FILE') { |file| @options[:manifest] = file }
59
+
60
+ opts.on('-q', '--quiet') { @options[:quiet] = true }
61
+
62
+ # Don't use builtin zip
63
+ opts.on('--no-zip') { @options[:nozip] = true }
64
+ opts.on('--nozip') { @options[:nozip] = true }
65
+
66
+ opts.on('--no-resources') { @options[:noresources] = true }
67
+ opts.on('--noresources') { @options[:noresources] = true }
68
+
69
+ opts.on('--no-color') { @options[:colorize] = false }
70
+ opts.on('--verbose') { @options[:verbose] = true }
71
+
72
+ opts.on('-n','--no-prompt') { @options[:noprompts] = true }
73
+ opts.on('--noprompt') { @options[:noprompts] = true }
74
+ opts.on('--non-interactive') { @options[:noprompts] = true }
75
+
76
+ opts.on('--prefix') { @options[:prefixlogs] = true }
77
+ opts.on('--prefix-logs') { @options[:prefixlogs] = true }
78
+ opts.on('--prefixlogs') { @options[:prefixlogs] = true }
79
+
80
+ opts.on('--json') { @options[:json] = true }
81
+
82
+ opts.on('-v', '--version') { set_cmd(:misc, :version) }
83
+ opts.on('-h', '--help') { puts "#{command_usage}\n"; exit }
84
+
85
+ opts.on('--port PORT') { |port| @options[:port] = port }
86
+
87
+ opts.on('--runtime RUNTIME') { |rt| @options[:runtime] = rt }
88
+
89
+ opts.on('--remote REMOTE') { |r| @options[:remote] = r }
90
+ opts.on('--scm-type TYPE') { |t| @options[:scm_type] = t if t == 'git' || t == 'hg' }
91
+
92
+ # deprecated
93
+ opts.on('--exec EXEC') { |exec| @options[:exec] = exec }
94
+ opts.on('--noframework') { @options[:noframework] = true }
95
+ opts.on('--canary') { @options[:canary] = true }
96
+
97
+ # Proxying for another user, requires admin privileges
98
+ opts.on('-u PROXY') { |proxy| @options[:proxy] = proxy }
99
+
100
+ opts.on_tail('--options') { puts "#{opts}\n"; exit }
101
+ end
102
+ instances_delta_arg = check_instances_delta!
103
+ @args = opts_parser.parse!(@args)
104
+ @args.concat instances_delta_arg
105
+ convert_options!
106
+ self
107
+ end
108
+
109
+ def check_instances_delta!
110
+ return unless @args
111
+ instance_args = @args.select { |arg| /^[-]\d+$/ =~ arg } || []
112
+ @args.delete_if { |arg| instance_args.include? arg}
113
+ instance_args
114
+ end
115
+
116
+ def display_help
117
+ puts command_usage
118
+ exit
119
+ end
120
+
121
+ def convert_options!
122
+ # make sure certain options are valid and in correct form.
123
+ @options[:instances] = Integer(@options[:instances]) if @options[:instances]
124
+ end
125
+
126
+ def set_cmd(namespace, action, args_range=0)
127
+ return if @help_only
128
+ unless args_range == "*" || args_range.is_a?(Range)
129
+ args_range = (args_range.to_i..args_range.to_i)
130
+ end
131
+
132
+ if args_range == "*" || args_range.include?(@args.size)
133
+ @namespace = namespace
134
+ @action = action
135
+ else
136
+ @exit_status = false
137
+ if @args.size > args_range.last
138
+ usage_error("Too many arguments for [#{action}]: %s" % [ @args[args_range.last..-1].map{|a| "'#{a}'"}.join(', ') ])
139
+ else
140
+ usage_error("Not enough arguments for [#{action}]")
141
+ end
142
+ end
143
+ end
144
+
145
+ def parse_command!
146
+ # just return if already set, happends with -v, -h
147
+ return if @namespace && @action
148
+
149
+ verb = @args.shift
150
+ case verb
151
+
152
+ when 'version'
153
+ usage('paasio version')
154
+ set_cmd(:misc, :version)
155
+
156
+ when 'target'
157
+ usage('paasio target [url] [--url]')
158
+ if @args.size == 1
159
+ set_cmd(:misc, :set_target, 1)
160
+ else
161
+ set_cmd(:misc, :target)
162
+ end
163
+
164
+ when 'targets'
165
+ usage('paasio targets')
166
+ set_cmd(:misc, :targets)
167
+
168
+ when 'tokens'
169
+ usage('paasio tokens')
170
+ set_cmd(:misc, :tokens)
171
+
172
+ when 'info'
173
+ usage('paasio info')
174
+ set_cmd(:misc, :info)
175
+
176
+ when 'runtimes'
177
+ usage('paasio runtimes')
178
+ set_cmd(:misc, :runtimes)
179
+
180
+ when 'frameworks'
181
+ usage('paasio frameworks')
182
+ set_cmd(:misc, :frameworks)
183
+
184
+ when 'user'
185
+ usage('paasio user')
186
+ set_cmd(:user, :info)
187
+
188
+ when 'login'
189
+ usage('paasio login [email] [--email EMAIL] [--passwd PASS]')
190
+ if @args.size == 1
191
+ set_cmd(:user, :login, 1)
192
+ else
193
+ set_cmd(:user, :login)
194
+ end
195
+
196
+ when 'logout'
197
+ usage('paasio logout')
198
+ set_cmd(:user, :logout)
199
+
200
+ when 'passwd'
201
+ usage('paasio passwd')
202
+ if @args.size == 1
203
+ set_cmd(:user, :change_password, 1)
204
+ else
205
+ set_cmd(:user, :change_password)
206
+ end
207
+
208
+ when 'add-user', 'add_user', 'create_user', 'create-user', 'register'
209
+ usage('paasio add-user [user] [--email EMAIL] [--passwd PASS]')
210
+ if @args.size == 1
211
+ set_cmd(:admin, :add_user, 1)
212
+ else
213
+ set_cmd(:admin, :add_user)
214
+ end
215
+
216
+ when 'delete-user', 'delete_user', 'unregister'
217
+ usage('paasio delete-user <user>')
218
+ set_cmd(:admin, :delete_user, 1)
219
+
220
+ when 'users'
221
+ usage('paasio users')
222
+ set_cmd(:admin, :users)
223
+
224
+ when 'apps'
225
+ usage('paasio apps')
226
+ set_cmd(:apps, :apps)
227
+
228
+ when 'list'
229
+ usage('paasio list')
230
+ set_cmd(:apps, :list)
231
+
232
+ when 'start'
233
+ usage('paasio start <appname>')
234
+ set_cmd(:apps, :start, @args.size == 1 ? 1 : 0)
235
+
236
+ when 'stop'
237
+ usage('paasio stop <appname>')
238
+ set_cmd(:apps, :stop, @args.size == 1 ? 1 : 0)
239
+
240
+ when 'restart'
241
+ usage('paasio restart <appname>')
242
+ set_cmd(:apps, :restart, @args.size == 1 ? 1 : 0)
243
+
244
+ when 'rename'
245
+ usage('paasio rename <appname> <newname>')
246
+ set_cmd(:apps, :rename, 2)
247
+
248
+ when 'mem'
249
+ usage('paasio mem <appname> [memsize]')
250
+ if @args.size == 2
251
+ set_cmd(:apps, :mem, 2)
252
+ else
253
+ set_cmd(:apps, :mem, 1)
254
+ end
255
+
256
+ when 'stats'
257
+ usage('paasio stats <appname>')
258
+ set_cmd(:apps, :stats, @args.size == 1 ? 1 : 0)
259
+
260
+ when 'map'
261
+ usage('paasio map <appname> <url>')
262
+ set_cmd(:apps, :map, 2)
263
+
264
+ when 'unmap'
265
+ usage('paasio unmap <appname> <url>')
266
+ set_cmd(:apps, :unmap, 2)
267
+
268
+ when 'delete'
269
+ usage('paasio delete <appname>')
270
+ if @options[:all] && @args.size == 0
271
+ set_cmd(:apps, :delete)
272
+ else
273
+ set_cmd(:apps, :delete, 1)
274
+ end
275
+
276
+ when 'files'
277
+ usage('paasio files <appname> [path] [--instance N] [--all] [--prefix]')
278
+ if @args.size == 1
279
+ set_cmd(:apps, :files, 1)
280
+ else
281
+ set_cmd(:apps, :files, 2)
282
+ end
283
+
284
+ when 'logs'
285
+ usage('paasio logs <appname> [--instance N] [--all] [--prefix]')
286
+ set_cmd(:apps, :logs, 1)
287
+
288
+ when 'instances', 'scale'
289
+ if @args.size > 1
290
+ usage('paasio instances <appname> <num|delta>')
291
+ set_cmd(:apps, :instances, 2)
292
+ else
293
+ usage('paasio instances <appname>')
294
+ set_cmd(:apps, :instances, @args.size == 1 ? 1 : 0)
295
+ end
296
+
297
+ when 'crashes'
298
+ usage('paasio crashes <appname>')
299
+ set_cmd(:apps, :crashes, 1)
300
+
301
+ when 'crashlogs'
302
+ usage('paasio crashlogs <appname>')
303
+ set_cmd(:apps, :crashlogs, 1)
304
+
305
+ when 'create'
306
+ usage('paasio create [appname] [--url URL] [--instances N] [--mem] [--runtime RUNTIME] [--scm-type git|hg] [--remote NAME]')
307
+ if @args.size == 1
308
+ set_cmd(:apps, :create, 1)
309
+ else
310
+ set_cmd(:apps, :create, 0)
311
+ end
312
+
313
+ when 'upload'
314
+ usage('paasio upload <appname> [--path PATH]')
315
+ set_cmd(:apps, :upload, @args.size == 1 ? 1 : 0)
316
+
317
+ when 'push'
318
+ usage('paasio push [appname] [--path PATH] [--url URL] [--instances N] [--mem] [--runtime RUNTIME] [--no-start]')
319
+ if @args.size == 1
320
+ set_cmd(:apps, :push, 1)
321
+ else
322
+ set_cmd(:apps, :push, 0)
323
+ end
324
+
325
+ when 'update'
326
+ usage('paasio update <appname> [--path PATH]')
327
+ set_cmd(:apps, :update, @args.size == 1 ? 1 : 0)
328
+
329
+ when 'services'
330
+ usage('paasio services')
331
+ set_cmd(:services, :services)
332
+
333
+ when 'env'
334
+ usage('paasio env <appname>')
335
+ set_cmd(:apps, :environment, 1)
336
+
337
+ when 'env-add'
338
+ usage('paasio env-add <appname> <variable[=]value>')
339
+ if @args.size == 2
340
+ set_cmd(:apps, :environment_add, 2)
341
+ elsif @args.size == 3
342
+ set_cmd(:apps, :environment_add, 3)
343
+ end
344
+
345
+ when 'env-del'
346
+ usage('paasio env-del <appname> <variable>')
347
+ set_cmd(:apps, :environment_del, 2)
348
+
349
+ when 'create-service', 'create_service'
350
+ usage('paasio create-service [service] [servicename] [appname] [--name servicename] [--bind appname]')
351
+ set_cmd(:services, :create_service) if @args.size == 0
352
+ set_cmd(:services, :create_service, 1) if @args.size == 1
353
+ set_cmd(:services, :create_service, 2) if @args.size == 2
354
+ set_cmd(:services, :create_service, 3) if @args.size == 3
355
+
356
+ when 'delete-service', 'delete_service'
357
+ usage('paasio delete-service <service>')
358
+ if @args.size == 1
359
+ set_cmd(:services, :delete_service, 1)
360
+ else
361
+ set_cmd(:services, :delete_service)
362
+ end
363
+
364
+ when 'bind-service', 'bind_service'
365
+ usage('paasio bind-service <servicename> <appname>')
366
+ set_cmd(:services, :bind_service, 2)
367
+
368
+ when 'unbind-service', 'unbind_service'
369
+ usage('paasio unbind-service <servicename> <appname>')
370
+ set_cmd(:services, :unbind_service, 2)
371
+
372
+ when 'clone-services'
373
+ usage('paasio clone-services <src-app> <dest-app>')
374
+ set_cmd(:services, :clone_services, 2)
375
+
376
+ when 'aliases'
377
+ usage('paasio aliases')
378
+ set_cmd(:misc, :aliases)
379
+
380
+ when 'alias'
381
+ usage('paasio alias <alias[=]command>')
382
+ if @args.size == 1
383
+ set_cmd(:misc, :alias, 1)
384
+ elsif @args.size == 2
385
+ set_cmd(:misc, :alias, 2)
386
+ end
387
+
388
+ when 'unalias'
389
+ usage('paasio unalias <alias>')
390
+ set_cmd(:misc, :unalias, 1)
391
+
392
+ when 'tunnel'
393
+ usage('paasio tunnel [servicename] [clientcmd] [--port port]')
394
+ set_cmd(:services, :tunnel, 0) if @args.size == 0
395
+ set_cmd(:services, :tunnel, 1) if @args.size == 1
396
+ set_cmd(:services, :tunnel, 2) if @args.size == 2
397
+
398
+ when 'help'
399
+ display_help if @args.size == 0
400
+ @help_only = true
401
+ parse_command!
402
+
403
+ when 'usage'
404
+ display basic_usage
405
+ exit(true)
406
+
407
+ when 'options'
408
+ # Simulate --options
409
+ @args = @args.unshift('--options')
410
+ parse_options!
411
+
412
+ when 'manifest'
413
+ usage('paasio manifest')
414
+ set_cmd(:manifest, :edit)
415
+
416
+ when 'extend-manifest'
417
+ usage('paasio extend-manifest')
418
+ set_cmd(:manifest, :extend, 1)
419
+
420
+ else
421
+ if verb
422
+ display "paasio: Unknown command [#{verb}]"
423
+ display basic_usage
424
+ exit(false)
425
+ end
426
+ end
427
+ end
428
+
429
+ def process_aliases!
430
+ return if @args.empty?
431
+ aliases = VMC::Cli::Config.aliases
432
+ aliases.each_pair do |k,v|
433
+ if @args[0] == k
434
+ display "[#{@args[0]} aliased to #{aliases.invert[key]}]" if @options[:verbose]
435
+ @args[0] = v
436
+ break;
437
+ end
438
+ end
439
+ end
440
+
441
+ def usage(msg = nil)
442
+ @usage = msg if msg
443
+ @usage
444
+ end
445
+
446
+ def usage_error(msg = nil)
447
+ @usage_error = msg if msg
448
+ @usage_error
449
+ end
450
+
451
+ def run
452
+
453
+ trap('TERM') { print "\nTerminated\n"; exit(false)}
454
+
455
+ parse_options!
456
+
457
+ @options[:colorize] = false unless STDOUT.tty?
458
+
459
+ VMC::Cli::Config.colorize = @options.delete(:colorize)
460
+ VMC::Cli::Config.nozip = @options.delete(:nozip)
461
+ VMC::Cli::Config.trace = @options.delete(:trace)
462
+ VMC::Cli::Config.output ||= STDOUT unless @options[:quiet]
463
+
464
+ process_aliases!
465
+ parse_command!
466
+
467
+ if @namespace && @action
468
+ cmd = VMC::Cli::Command.const_get(@namespace.to_s.capitalize)
469
+ cmd.new(@options).send(@action, *@args.collect(&:dup))
470
+ elsif @help_only || @usage
471
+ display_usage
472
+ else
473
+ display basic_usage
474
+ exit(false)
475
+ end
476
+
477
+ rescue OptionParser::InvalidOption => e
478
+ puts(e.message.red)
479
+ puts("\n")
480
+ puts(basic_usage)
481
+ @exit_status = false
482
+ rescue OptionParser::AmbiguousOption => e
483
+ puts(e.message.red)
484
+ puts("\n")
485
+ puts(basic_usage)
486
+ @exit_status = false
487
+ rescue VMC::Client::AuthError => e
488
+ if VMC::Cli::Config.auth_token.nil?
489
+ puts "Login Required".red
490
+ else
491
+ puts "Not Authorized".red
492
+ end
493
+ @exit_status = false
494
+ rescue VMC::Client::TargetError, VMC::Client::NotFound, VMC::Client::BadTarget => e
495
+ puts e.message.red
496
+ @exit_status = false
497
+ rescue VMC::Client::HTTPException => e
498
+ puts e.message.red
499
+ @exit_status = false
500
+ rescue VMC::Cli::GracefulExit => e
501
+ # Redirected commands end up generating this exception (kind of goto)
502
+ rescue VMC::Cli::CliExit => e
503
+ puts e.message.red
504
+ @exit_status = false
505
+ rescue VMC::Cli::CliError => e
506
+ say("Error #{e.error_code}: #{e.message}".red)
507
+ @exit_status = false
508
+ rescue SystemExit => e
509
+ @exit_status = e.success?
510
+ rescue SyntaxError => e
511
+ puts e.message.red
512
+ puts e.backtrace
513
+ @exit_status = false
514
+ rescue Interrupt => e
515
+ say("\nInterrupted".red)
516
+ @exit_status = false
517
+ rescue Exception => e
518
+ puts e.message.red
519
+ puts e.backtrace
520
+ @exit_status = false
521
+ ensure
522
+ say("\n")
523
+ @exit_status == true if @exit_status.nil?
524
+ if @options[:verbose]
525
+ if @exit_status
526
+ puts "[#{@namespace}:#{@action}] SUCCEEDED".green
527
+ else
528
+ puts "[#{@namespace}:#{@action}] FAILED".red
529
+ end
530
+ say("\n")
531
+ end
532
+ exit(@exit_status)
533
+ end
534
+
535
+ end
@@ -0,0 +1,84 @@
1
+
2
+ module VMC::Cli
3
+ module ServicesHelper
4
+ def display_system_services(services=nil)
5
+ services ||= client.services_info
6
+
7
+ display "\n============== System Services ==============\n\n"
8
+
9
+ return display "No system services available" if services.empty?
10
+
11
+ displayed_services = []
12
+ services.each do |service_type, value|
13
+ value.each do |vendor, version|
14
+ version.each do |version_str, service|
15
+ displayed_services << [ vendor, version_str, service[:description] ]
16
+ end
17
+ end
18
+ end
19
+ displayed_services.sort! { |a, b| a.first.to_s <=> b.first.to_s}
20
+
21
+ services_table = table do |t|
22
+ t.headings = 'Service', 'Version', 'Description'
23
+ displayed_services.each { |s| t << s }
24
+ end
25
+ display services_table
26
+ end
27
+
28
+ def display_provisioned_services(services=nil)
29
+ services ||= client.services
30
+ display "\n=========== Provisioned Services ============\n\n"
31
+ display_provisioned_services_table(services)
32
+ end
33
+
34
+ def display_provisioned_services_table(services)
35
+ return unless services && !services.empty?
36
+ services_table = table do |t|
37
+ t.headings = 'Name', 'Service'
38
+ services.each do |service|
39
+ t << [ service[:name], service[:vendor] ]
40
+ end
41
+ end
42
+ display services_table
43
+ end
44
+
45
+ def create_service_banner(service, name, display_name=false)
46
+ sn = " [#{name}]" if display_name
47
+ display "Creating Service#{sn}: ", false
48
+ client.create_service(service, name)
49
+ display 'OK'.green
50
+ end
51
+
52
+ def bind_service_banner(service, appname, check_restart=true)
53
+ display "Binding Service [#{service}]: ", false
54
+ client.bind_service(service, appname)
55
+ display 'OK'.green
56
+ check_app_for_restart(appname) if check_restart
57
+ end
58
+
59
+ def unbind_service_banner(service, appname, check_restart=true)
60
+ display "Unbinding Service [#{service}]: ", false
61
+ client.unbind_service(service, appname)
62
+ display 'OK'.green
63
+ check_app_for_restart(appname) if check_restart
64
+ end
65
+
66
+ def delete_service_banner(service)
67
+ display "Deleting service [#{service}]: ", false
68
+ client.delete_service(service)
69
+ display 'OK'.green
70
+ end
71
+
72
+ def random_service_name(service)
73
+ r = "%04x" % [rand(0x0100000)]
74
+ "#{service.to_s}-#{r}"
75
+ end
76
+
77
+ def check_app_for_restart(appname)
78
+ app = client.app_info(appname)
79
+ cmd = VMC::Cli::Command::Apps.new(@options)
80
+ cmd.restart(appname) if app[:state] == 'STARTED'
81
+ end
82
+
83
+ end
84
+ end