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