sys 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.
Files changed (44) hide show
  1. data/LICENSE +24 -0
  2. data/README.md +103 -0
  3. data/Rakefile +101 -0
  4. data/bin/sys +6 -0
  5. data/caldecott_helper/Gemfile +10 -0
  6. data/caldecott_helper/Gemfile.lock +48 -0
  7. data/caldecott_helper/server.rb +43 -0
  8. data/config/clients.yml +17 -0
  9. data/config/micro/offline.conf +2 -0
  10. data/config/micro/paths.yml +22 -0
  11. data/config/micro/refresh_ip.rb +20 -0
  12. data/lib/cli.rb +48 -0
  13. data/lib/cli/commands/admin.rb +80 -0
  14. data/lib/cli/commands/apps.rb +1208 -0
  15. data/lib/cli/commands/base.rb +233 -0
  16. data/lib/cli/commands/manifest.rb +56 -0
  17. data/lib/cli/commands/micro.rb +115 -0
  18. data/lib/cli/commands/misc.rb +140 -0
  19. data/lib/cli/commands/services.rb +217 -0
  20. data/lib/cli/commands/user.rb +65 -0
  21. data/lib/cli/config.rb +170 -0
  22. data/lib/cli/console_helper.rb +163 -0
  23. data/lib/cli/core_ext.rb +122 -0
  24. data/lib/cli/errors.rb +19 -0
  25. data/lib/cli/file_helper.rb +123 -0
  26. data/lib/cli/frameworks.rb +265 -0
  27. data/lib/cli/manifest_helper.rb +316 -0
  28. data/lib/cli/runner.rb +568 -0
  29. data/lib/cli/services_helper.rb +104 -0
  30. data/lib/cli/tunnel_helper.rb +336 -0
  31. data/lib/cli/usage.rb +125 -0
  32. data/lib/cli/version.rb +7 -0
  33. data/lib/cli/zip_util.rb +77 -0
  34. data/lib/vmc.rb +3 -0
  35. data/lib/vmc/client.rb +558 -0
  36. data/lib/vmc/const.rb +27 -0
  37. data/lib/vmc/micro.rb +56 -0
  38. data/lib/vmc/micro/switcher/base.rb +97 -0
  39. data/lib/vmc/micro/switcher/darwin.rb +19 -0
  40. data/lib/vmc/micro/switcher/dummy.rb +15 -0
  41. data/lib/vmc/micro/switcher/linux.rb +16 -0
  42. data/lib/vmc/micro/switcher/windows.rb +31 -0
  43. data/lib/vmc/micro/vmrun.rb +158 -0
  44. metadata +217 -0
