vmc 0.0.8 → 0.2.4
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/LICENSE +8 -3
- data/README.md +83 -0
- data/Rakefile +11 -65
- data/bin/vmc +3 -2
- data/lib/cli/commands/admin.rb +57 -0
- data/lib/cli/commands/apps.rb +828 -0
- data/lib/cli/commands/base.rb +56 -0
- data/lib/cli/commands/misc.rb +99 -0
- data/lib/cli/commands/services.rb +84 -0
- data/lib/cli/commands/user.rb +60 -0
- data/lib/cli/config.rb +109 -0
- data/lib/cli/core_ext.rb +119 -0
- data/lib/cli/errors.rb +19 -0
- data/lib/cli/frameworks.rb +97 -0
- data/lib/cli/runner.rb +437 -0
- data/lib/cli/services_helper.rb +74 -0
- data/lib/cli/usage.rb +94 -0
- data/lib/cli/version.rb +5 -0
- data/lib/cli/zip_util.rb +61 -0
- data/lib/cli.rb +30 -0
- data/lib/vmc/client.rb +415 -0
- data/lib/vmc/const.rb +19 -0
- data/lib/vmc.rb +2 -1589
- data/spec/assets/app_info.txt +9 -0
- data/spec/assets/app_listings.txt +9 -0
- data/spec/assets/bad_create_app.txt +9 -0
- data/spec/assets/delete_app.txt +9 -0
- data/spec/assets/global_service_listings.txt +9 -0
- data/spec/assets/good_create_app.txt +9 -0
- data/spec/assets/good_create_service.txt +9 -0
- data/spec/assets/info_authenticated.txt +27 -0
- data/spec/assets/info_return.txt +15 -0
- data/spec/assets/info_return_bad.txt +16 -0
- data/spec/assets/login_fail.txt +9 -0
- data/spec/assets/login_success.txt +9 -0
- data/spec/assets/sample_token.txt +1 -0
- data/spec/assets/service_already_exists.txt +9 -0
- data/spec/assets/service_listings.txt +9 -0
- data/spec/assets/service_not_found.txt +9 -0
- data/spec/assets/user_info.txt +9 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/unit/cli_opts_spec.rb +73 -0
- data/spec/unit/client_spec.rb +284 -0
- metadata +114 -71
- data/README +0 -58
- data/lib/parse.rb +0 -719
- data/lib/vmc_base.rb +0 -205
- data/vendor/gems/httpclient/VERSION +0 -1
- data/vendor/gems/httpclient/lib/http-access2/cookie.rb +0 -1
- data/vendor/gems/httpclient/lib/http-access2/http.rb +0 -1
- data/vendor/gems/httpclient/lib/http-access2.rb +0 -53
- data/vendor/gems/httpclient/lib/httpclient/auth.rb +0 -522
- data/vendor/gems/httpclient/lib/httpclient/cacert.p7s +0 -1579
- data/vendor/gems/httpclient/lib/httpclient/cacert_sha1.p7s +0 -1579
- data/vendor/gems/httpclient/lib/httpclient/connection.rb +0 -84
- data/vendor/gems/httpclient/lib/httpclient/cookie.rb +0 -562
- data/vendor/gems/httpclient/lib/httpclient/http.rb +0 -867
- data/vendor/gems/httpclient/lib/httpclient/session.rb +0 -864
- data/vendor/gems/httpclient/lib/httpclient/ssl_config.rb +0 -417
- data/vendor/gems/httpclient/lib/httpclient/timeout.rb +0 -136
- data/vendor/gems/httpclient/lib/httpclient/util.rb +0 -86
- data/vendor/gems/httpclient/lib/httpclient.rb +0 -1020
- data/vendor/gems/httpclient/lib/tags +0 -908
data/lib/cli/runner.rb
ADDED
@@ -0,0 +1,437 @@
|
|
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('--app NAME') { |name| @options[:name] = name }
|
35
|
+
opts.on('--name NAME') { |name| @options[:name] = name }
|
36
|
+
opts.on('--bind BIND') { |bind| @options[:bind] = bind }
|
37
|
+
opts.on('--instance INST') { |inst| @options[:instance] = inst }
|
38
|
+
opts.on('--instances INST') { |inst| @options[:instances] = inst }
|
39
|
+
opts.on('--url URL') { |url| @options[:url] = url }
|
40
|
+
opts.on('--mem MEM') { |mem| @options[:mem] = mem }
|
41
|
+
opts.on('--path PATH') { |path| @options[:path] = path }
|
42
|
+
opts.on('--no-start') { @options[:nostart] = true }
|
43
|
+
opts.on('--nostart') { @options[:nostart] = true }
|
44
|
+
opts.on('--force') { @options[:force] = true }
|
45
|
+
opts.on('--all') { @options[:all] = true }
|
46
|
+
|
47
|
+
# generic tracing and debugging
|
48
|
+
opts.on('-t', '--trace') { @options[:trace] = true }
|
49
|
+
opts.on('-q', '--quiet') { @options[:quiet] = true }
|
50
|
+
|
51
|
+
# Don't use builtin zip
|
52
|
+
opts.on('--no-zip') { @options[:nozip] = true }
|
53
|
+
opts.on('--nozip') { @options[:nozip] = true }
|
54
|
+
|
55
|
+
opts.on('--no-resources') { @options[:noresources] = true }
|
56
|
+
opts.on('--noresources') { @options[:noresources] = true }
|
57
|
+
|
58
|
+
opts.on('--no-color') { @options[:colorize] = false }
|
59
|
+
opts.on('--verbose') { @options[:verbose] = true }
|
60
|
+
|
61
|
+
opts.on('-n','--no-prompt') { @options[:noprompts] = true }
|
62
|
+
opts.on('--noprompt') { @options[:noprompts] = true }
|
63
|
+
opts.on('--non-interactive') { @options[:noprompts] = true }
|
64
|
+
|
65
|
+
opts.on('--prefix') { @options[:prefixlogs] = true }
|
66
|
+
opts.on('--prefix-logs') { @options[:prefixlogs] = true }
|
67
|
+
opts.on('--prefixlogs') { @options[:prefixlogs] = true }
|
68
|
+
|
69
|
+
opts.on('--json') { @options[:json] = true }
|
70
|
+
|
71
|
+
opts.on('-v', '--version') { set_cmd(:misc, :version) }
|
72
|
+
opts.on('-h', '--help') { puts "#{command_usage}\n"; exit }
|
73
|
+
|
74
|
+
# deprecated
|
75
|
+
opts.on('--exec EXEC') { |exec| @options[:exec] = exec }
|
76
|
+
opts.on('--noframework') { @options[:noframework] = true }
|
77
|
+
opts.on('--canary') { @options[:canary] = true }
|
78
|
+
|
79
|
+
# Proxying for another user, requires admin privileges
|
80
|
+
opts.on('-u PROXY') { |proxy| @options[:proxy] = proxy }
|
81
|
+
|
82
|
+
opts.on_tail('--options') { puts "#{opts}\n"; exit }
|
83
|
+
end
|
84
|
+
@args = opts_parser.parse!(@args)
|
85
|
+
convert_options!
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def display_help
|
90
|
+
puts command_usage
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
|
94
|
+
def convert_options!
|
95
|
+
# make sure certain options are valid and in correct form.
|
96
|
+
@options[:instances] = Integer(@options[:instances]) if @options[:instances]
|
97
|
+
@options[:instance] = Integer(@options[:instance]) if @options[:instance]
|
98
|
+
end
|
99
|
+
|
100
|
+
def set_cmd(namespace, action, args_range=0)
|
101
|
+
return if @help_only
|
102
|
+
unless args_range == "*" || args_range.is_a?(Range)
|
103
|
+
args_range = (args_range.to_i..args_range.to_i)
|
104
|
+
end
|
105
|
+
|
106
|
+
if args_range == "*" || args_range.include?(@args.size)
|
107
|
+
@namespace = namespace
|
108
|
+
@action = action
|
109
|
+
else
|
110
|
+
@exit_status = false
|
111
|
+
if @args.size > args_range.last
|
112
|
+
usage_error("Too many arguments for [#{action}]: %s" % [ @args[args_range.last..-1].map{|a| "'#{a}'"}.join(', ') ])
|
113
|
+
else
|
114
|
+
usage_error("Not enough arguments for [#{action}]")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def parse_command!
|
120
|
+
# just return if already set, happends with -v, -h
|
121
|
+
return if @namespace && @action
|
122
|
+
|
123
|
+
verb = @args.shift
|
124
|
+
case verb
|
125
|
+
|
126
|
+
when 'version'
|
127
|
+
usage('vmc version')
|
128
|
+
set_cmd(:misc, :version)
|
129
|
+
|
130
|
+
when 'target'
|
131
|
+
usage('vmc target [url] [--url]')
|
132
|
+
if @args.size == 1
|
133
|
+
set_cmd(:misc, :set_target, 1)
|
134
|
+
else
|
135
|
+
set_cmd(:misc, :target)
|
136
|
+
end
|
137
|
+
|
138
|
+
when 'targets'
|
139
|
+
usage('vmc targets')
|
140
|
+
set_cmd(:misc, :targets)
|
141
|
+
|
142
|
+
when 'tokens'
|
143
|
+
usage('vmc tokens')
|
144
|
+
set_cmd(:misc, :tokens)
|
145
|
+
|
146
|
+
when 'info'
|
147
|
+
usage('vmc info')
|
148
|
+
set_cmd(:misc, :info)
|
149
|
+
|
150
|
+
when 'user'
|
151
|
+
usage('vmc user')
|
152
|
+
set_cmd(:user, :info)
|
153
|
+
|
154
|
+
when 'login'
|
155
|
+
usage('vmc login [email] [--email EMAIL] [--passwd PASS]')
|
156
|
+
if @args.size == 1
|
157
|
+
set_cmd(:user, :login, 1)
|
158
|
+
else
|
159
|
+
set_cmd(:user, :login)
|
160
|
+
end
|
161
|
+
|
162
|
+
when 'logout'
|
163
|
+
usage('vmc logout')
|
164
|
+
set_cmd(:user, :logout)
|
165
|
+
|
166
|
+
when 'passwd'
|
167
|
+
usage('vmc passwd')
|
168
|
+
if @args.size == 1
|
169
|
+
set_cmd(:user, :change_password, 1)
|
170
|
+
else
|
171
|
+
set_cmd(:user, :change_password)
|
172
|
+
end
|
173
|
+
|
174
|
+
when 'add-user', 'add_user', 'create_user', 'create-user', 'register'
|
175
|
+
usage('vmc add-user [user] [--email EMAIL] [--passwd PASS]')
|
176
|
+
if @args.size == 1
|
177
|
+
set_cmd(:admin, :add_user, 1)
|
178
|
+
else
|
179
|
+
set_cmd(:admin, :add_user)
|
180
|
+
end
|
181
|
+
|
182
|
+
when 'delete-user', 'delete_user', 'unregister'
|
183
|
+
usage('vmc delete-user <user>')
|
184
|
+
set_cmd(:admin, :delete_user, 1)
|
185
|
+
|
186
|
+
when 'apps'
|
187
|
+
usage('vmc apps')
|
188
|
+
set_cmd(:apps, :apps)
|
189
|
+
|
190
|
+
when 'list'
|
191
|
+
usage('vmc list')
|
192
|
+
set_cmd(:apps, :list)
|
193
|
+
|
194
|
+
when 'start'
|
195
|
+
usage('vmc start <appname>')
|
196
|
+
set_cmd(:apps, :start, 1)
|
197
|
+
|
198
|
+
when 'stop'
|
199
|
+
usage('vmc stop <appname>')
|
200
|
+
set_cmd(:apps, :stop, 1)
|
201
|
+
|
202
|
+
when 'restart'
|
203
|
+
usage('vmc restart <appname>')
|
204
|
+
set_cmd(:apps, :restart, 1)
|
205
|
+
|
206
|
+
when 'rename'
|
207
|
+
usage('vmc rename <appname> <newname>')
|
208
|
+
set_cmd(:apps, :rename, 2)
|
209
|
+
|
210
|
+
when 'mem'
|
211
|
+
usage('vmc mem <appname> [memsize]')
|
212
|
+
if @args.size == 2
|
213
|
+
set_cmd(:apps, :mem, 2)
|
214
|
+
else
|
215
|
+
set_cmd(:apps, :mem, 1)
|
216
|
+
end
|
217
|
+
|
218
|
+
when 'stats'
|
219
|
+
usage('vmc stats <appname>')
|
220
|
+
set_cmd(:apps, :stats, 1)
|
221
|
+
|
222
|
+
when 'map'
|
223
|
+
usage('vmc map <appname> <url>')
|
224
|
+
set_cmd(:apps, :map, 2)
|
225
|
+
|
226
|
+
when 'unmap'
|
227
|
+
usage('vmc unmap <appname> <url>')
|
228
|
+
set_cmd(:apps, :unmap, 2)
|
229
|
+
|
230
|
+
when 'delete'
|
231
|
+
usage('vmc delete <appname>')
|
232
|
+
if @options[:all] && @args.size == 0
|
233
|
+
set_cmd(:apps, :delete)
|
234
|
+
else
|
235
|
+
set_cmd(:apps, :delete, 1)
|
236
|
+
end
|
237
|
+
|
238
|
+
when 'files'
|
239
|
+
usage('vmc files <appname> [path] [--instance N] [--all] [--prefix]')
|
240
|
+
if @args.size == 1
|
241
|
+
set_cmd(:apps, :files, 1)
|
242
|
+
else
|
243
|
+
set_cmd(:apps, :files, 2)
|
244
|
+
end
|
245
|
+
|
246
|
+
when 'logs'
|
247
|
+
usage('vmc logs <appname> [--instance N] [--all] [--prefix]')
|
248
|
+
set_cmd(:apps, :logs, 1)
|
249
|
+
|
250
|
+
when 'instances', 'scale'
|
251
|
+
if @args.size == 1
|
252
|
+
usage('vmc instances <appname>')
|
253
|
+
set_cmd(:apps, :instances, 1)
|
254
|
+
else
|
255
|
+
usage('vmc instances <appname> <num|delta>')
|
256
|
+
set_cmd(:apps, :instances, 2)
|
257
|
+
end
|
258
|
+
|
259
|
+
when 'crashes'
|
260
|
+
usage('vmc crashes <appname>')
|
261
|
+
set_cmd(:apps, :crashes, 1)
|
262
|
+
|
263
|
+
when 'crashlogs'
|
264
|
+
usage('vmc crashlogs <appname>')
|
265
|
+
set_cmd(:apps, :crashlogs, 1)
|
266
|
+
|
267
|
+
when 'push'
|
268
|
+
usage('vmc push [appname] [--path PATH] [--url URL] [--instances N] [--mem] [--no-start]')
|
269
|
+
if @args.size == 1
|
270
|
+
set_cmd(:apps, :push, 1)
|
271
|
+
else
|
272
|
+
set_cmd(:apps, :push, 0)
|
273
|
+
end
|
274
|
+
|
275
|
+
when 'update'
|
276
|
+
usage('vmc update <appname> [--path PATH]')
|
277
|
+
set_cmd(:apps, :update, 1)
|
278
|
+
|
279
|
+
when 'services'
|
280
|
+
usage('vmc services')
|
281
|
+
set_cmd(:services, :services)
|
282
|
+
|
283
|
+
when 'create-service', 'create_service'
|
284
|
+
usage('vmc create-service [service] [servicename] [appname] [--name servicename] [--bind appname]')
|
285
|
+
set_cmd(:services, :create_service) if @args.size == 0
|
286
|
+
set_cmd(:services, :create_service, 1) if @args.size == 1
|
287
|
+
set_cmd(:services, :create_service, 2) if @args.size == 2
|
288
|
+
set_cmd(:services, :create_service, 3) if @args.size == 3
|
289
|
+
|
290
|
+
when 'delete-service', 'delete_service'
|
291
|
+
usage('vmc delete-service <service>')
|
292
|
+
if @args.size == 1
|
293
|
+
set_cmd(:services, :delete_service, 1)
|
294
|
+
else
|
295
|
+
set_cmd(:services, :delete_service)
|
296
|
+
end
|
297
|
+
|
298
|
+
when 'bind-service', 'bind_service'
|
299
|
+
usage('vmc bind-service <servicename> <appname>')
|
300
|
+
set_cmd(:services, :bind_service, 2)
|
301
|
+
|
302
|
+
when 'unbind-service', 'unbind_service'
|
303
|
+
usage('vmc unbind-service <servicename> <appname>')
|
304
|
+
set_cmd(:services, :unbind_service, 2)
|
305
|
+
|
306
|
+
when 'clone-services'
|
307
|
+
usage('vmc clone-services <src-app> <dest-app>')
|
308
|
+
set_cmd(:services, :clone_services, 2)
|
309
|
+
|
310
|
+
when 'aliases'
|
311
|
+
usage('vmc aliases')
|
312
|
+
set_cmd(:misc, :aliases)
|
313
|
+
|
314
|
+
when 'alias'
|
315
|
+
usage('vmc alias <alias[=]command>')
|
316
|
+
if @args.size == 1
|
317
|
+
set_cmd(:misc, :alias, 1)
|
318
|
+
elsif @args.size == 2
|
319
|
+
set_cmd(:misc, :alias, 2)
|
320
|
+
end
|
321
|
+
|
322
|
+
when 'unalias'
|
323
|
+
usage('vmc unalias <alias>')
|
324
|
+
set_cmd(:misc, :unalias, 1)
|
325
|
+
|
326
|
+
when 'help'
|
327
|
+
display_help if @args.size == 0
|
328
|
+
@help_only = true
|
329
|
+
parse_command!
|
330
|
+
|
331
|
+
when 'usage'
|
332
|
+
display basic_usage
|
333
|
+
exit(true)
|
334
|
+
|
335
|
+
when 'options'
|
336
|
+
# Simulate --options
|
337
|
+
@args = @args.unshift('--options')
|
338
|
+
parse_options!
|
339
|
+
|
340
|
+
else
|
341
|
+
if verb
|
342
|
+
display "vmc: Unknown command [#{verb}]"
|
343
|
+
display basic_usage
|
344
|
+
exit(false)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def process_aliases!
|
350
|
+
return if @args.empty?
|
351
|
+
aliases = VMC::Cli::Config.aliases
|
352
|
+
if key = aliases.values.grep(@args[0]).first
|
353
|
+
display "[#{@args[0]} aliased to #{aliases.invert[key]}]" if @options[:verbose]
|
354
|
+
@args[0] = aliases.invert[key]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
def usage(msg = nil)
|
359
|
+
@usage = msg if msg
|
360
|
+
@usage
|
361
|
+
end
|
362
|
+
|
363
|
+
def usage_error(msg = nil)
|
364
|
+
@usage_error = msg if msg
|
365
|
+
@usage_error
|
366
|
+
end
|
367
|
+
|
368
|
+
def run
|
369
|
+
trap('TERM') { print "\nInterupted\n"; exit(false)}
|
370
|
+
trap("INT") { print "\nInterupted\n"; exit(false)}
|
371
|
+
|
372
|
+
parse_options!
|
373
|
+
|
374
|
+
@options[:colorize] = false unless STDOUT.tty?
|
375
|
+
|
376
|
+
VMC::Cli::Config.colorize = @options.delete(:colorize)
|
377
|
+
VMC::Cli::Config.trace = @options.delete(:trace)
|
378
|
+
VMC::Cli::Config.nozip = @options.delete(:nozip)
|
379
|
+
VMC::Cli::Config.output ||= STDOUT unless @options[:quiet]
|
380
|
+
|
381
|
+
process_aliases!
|
382
|
+
parse_command!
|
383
|
+
|
384
|
+
if @namespace && @action
|
385
|
+
eval("VMC::Cli::Command::#{@namespace.to_s.capitalize}").new(@options).send(@action.to_sym, *@args)
|
386
|
+
elsif @help_only || @usage
|
387
|
+
display_usage
|
388
|
+
else
|
389
|
+
display basic_usage
|
390
|
+
exit(false)
|
391
|
+
end
|
392
|
+
|
393
|
+
rescue OptionParser::InvalidOption => e
|
394
|
+
rescue OptionParser::AmbiguousOption => e
|
395
|
+
puts(e.message.red)
|
396
|
+
puts("\n")
|
397
|
+
puts(basic_usage)
|
398
|
+
@exit_status = false
|
399
|
+
rescue VMC::Client::AuthError => e
|
400
|
+
if VMC::Cli::Config.auth_token.nil?
|
401
|
+
puts "Login Required".red
|
402
|
+
else
|
403
|
+
puts "Not Authorized".red
|
404
|
+
end
|
405
|
+
@exit_status = false
|
406
|
+
rescue VMC::Client::TargetError, VMC::Client::NotFound, VMC::Client::BadTarget => e
|
407
|
+
puts e.message.red
|
408
|
+
@exit_status = false
|
409
|
+
rescue VMC::Cli::GracefulExit => e
|
410
|
+
# Redirected commands end up generating this exception (kind of goto)
|
411
|
+
rescue VMC::Cli::CliExit => e
|
412
|
+
puts e.message.red
|
413
|
+
@exit_status = false
|
414
|
+
rescue VMC::Cli::CliError => e
|
415
|
+
say("Error #{e.error_code}: #{e.message}".red)
|
416
|
+
@exit_status = false
|
417
|
+
rescue SystemExit => e
|
418
|
+
@exit_status = e.success?
|
419
|
+
rescue => e
|
420
|
+
puts e.message.red
|
421
|
+
puts e.backtrace
|
422
|
+
@exit_status = false
|
423
|
+
ensure
|
424
|
+
say("\n")
|
425
|
+
@exit_status == true if @exit_status.nil?
|
426
|
+
if @options[:verbose]
|
427
|
+
if @exit_status
|
428
|
+
puts "[#{@namespace}:#{@action}] SUCCEEDED".green
|
429
|
+
else
|
430
|
+
puts "[#{@namespace}:#{@action}] FAILED".red
|
431
|
+
end
|
432
|
+
say("\n")
|
433
|
+
end
|
434
|
+
exit(@exit_status)
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|
@@ -0,0 +1,74 @@
|
|
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
|
+
services_table = table do |t|
|
12
|
+
t.headings = 'Service', 'Version', 'Description'
|
13
|
+
services.each do |service_type, value|
|
14
|
+
value.each do |vendor, version|
|
15
|
+
version.each do |version_str, service|
|
16
|
+
t << [ vendor, version_str, service[:description] ]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
display services_table
|
22
|
+
end
|
23
|
+
|
24
|
+
def display_provisioned_services(services=nil)
|
25
|
+
services ||= client.services
|
26
|
+
display "\n=========== Provisioned Services ============\n\n"
|
27
|
+
display_provisioned_services_table(services)
|
28
|
+
end
|
29
|
+
|
30
|
+
def display_provisioned_services_table(services)
|
31
|
+
return unless services && !services.empty?
|
32
|
+
services_table = table do |t|
|
33
|
+
t.headings = 'Name', 'Service'
|
34
|
+
services.each do |service|
|
35
|
+
t << [ service[:name], service[:vendor] ]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
display services_table
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_service_banner(service, name, display_name=false)
|
42
|
+
sn = " [#{name}]" if display_name
|
43
|
+
display "Creating Service#{sn}: ", false
|
44
|
+
client.create_service(service, name)
|
45
|
+
display 'OK'.green
|
46
|
+
end
|
47
|
+
|
48
|
+
def bind_service_banner(service, appname, check_restart=true)
|
49
|
+
display "Binding Service: ", false
|
50
|
+
client.bind_service(service, appname)
|
51
|
+
display 'OK'.green
|
52
|
+
check_app_for_restart(appname) if check_restart
|
53
|
+
end
|
54
|
+
|
55
|
+
def unbind_service_banner(service, appname, check_restart=true)
|
56
|
+
display "Unbinding Service: ", false
|
57
|
+
client.unbind_service(service, appname)
|
58
|
+
display 'OK'.green
|
59
|
+
check_app_for_restart(appname) if check_restart
|
60
|
+
end
|
61
|
+
|
62
|
+
def random_service_name(service)
|
63
|
+
r = "%04x" % [rand(0x0100000)]
|
64
|
+
"#{service.to_s}-#{r}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_app_for_restart(appname)
|
68
|
+
app = client.app_info(appname)
|
69
|
+
cmd = VMC::Cli::Command::Apps.new(@options)
|
70
|
+
cmd.restart(appname) if app[:state] == 'STARTED'
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
data/lib/cli/usage.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
class VMC::Cli::Runner
|
2
|
+
|
3
|
+
def basic_usage
|
4
|
+
"Usage: vmc [options] command [<args>] [command_options]\n" +
|
5
|
+
"Try 'vmc help [command]' or 'vmc help options' for more information."
|
6
|
+
end
|
7
|
+
|
8
|
+
def display_usage
|
9
|
+
if @usage
|
10
|
+
say @usage_error if @usage_error
|
11
|
+
say "Usage: #{@usage}"
|
12
|
+
return
|
13
|
+
elsif @verb_usage
|
14
|
+
say @verb_usage
|
15
|
+
return
|
16
|
+
end
|
17
|
+
say command_usage
|
18
|
+
end
|
19
|
+
|
20
|
+
def command_usage
|
21
|
+
<<-USAGE
|
22
|
+
|
23
|
+
#{basic_usage}
|
24
|
+
|
25
|
+
Currently available vmc commands are:
|
26
|
+
|
27
|
+
Getting Started
|
28
|
+
target [url] Reports current target or sets a new target
|
29
|
+
login [email] [--email, --passwd] Login
|
30
|
+
info System and account information
|
31
|
+
|
32
|
+
Applications
|
33
|
+
apps List deployed applications
|
34
|
+
|
35
|
+
Application Creation
|
36
|
+
push [appname] Create, push, map, and start a new application
|
37
|
+
push [appname] --path Push application from specified path
|
38
|
+
push [appname] --url Set the url for the application
|
39
|
+
push [appname] --instances <N> Set the expected number <N> of instances
|
40
|
+
push [appname] --mem M Set the memory reservation for the application
|
41
|
+
push [appname] --no-start Do not auto-start the application
|
42
|
+
|
43
|
+
Application Operations
|
44
|
+
start <appname> Start the application
|
45
|
+
stop <appname> Stop the application
|
46
|
+
restart <appname> Restart the application
|
47
|
+
delete <appname> Delete the application
|
48
|
+
rename <appname> <newname> Rename the application
|
49
|
+
|
50
|
+
Application Updates
|
51
|
+
update <appname> [--path] Update the application bits
|
52
|
+
mem <appname> [memsize] Update the memory reservation for an application
|
53
|
+
map <appname> <url> Register the application to the url
|
54
|
+
unmap <appname> <url> Unregister the application from the url
|
55
|
+
instances <appname> <num|delta> Scale the application instances up or down
|
56
|
+
|
57
|
+
Application Information
|
58
|
+
crashes <appname> List recent application crashes
|
59
|
+
crashlogs <appname> Display log information for crashed applications
|
60
|
+
logs <appname> [--all] Display log information for the application
|
61
|
+
files <appname> [path] [--all] Display directory listing or file download for [path]
|
62
|
+
stats <appname> Display resource usage for the application
|
63
|
+
instances <appname> List application instances
|
64
|
+
|
65
|
+
Services
|
66
|
+
services Lists of services available and provisioned
|
67
|
+
create-service <service> [--name,--bind] Create a provisioned service
|
68
|
+
create-service <service> <name> Create a provisioned service and assign it <name>
|
69
|
+
create-service <service> <name> <app> Create a provisioned service and assign it <name>, and bind to <app>
|
70
|
+
delete-service [servicename] Delete a provisioned service
|
71
|
+
bind-service <servicename> <appname> Bind a service to an application
|
72
|
+
unbind-service <servicename> <appname> Unbind service from the application
|
73
|
+
clone-services <src-app> <dest-app> Clone service bindings from <src-app> application to <dest-app>
|
74
|
+
|
75
|
+
Administration
|
76
|
+
user Display user account information
|
77
|
+
passwd Change the password for the current user
|
78
|
+
logout Logs current user out of the target system
|
79
|
+
add-user [--email, --passwd] Register a new user (requires admin privileges)
|
80
|
+
delete-user <user> Delete a user and all apps and services (requires admin privileges)
|
81
|
+
|
82
|
+
Misc
|
83
|
+
aliases List aliases
|
84
|
+
alias <alias[=]command> Create an alias for a command
|
85
|
+
unalias <alias> Remove an alias
|
86
|
+
targets List known targets and associated authorization tokens
|
87
|
+
|
88
|
+
Help
|
89
|
+
help [command] Get general help or help on a specific command
|
90
|
+
help options Get help on available options
|
91
|
+
USAGE
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
data/lib/cli/version.rb
ADDED
data/lib/cli/zip_util.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
require 'zip/zipfilesystem'
|
3
|
+
|
4
|
+
module VMC::Cli
|
5
|
+
|
6
|
+
class ZipUtil
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def entry_lines(file)
|
10
|
+
contents = nil
|
11
|
+
unless VMC::Cli::Config.nozip
|
12
|
+
contents = `unzip -l #{file} 2> /dev/null`
|
13
|
+
contents = nil if $? != 0
|
14
|
+
end
|
15
|
+
# Do Ruby version if told to or native version failed
|
16
|
+
unless contents
|
17
|
+
entries = []
|
18
|
+
Zip::ZipFile.foreach(file) { |zentry| entries << zentry }
|
19
|
+
contents = entries.join("\n")
|
20
|
+
end
|
21
|
+
contents
|
22
|
+
end
|
23
|
+
|
24
|
+
def unpack(file, dest)
|
25
|
+
unless VMC::Cli::Config.nozip
|
26
|
+
FileUtils.mkdir(dest)
|
27
|
+
`unzip -q #{file} -d #{dest} 2> /dev/null`
|
28
|
+
return unless $? != 0
|
29
|
+
end
|
30
|
+
# Do Ruby version if told to or native version failed
|
31
|
+
Zip::ZipFile.foreach(file) do |zentry|
|
32
|
+
epath = "#{dest}/#{zentry}"
|
33
|
+
dirname = File.dirname(epath)
|
34
|
+
FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
|
35
|
+
zentry.extract(epath) unless File.exists?(epath)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def pack(dir, zipfile)
|
40
|
+
exclude = ['..', '.', '*~', '#*#', '*.log']
|
41
|
+
unless VMC::Cli::Config.nozip
|
42
|
+
excludes = exclude.map { |e| "\\#{e}" }
|
43
|
+
excludes = excludes.join(' ')
|
44
|
+
Dir.chdir(dir) do
|
45
|
+
`zip -q -r -x #{excludes} #{zipfile} . 2> /dev/null`
|
46
|
+
return unless $? != 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# Do Ruby version if told to or native version failed
|
50
|
+
Zip::ZipFile::open(zipfile, true) do |zf|
|
51
|
+
Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH).each do |f|
|
52
|
+
process = true
|
53
|
+
exclude.each { |e| process = false if File.fnmatch(e, File.basename(f)) }
|
54
|
+
zf.add(f.sub("#{dir}/",''), f) if (process && File.exists?(f))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/cli.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
module VMC
|
5
|
+
|
6
|
+
autoload :Client, "#{ROOT}/vmc/client"
|
7
|
+
|
8
|
+
module Cli
|
9
|
+
|
10
|
+
autoload :Config, "#{ROOT}/cli/config"
|
11
|
+
autoload :Framework, "#{ROOT}/cli/frameworks"
|
12
|
+
autoload :Runner, "#{ROOT}/cli/runner"
|
13
|
+
autoload :ZipUtil, "#{ROOT}/cli/zip_util"
|
14
|
+
autoload :ServicesHelper, "#{ROOT}/cli/services_helper"
|
15
|
+
|
16
|
+
module Command
|
17
|
+
autoload :Base, "#{ROOT}/cli/commands/base"
|
18
|
+
autoload :Admin, "#{ROOT}/cli/commands/admin"
|
19
|
+
autoload :Apps, "#{ROOT}/cli/commands/apps"
|
20
|
+
autoload :Misc, "#{ROOT}/cli/commands/misc"
|
21
|
+
autoload :Services, "#{ROOT}/cli/commands/services"
|
22
|
+
autoload :User, "#{ROOT}/cli/commands/user"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
require "#{ROOT}/cli/version"
|
29
|
+
require "#{ROOT}/cli/core_ext"
|
30
|
+
require "#{ROOT}/cli/errors"
|