@@ -0,0 +1,316 @@
1
+ require "set"
2
+
3
+ module VMC::Cli::ManifestHelper
4
+ include VMC::Cli::ServicesHelper
5
+
6
+ DEFAULTS = {
7
+ "url" => "${name}.${target-base}",
8
+ "mem" => "128M",
9
+ "instances" => 1
10
+ }
11
+
12
+ MANIFEST = "manifest.yml"
13
+
14
+ YES_SET = Set.new(["y", "Y", "yes", "YES"])
15
+
16
+ # take a block and call it once for each app to push/update.
17
+ # with @application and @app_info set appropriately
18
+ def each_app(panic=true)
19
+ if @manifest and all_apps = @manifest["applications"]
20
+ where = File.expand_path(@path)
21
+ single = false
22
+
23
+ all_apps.each do |path, info|
24
+ app = File.expand_path("../" + path, manifest_file)
25
+ if where.start_with?(app)
26
+ @application = app
27
+ @app_info = info
28
+ yield info["name"]
29
+ single = true
30
+ break
31
+ end
32
+ end
33
+
34
+ unless single
35
+ if where == File.expand_path("../", manifest_file)
36
+ ordered_by_deps(all_apps).each do |path, info|
37
+ app = File.expand_path("../" + path, manifest_file)
38
+ @application = app
39
+ @app_info = info
40
+ yield info["name"]
41
+ end
42
+ else
43
+ err "Path '#{@path}' is not known to manifest '#{manifest_file}'."
44
+ end
45
+ end
46
+ else
47
+ @application = @path
48
+ @app_info = @manifest
49
+ if @app_info
50
+ yield @app_info["name"]
51
+ elsif panic
52
+ err "No applications."
53
+ end
54
+ end
55
+
56
+ nil
57
+ ensure
58
+ @application = nil
59
+ @app_info = nil
60
+ end
61
+
62
+ def interact(many=false)
63
+ @manifest ||= {}
64
+ configure_app(many)
65
+ end
66
+
67
+ def target_manifest
68
+ @options[:manifest] || MANIFEST
69
+ end
70
+
71
+ def save_manifest(save_to = nil)
72
+ save_to ||= target_manifest
73
+
74
+ File.open(save_to, "w") do |f|
75
+ f.write @manifest.to_yaml
76
+ end
77
+
78
+ say "Manifest written to #{save_to}."
79
+ end
80
+
81
+ def configure_app(many=false)
82
+ name = manifest("name") ||
83
+ set(ask("Application Name", :default => manifest("name")), "name")
84
+
85
+ if manifest "framework"
86
+ framework = VMC::Cli::Framework.lookup_by_framework manifest("framework","name")
87
+ else
88
+ framework = detect_framework
89
+ set framework.name, "framework", "name"
90
+ set(
91
+ { "mem" => framework.mem,
92
+ "description" => framework.description,
93
+ "exec" => framework.exec
94
+ },
95
+ "framework",
96
+ "info"
97
+ )
98
+ end
99
+
100
+ default_runtime = manifest "runtime"
101
+ if not default_runtime
102
+ default_runtime = framework.default_runtime(@application)
103
+ set(detect_runtime(default_runtime), "runtime") if framework.prompt_for_runtime?
104
+ end
105
+ default_command = manifest "command"
106
+ set ask("Start Command", :default => default_command), "command" if framework.require_start_command?
107
+
108
+ if client.infra_supported?
109
+ infra = @options[:infra] || manifest("infra") ||
110
+ client.infra_name_for_description(
111
+ ask("Select Infrastructure",:indexed => true, :choices => client.infra_descriptions))
112
+ set infra.dup, "infra"
113
+ client.infra = infra
114
+ end
115
+
116
+ url_template = manifest("url") || DEFAULTS["url"]
117
+ url_resolved = url_template.dup
118
+ resolve_lexically(url_resolved)
119
+
120
+ if !framework.require_url?
121
+ url_resolved = "None"
122
+ end
123
+ url = ask("Application Deployed URL", :default => url_resolved)
124
+
125
+ if url == url_resolved && url != "None"
126
+ url = url_template
127
+ end
128
+
129
+ # common error case is for prompted users to answer y or Y or yes or
130
+ # YES to this ask() resulting in an unintended URL of y. Special
131
+ # case this common error
132
+ url = url_resolved if YES_SET.member? url
133
+
134
+ if(url == "None")
135
+ url = nil
136
+ end
137
+
138
+ set url, "url"
139
+
140
+ default_mem = manifest("mem")
141
+ default_mem = framework.memory(manifest("runtime")) if not default_mem
142
+ set ask(
143
+ "Memory reservation",
144
+ :default =>
145
+ default_mem ||
146
+ DEFAULTS["mem"],
147
+ :choices => ["128M", "256M", "512M", "1G", "2G"]
148
+ ), "mem"
149
+
150
+ set ask(
151
+ "How many instances?",
152
+ :default => manifest("instances") || DEFAULTS["instances"]
153
+ ), "instances"
154
+
155
+ unless manifest "services"
156
+ user_services = services_for_infra(manifest("infra"))
157
+ user_services.sort! {|a, b| a[:name] <=> b[:name] }
158
+
159
+ unless user_services.empty?
160
+ if ask "Bind existing services to '#{name}'?", :default => false
161
+ bind_services(user_services)
162
+ end
163
+ end
164
+
165
+ services = client.services_info
166
+ unless services.empty?
167
+ if ask "Create services to bind to '#{name}'?", :default => false
168
+ create_services(services.values.collect(&:keys).flatten)
169
+ end
170
+ end
171
+ end
172
+
173
+ if many and ask("Configure for another application?", :default => false)
174
+ @application = ask "Application path?"
175
+ configure_app
176
+ end
177
+ end
178
+
179
+ def set(what, *where)
180
+ where.unshift "applications", @application
181
+
182
+ which = @manifest
183
+ where.each_with_index do |k, i|
184
+ if i + 1 == where.size
185
+ which[k] = what
186
+ else
187
+ which = (which[k] ||= {})
188
+ end
189
+ end
190
+
191
+ what
192
+ end
193
+
194
+ # Detect the appropriate framework.
195
+ def detect_framework(prompt_ok = true)
196
+ framework = VMC::Cli::Framework.detect(@application, frameworks_info)
197
+ framework_correct = ask("Detected a #{framework}, is this correct?", :default => true) if prompt_ok && framework
198
+ if prompt_ok && (framework.nil? || !framework_correct)
199
+ display "#{"[WARNING]".yellow} Can't determine the Application Type." unless framework
200
+ framework = nil if !framework_correct
201
+ framework = VMC::Cli::Framework.lookup(
202
+ ask(
203
+ "Select Application Type",
204
+ :indexed => true,
205
+ :default => framework,
206
+ :choices => VMC::Cli::Framework.known_frameworks(frameworks_info)
207
+ )
208
+ )
209
+ display "Selected #{framework}"
210
+ end
211
+
212
+ framework
213
+ end
214
+
215
+ # Detect the appropriate runtime.
216
+ def detect_runtime(default, prompt_ok=true)
217
+ runtime = nil
218
+ runtime_keys=[]
219
+ runtimes_info.keys.each {|runtime_key| runtime_keys << runtime_key.dup }
220
+ runtime_keys.sort!
221
+ if prompt_ok
222
+ runtime = ask(
223
+ "Select Runtime",
224
+ :indexed => true,
225
+ :default => default,
226
+ :choices => runtime_keys
227
+ )
228
+ display "Selected #{runtime}"
229
+ end
230
+ runtime
231
+ end
232
+
233
+ def bind_services(user_services, chosen = 0)
234
+ svcname = ask(
235
+ "Which one?",
236
+ :indexed => true,
237
+ :choices => user_services.collect { |p| p[:name] })
238
+
239
+ svc = user_services.find { |p| p[:name] == svcname }
240
+
241
+ set svc[:vendor], "services", svcname, "type"
242
+
243
+ if chosen + 1 < user_services.size && ask("Bind another?", :default => false)
244
+ bind_services(user_services, chosen + 1)
245
+ end
246
+ end
247
+
248
+ def create_services(services)
249
+ svcs = services.collect(&:to_s).sort!
250
+
251
+ configure_service(
252
+ ask(
253
+ "What kind of service?",
254
+ :indexed => true,
255
+ :choices => svcs
256
+ )
257
+ )
258
+
259
+ if ask "Create another?", :default => false
260
+ create_services(services)
261
+ end
262
+ end
263
+
264
+ def configure_service(vendor)
265
+ default_name = random_service_name(vendor)
266
+ name = ask "Specify the name of the service", :default => default_name
267
+
268
+ set vendor, "services", name, "type"
269
+ end
270
+
271
+ private
272
+ def services_for_infra(infra)
273
+ if client.infra_supported?
274
+ client.services.select { |s| s[:infra] && s[:infra][:provider] == manifest("infra") }
275
+ else
276
+ client.services
277
+ end
278
+ end
279
+
280
+ def ordered_by_deps(apps, abspaths = nil, processed = Set[])
281
+ unless abspaths
282
+ abspaths = {}
283
+ apps.each do |p, i|
284
+ ep = File.expand_path("../" + p, manifest_file)
285
+ abspaths[ep] = i
286
+ end
287
+ end
288
+
289
+ ordered = []
290
+ apps.each do |path, info|
291
+ epath = File.expand_path("../" + path, manifest_file)
292
+
293
+ if deps = info["depends-on"]
294
+ dep_apps = {}
295
+ deps.each do |dep|
296
+ edep = File.expand_path("../" + dep, manifest_file)
297
+
298
+ err "Circular dependency detected." if processed.include? edep
299
+
300
+ dep_apps[dep] = abspaths[edep]
301
+ end
302
+
303
+ processed.add(epath)
304
+
305
+ ordered += ordered_by_deps(dep_apps, abspaths, processed)
306
+ ordered << [path, info]
307
+ elsif not processed.include? epath
308
+ ordered << [path, info]
309
+ processed.add(epath)
310
+ end
311
+ end
312
+
313
+ ordered
314
+ end
315
+
316
+ end
data/lib/cli/runner.rb ADDED
@@ -0,0 +1,568 @@
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
+ # micro cloud options
63
+ opts.on('--vmx FILE') { |file| @options[:vmx] = file }
64
+ opts.on('--vmrun FILE') { |file| @options[:vmrun] = file }
65
+ opts.on('--save') { @options[:save] = true }
66
+
67
+ # Don't use builtin zip
68
+ opts.on('--no-zip') { @options[:nozip] = true }
69
+ opts.on('--nozip') { @options[:nozip] = true }
70
+
71
+ opts.on('--no-resources') { @options[:noresources] = true }
72
+ opts.on('--noresources') { @options[:noresources] = true }
73
+
74
+ opts.on('--no-color') { @options[:colorize] = false }
75
+ opts.on('--verbose') { @options[:verbose] = true }
76
+
77
+ opts.on('-n','--no-prompt') { @options[:noprompts] = true }
78
+ opts.on('--noprompt') { @options[:noprompts] = true }
79
+ opts.on('--non-interactive') { @options[:noprompts] = true }
80
+
81
+ opts.on('--prefix') { @options[:prefixlogs] = true }
82
+ opts.on('--prefix-logs') { @options[:prefixlogs] = true }
83
+ opts.on('--prefixlogs') { @options[:prefixlogs] = true }
84
+
85
+ opts.on('--json') { @options[:json] = true }
86
+
87
+ opts.on('-v', '--version') { set_cmd(:misc, :version) }
88
+ opts.on('-h', '--help') { puts "#{command_usage}\n"; exit }
89
+
90
+ opts.on('--port PORT') { |port| @options[:port] = port }
91
+
92
+ opts.on('--runtime RUNTIME') { |rt| @options[:runtime] = rt }
93
+
94
+ # deprecated
95
+ opts.on('--exec EXEC') { |exec| @options[:exec] = exec }
96
+ opts.on('--noframework') { @options[:noframework] = true }
97
+ opts.on('--canary') { @options[:canary] = true }
98
+
99
+ # Proxying for another user, requires admin privileges
100
+ opts.on('-u PROXY') { |proxy| @options[:proxy] = proxy }
101
+
102
+ # Select infrastructure
103
+ opts.on('--infra INFRA') { |infra| @options[:infra] = infra }
104
+
105
+ opts.on_tail('--options') { puts "#{opts}\n"; exit }
106
+ end
107
+ instances_delta_arg = check_instances_delta!
108
+ @args = opts_parser.parse!(@args)
109
+ @args.concat instances_delta_arg
110
+ convert_options!
111
+ self
112
+ end
113
+
114
+ def check_instances_delta!
115
+ return unless @args
116
+ instance_args = @args.select { |arg| /^[-]\d+$/ =~ arg } || []
117
+ @args.delete_if { |arg| instance_args.include? arg}
118
+ instance_args
119
+ end
120
+
121
+ def display_help
122
+ puts command_usage
123
+ exit
124
+ end
125
+
126
+ def convert_options!
127
+ # make sure certain options are valid and in correct form.
128
+ @options[:instances] = Integer(@options[:instances]) if @options[:instances]
129
+ end
130
+
131
+ def set_cmd(namespace, action, args_range=0)
132
+ return if @help_only
133
+ unless args_range == "*" || args_range.is_a?(Range)
134
+ args_range = (args_range.to_i..args_range.to_i)
135
+ end
136
+
137
+ if args_range == "*" || args_range.include?(@args.size)
138
+ @namespace = namespace
139
+ @action = action
140
+ else
141
+ @exit_status = false
142
+ if @args.size > args_range.last
143
+ usage_error("Too many arguments for [#{action}]: %s" % [ @args[args_range.last..-1].map{|a| "'#{a}'"}.join(', ') ])
144
+ else
145
+ usage_error("Not enough arguments for [#{action}]")
146
+ end
147
+ end
148
+ end
149
+
150
+ def parse_command!
151
+ # just return if already set, happends with -v, -h
152
+ return if @namespace && @action
153
+
154
+ verb = @args.shift
155
+ case verb
156
+
157
+ when 'version'
158
+ usage('sys version')
159
+ set_cmd(:misc, :version)
160
+
161
+ when 'target'
162
+ usage('sys target [url] [--url]')
163
+ if @args.size == 1
164
+ set_cmd(:misc, :set_target, 1)
165
+ else
166
+ set_cmd(:misc, :target)
167
+ end
168
+
169
+ when 'targets'
170
+ usage('sys targets')
171
+ set_cmd(:misc, :targets)
172
+
173
+ when 'tokens'
174
+ usage('sys tokens')
175
+ set_cmd(:misc, :tokens)
176
+
177
+ when 'info'
178
+ usage('sys info')
179
+ set_cmd(:misc, :info)
180
+
181
+ when 'runtimes'
182
+ usage('sys runtimes')
183
+ set_cmd(:misc, :runtimes)
184
+
185
+ when 'frameworks'
186
+ usage('sys frameworks')
187
+ set_cmd(:misc, :frameworks)
188
+
189
+ when 'infras'
190
+ usage('sys infras')
191
+ set_cmd(:misc, :infras)
192
+
193
+ when 'user'
194
+ usage('sys user')
195
+ set_cmd(:user, :info)
196
+
197
+ when 'login'
198
+ usage('sys login [email] [--email EMAIL] [--passwd PASS]')
199
+ if @args.size == 1
200
+ set_cmd(:user, :login, 1)
201
+ else
202
+ set_cmd(:user, :login)
203
+ end
204
+
205
+ when 'logout'
206
+ usage('sys logout')
207
+ set_cmd(:user, :logout)
208
+
209
+ when 'passwd'
210
+ usage('sys passwd')
211
+ if @args.size == 1
212
+ set_cmd(:user, :change_password, 1)
213
+ else
214
+ set_cmd(:user, :change_password)
215
+ end
216
+
217
+ when 'add-user', 'add_user', 'create_user', 'create-user', 'register'
218
+ usage('sys add-user [user] [--email EMAIL] [--passwd PASS]')
219
+ if @args.size == 1
220
+ set_cmd(:admin, :add_user, 1)
221
+ else
222
+ set_cmd(:admin, :add_user)
223
+ end
224
+
225
+ when 'delete-user', 'delete_user', 'unregister'
226
+ usage('sys delete-user <user>')
227
+ set_cmd(:admin, :delete_user, 1)
228
+
229
+ when 'users'
230
+ usage('sys users')
231
+ set_cmd(:admin, :users)
232
+
233
+ when 'apps'
234
+ usage('sys apps')
235
+ set_cmd(:apps, :apps)
236
+
237
+ when 'list'
238
+ usage('sys list')
239
+ set_cmd(:apps, :list)
240
+
241
+ when 'start'
242
+ usage('sys start <appname>')
243
+ set_cmd(:apps, :start, @args.size == 1 ? 1 : 0)
244
+
245
+ when 'stop'
246
+ usage('sys stop <appname>')
247
+ set_cmd(:apps, :stop, @args.size == 1 ? 1 : 0)
248
+
249
+ when 'restart'
250
+ usage('sys restart <appname>')
251
+ set_cmd(:apps, :restart, @args.size == 1 ? 1 : 0)
252
+
253
+ when 'mem'
254
+ usage('sys mem <appname> [memsize]')
255
+ if @args.size == 2
256
+ set_cmd(:apps, :mem, 2)
257
+ else
258
+ set_cmd(:apps, :mem, 1)
259
+ end
260
+
261
+ when 'stats'
262
+ usage('sys stats <appname>')
263
+ set_cmd(:apps, :stats, @args.size == 1 ? 1 : 0)
264
+
265
+ when 'map'
266
+ usage('sys map <appname> <url>')
267
+ set_cmd(:apps, :map, 2)
268
+
269
+ when 'unmap'
270
+ usage('sys unmap <appname> <url>')
271
+ set_cmd(:apps, :unmap, 2)
272
+
273
+ when 'delete'
274
+ usage('sys delete <appname>')
275
+ if @options[:all] && @args.size == 0
276
+ set_cmd(:apps, :delete)
277
+ else
278
+ set_cmd(:apps, :delete, 1)
279
+ end
280
+
281
+ when 'files'
282
+ usage('sys files <appname> [path] [--instance N] [--all] [--prefix]')
283
+ if @args.size == 1
284
+ set_cmd(:apps, :files, 1)
285
+ else
286
+ set_cmd(:apps, :files, 2)
287
+ end
288
+
289
+ when 'download'
290
+ usage('sys download <appname> [path]')
291
+ if @args.size == 1
292
+ set_cmd(:apps, :download, 1)
293
+ else
294
+ set_cmd(:apps, :download, 2)
295
+ end
296
+
297
+ when 'pull'
298
+ usage('sys pull <appname> [path]')
299
+ if @args.size == 1
300
+ set_cmd(:apps, :pull, 1)
301
+ else
302
+ set_cmd(:apps, :pull, 2)
303
+ end
304
+
305
+ when 'logs'
306
+ usage('sys logs <appname> [--instance N] [--all] [--prefix]')
307
+ set_cmd(:apps, :logs, 1)
308
+
309
+ when 'instances', 'scale'
310
+ if @args.size > 1
311
+ usage('sys instances <appname> <num|delta>')
312
+ set_cmd(:apps, :instances, 2)
313
+ else
314
+ usage('sys instances <appname>')
315
+ set_cmd(:apps, :instances, 1)
316
+ end
317
+
318
+ when 'crashes'
319
+ usage('sys crashes <appname>')
320
+ set_cmd(:apps, :crashes, 1)
321
+
322
+ when 'crashlogs'
323
+ usage('sys crashlogs <appname>')
324
+ set_cmd(:apps, :crashlogs, 1)
325
+
326
+ when 'push'
327
+ usage('sys push [appname] [--path PATH] [--url URL] [--instances N] [--mem] [--runtime RUNTIME] [--no-start] [--infra infraname]')
328
+ if @args.size == 1
329
+ set_cmd(:apps, :push, 1)
330
+ else
331
+ set_cmd(:apps, :push, 0)
332
+ end
333
+
334
+ when 'update'
335
+ usage('sys update <appname> [--path PATH]')
336
+ set_cmd(:apps, :update, @args.size == 1 ? 1 : 0)
337
+
338
+ when 'services'
339
+ usage('sys services')
340
+ set_cmd(:services, :services)
341
+
342
+ when 'env'
343
+ usage('sys env <appname>')
344
+ set_cmd(:apps, :environment, 1)
345
+
346
+ when 'env-add'
347
+ usage('sys env-add <appname> <variable[=]value>')
348
+ if @args.size == 2
349
+ set_cmd(:apps, :environment_add, 2)
350
+ elsif @args.size == 3
351
+ set_cmd(:apps, :environment_add, 3)
352
+ end
353
+
354
+ when 'env-del'
355
+ usage('sys env-del <appname> <variable>')
356
+ set_cmd(:apps, :environment_del, 2)
357
+
358
+ when 'create-service', 'create_service'
359
+ usage('sys create-service [service] [servicename] [appname] [--name servicename] [--bind appname] [--infra infraname]')
360
+ set_cmd(:services, :create_service) if @args.size == 0
361
+ set_cmd(:services, :create_service, 1) if @args.size == 1
362
+ set_cmd(:services, :create_service, 2) if @args.size == 2
363
+ set_cmd(:services, :create_service, 3) if @args.size == 3
364
+
365
+ when 'delete-service', 'delete_service'
366
+ usage('sys delete-service <service>')
367
+ if @args.size == 1
368
+ set_cmd(:services, :delete_service, 1)
369
+ else
370
+ set_cmd(:services, :delete_service)
371
+ end
372
+
373
+ when 'bind-service', 'bind_service'
374
+ usage('sys bind-service <servicename> <appname>')
375
+ set_cmd(:services, :bind_service, 2)
376
+
377
+ when 'unbind-service', 'unbind_service'
378
+ usage('sys unbind-service <servicename> <appname>')
379
+ set_cmd(:services, :unbind_service, 2)
380
+
381
+ when 'clone-services'
382
+ usage('sys clone-services <src-app> <dest-app>')
383
+ set_cmd(:services, :clone_services, 2)
384
+
385
+ when 'export-service'
386
+ usage('sys export-service <service-name>')
387
+ set_cmd(:services, :export_service, 1)
388
+
389
+ when 'import-service'
390
+ usage('sys import-service <service-name> <url>')
391
+ set_cmd(:services, :import_service, 2)
392
+
393
+ when 'clone'
394
+ usage('sys clone <src-app> <dest-app> [<infra>]')
395
+ set_cmd(:apps, :clone, 2) if @args.size == 2
396
+ set_cmd(:apps, :clone, 3) if @args.size == 3
397
+
398
+ when 'aliases'
399
+ usage('sys aliases')
400
+ set_cmd(:misc, :aliases)
401
+
402
+ when 'alias'
403
+ usage('sys alias <alias[=]command>')
404
+ if @args.size == 1
405
+ set_cmd(:misc, :alias, 1)
406
+ elsif @args.size == 2
407
+ set_cmd(:misc, :alias, 2)
408
+ end
409
+
410
+ when 'unalias'
411
+ usage('sys unalias <alias>')
412
+ set_cmd(:misc, :unalias, 1)
413
+
414
+ when 'tunnel'
415
+ usage('sys tunnel [servicename] [clientcmd] [--port port]')
416
+ set_cmd(:services, :tunnel, 0) if @args.size == 0
417
+ set_cmd(:services, :tunnel, 1) if @args.size == 1
418
+ set_cmd(:services, :tunnel, 2) if @args.size == 2
419
+
420
+ when 'rails-console'
421
+ usage('sys rails-console <appname>')
422
+ set_cmd(:apps, :console, 1)
423
+
424
+ when 'micro'
425
+ usage('sys micro <online|offline|status> [--password password] [--save] [--vmx file] [--vmrun executable]')
426
+ if %w[online offline status].include?(@args[0])
427
+ set_cmd(:micro, @args[0].to_sym, 1)
428
+ end
429
+
430
+ when 'help'
431
+ display_help if @args.size == 0
432
+ @help_only = true
433
+ parse_command!
434
+
435
+ when 'usage'
436
+ display basic_usage
437
+ exit(true)
438
+
439
+ when 'options'
440
+ # Simulate --options
441
+ @args = @args.unshift('--options')
442
+ parse_options!
443
+
444
+ when 'manifest'
445
+ usage('sys manifest')
446
+ set_cmd(:manifest, :edit)
447
+
448
+ when 'extend-manifest'
449
+ usage('sys extend-manifest')
450
+ set_cmd(:manifest, :extend, 1)
451
+
452
+ else
453
+ if verb
454
+ display "sys: Unknown command [#{verb}]"
455
+ display basic_usage
456
+ exit(false)
457
+ end
458
+ end
459
+ end
460
+
461
+ def process_aliases!
462
+ return if @args.empty?
463
+ aliases = VMC::Cli::Config.aliases
464
+ aliases.each_pair do |k,v|
465
+ if @args[0] == k
466
+ display "[#{@args[0]} aliased to #{aliases.invert[key]}]" if @options[:verbose]
467
+ @args[0] = v
468
+ break;
469
+ end
470
+ end
471
+ end
472
+
473
+ def usage(msg = nil)
474
+ @usage = msg if msg
475
+ @usage
476
+ end
477
+
478
+ def usage_error(msg = nil)
479
+ @usage_error = msg if msg
480
+ @usage_error
481
+ end
482
+
483
+ def run
484
+
485
+ trap('TERM') { print "\nTerminated\n"; exit(false)}
486
+
487
+ parse_options!
488
+
489
+ @options[:colorize] = false unless STDOUT.tty?
490
+
491
+ VMC::Cli::Config.colorize = @options.delete(:colorize)
492
+ VMC::Cli::Config.nozip = @options.delete(:nozip)
493
+ VMC::Cli::Config.trace = @options.delete(:trace)
494
+ VMC::Cli::Config.output ||= STDOUT unless @options[:quiet]
495
+ VMC::Cli::Config.infra = @options[:infra]
496
+
497
+ process_aliases!
498
+ parse_command!
499
+
500
+ if @namespace && @action
501
+ cmd = VMC::Cli::Command.const_get(@namespace.to_s.capitalize)
502
+ cmd.new(@options).send(@action, *@args.collect(&:dup))
503
+ elsif @help_only || @usage
504
+ display_usage
505
+ else
506
+ display basic_usage
507
+ exit(false)
508
+ end
509
+
510
+ rescue OptionParser::InvalidOption => e
511
+ puts(e.message.red)
512
+ puts("\n")
513
+ puts(basic_usage)
514
+ @exit_status = false
515
+ rescue OptionParser::AmbiguousOption => e
516
+ puts(e.message.red)
517
+ puts("\n")
518
+ puts(basic_usage)
519
+ @exit_status = false
520
+ rescue VMC::Client::AuthError => e
521
+ if VMC::Cli::Config.auth_token.nil?
522
+ puts "Login Required".red
523
+ else
524
+ puts "Not Authorized".red
525
+ end
526
+ @exit_status = false
527
+ rescue VMC::Client::TargetError, VMC::Client::NotFound, VMC::Client::BadTarget => e
528
+ puts e.message.red
529
+ @exit_status = false
530
+ rescue VMC::Client::HTTPException => e
531
+ puts e.message.red
532
+ @exit_status = false
533
+ rescue VMC::Cli::GracefulExit => e
534
+ # Redirected commands end up generating this exception (kind of goto)
535
+ rescue VMC::Cli::CliExit => e
536
+ puts e.message.red
537
+ @exit_status = false
538
+ rescue VMC::Cli::CliError => e
539
+ say("Error #{e.error_code}: #{e.message}".red)
540
+ @exit_status = false
541
+ rescue SystemExit => e
542
+ @exit_status = e.success?
543
+ rescue SyntaxError => e
544
+ puts e.message.red
545
+ puts e.backtrace
546
+ @exit_status = false
547
+ rescue Interrupt => e
548
+ say("\nInterrupted".red)
549
+ @exit_status = false
550
+ rescue Exception => e
551
+ puts e.message.red
552
+ puts e.backtrace
553
+ @exit_status = false
554
+ ensure
555
+ say("\n")
556
+ @exit_status == true if @exit_status.nil?
557
+ if @options[:verbose]
558
+ if @exit_status
559
+ puts "[#{@namespace}:#{@action}] SUCCEEDED".green
560
+ else
561
+ puts "[#{@namespace}:#{@action}] FAILED".red
562
+ end
563
+ say("\n")
564
+ end
565
+ exit(@exit_status)
566
+ end
567
+
568
+ end