cloulu 0.0.0 → 0.1.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.
- data/bin/{cloulu → cl} +0 -0
- data/lib/cc_api_stub/applications.rb +53 -0
- data/lib/cc_api_stub/domains.rb +16 -0
- data/lib/cc_api_stub/frameworks.rb +22 -0
- data/lib/cc_api_stub/helper.rb +131 -0
- data/lib/cc_api_stub/login.rb +21 -0
- data/lib/cc_api_stub/organization_users.rb +21 -0
- data/lib/cc_api_stub/organizations.rb +70 -0
- data/lib/cc_api_stub/routes.rb +26 -0
- data/lib/cc_api_stub/runtimes.rb +22 -0
- data/lib/cc_api_stub/service_bindings.rb +22 -0
- data/lib/cc_api_stub/service_instances.rb +22 -0
- data/lib/cc_api_stub/services.rb +25 -0
- data/lib/cc_api_stub/spaces.rb +49 -0
- data/lib/cc_api_stub/users.rb +84 -0
- data/lib/cc_api_stub.rb +17 -0
- data/lib/cfoundry/auth_token.rb +63 -0
- data/lib/cfoundry/baseclient.rb +201 -0
- data/lib/cfoundry/chatty_hash.rb +46 -0
- data/lib/cfoundry/client.rb +46 -0
- data/lib/cfoundry/concerns/login_helpers.rb +13 -0
- data/lib/cfoundry/errors.rb +160 -0
- data/lib/cfoundry/rest_client.rb +299 -0
- data/lib/cfoundry/test_support.rb +3 -0
- data/lib/cfoundry/trace_helpers.rb +40 -0
- data/lib/cfoundry/uaaclient.rb +112 -0
- data/lib/cfoundry/upload_helpers.rb +187 -0
- data/lib/cfoundry/v1/app.rb +363 -0
- data/lib/cfoundry/v1/base.rb +72 -0
- data/lib/cfoundry/v1/client.rb +193 -0
- data/lib/cfoundry/v1/framework.rb +21 -0
- data/lib/cfoundry/v1/model.rb +178 -0
- data/lib/cfoundry/v1/model_magic.rb +129 -0
- data/lib/cfoundry/v1/runtime.rb +24 -0
- data/lib/cfoundry/v1/service.rb +39 -0
- data/lib/cfoundry/v1/service_instance.rb +32 -0
- data/lib/cfoundry/v1/service_plan.rb +19 -0
- data/lib/cfoundry/v1/user.rb +22 -0
- data/lib/cfoundry/v2/app.rb +392 -0
- data/lib/cfoundry/v2/base.rb +83 -0
- data/lib/cfoundry/v2/client.rb +138 -0
- data/lib/cfoundry/v2/domain.rb +11 -0
- data/lib/cfoundry/v2/framework.rb +14 -0
- data/lib/cfoundry/v2/model.rb +148 -0
- data/lib/cfoundry/v2/model_magic.rb +449 -0
- data/lib/cfoundry/v2/organization.rb +16 -0
- data/lib/cfoundry/v2/route.rb +15 -0
- data/lib/cfoundry/v2/runtime.rb +12 -0
- data/lib/cfoundry/v2/service.rb +19 -0
- data/lib/cfoundry/v2/service_auth_token.rb +9 -0
- data/lib/cfoundry/v2/service_binding.rb +10 -0
- data/lib/cfoundry/v2/service_instance.rb +14 -0
- data/lib/cfoundry/v2/service_plan.rb +12 -0
- data/lib/cfoundry/v2/space.rb +18 -0
- data/lib/cfoundry/v2/user.rb +64 -0
- data/lib/cfoundry/validator.rb +39 -0
- data/lib/cfoundry/version.rb +4 -0
- data/lib/cfoundry/zip.rb +56 -0
- data/lib/cfoundry.rb +2 -0
- data/lib/manifests-vmc-plugin/errors.rb +21 -0
- data/lib/manifests-vmc-plugin/loader/builder.rb +34 -0
- data/lib/manifests-vmc-plugin/loader/normalizer.rb +149 -0
- data/lib/manifests-vmc-plugin/loader/resolver.rb +79 -0
- data/lib/manifests-vmc-plugin/loader.rb +31 -0
- data/lib/manifests-vmc-plugin/plugin.rb +145 -0
- data/lib/manifests-vmc-plugin/version.rb +3 -0
- data/lib/manifests-vmc-plugin.rb +313 -0
- data/lib/mothership/base.rb +99 -0
- data/lib/mothership/callbacks.rb +85 -0
- data/lib/mothership/command.rb +146 -0
- data/lib/mothership/errors.rb +38 -0
- data/lib/mothership/help/commands.rb +53 -0
- data/lib/mothership/help/printer.rb +170 -0
- data/lib/mothership/help.rb +64 -0
- data/lib/mothership/inputs.rb +189 -0
- data/lib/mothership/parser.rb +182 -0
- data/lib/mothership/version.rb +3 -0
- data/lib/mothership.rb +64 -0
- data/lib/tunnel-vmc-plugin/plugin.rb +178 -0
- data/lib/tunnel-vmc-plugin/tunnel.rb +308 -0
- data/lib/tunnel-vmc-plugin/version.rb +3 -0
- data/lib/uaa/http.rb +168 -0
- data/lib/uaa/misc.rb +121 -0
- data/lib/uaa/scim.rb +292 -0
- data/lib/uaa/token_coder.rb +196 -0
- data/lib/uaa/token_issuer.rb +255 -0
- data/lib/uaa/util.rb +235 -0
- data/lib/uaa/version.rb +19 -0
- data/lib/uaa.rb +18 -0
- data/lib/vmc/cli/app/app.rb +45 -0
- data/lib/vmc/cli/app/apps.rb +99 -0
- data/lib/vmc/cli/app/base.rb +90 -0
- data/lib/vmc/cli/app/crashes.rb +42 -0
- data/lib/vmc/cli/app/delete.rb +95 -0
- data/lib/vmc/cli/app/deprecated.rb +11 -0
- data/lib/vmc/cli/app/env.rb +78 -0
- data/lib/vmc/cli/app/files.rb +137 -0
- data/lib/vmc/cli/app/health.rb +26 -0
- data/lib/vmc/cli/app/instances.rb +53 -0
- data/lib/vmc/cli/app/logs.rb +76 -0
- data/lib/vmc/cli/app/push/create.rb +165 -0
- data/lib/vmc/cli/app/push/interactions.rb +94 -0
- data/lib/vmc/cli/app/push/sync.rb +64 -0
- data/lib/vmc/cli/app/push.rb +109 -0
- data/lib/vmc/cli/app/rename.rb +35 -0
- data/lib/vmc/cli/app/restart.rb +20 -0
- data/lib/vmc/cli/app/scale.rb +71 -0
- data/lib/vmc/cli/app/start.rb +143 -0
- data/lib/vmc/cli/app/stats.rb +67 -0
- data/lib/vmc/cli/app/stop.rb +27 -0
- data/lib/vmc/cli/help.rb +11 -0
- data/lib/vmc/cli/interactive.rb +105 -0
- data/lib/vmc/cli/route/base.rb +12 -0
- data/lib/vmc/cli/route/map.rb +82 -0
- data/lib/vmc/cli/route/routes.rb +25 -0
- data/lib/vmc/cli/route/unmap.rb +94 -0
- data/lib/vmc/cli/service/base.rb +8 -0
- data/lib/vmc/cli/service/bind.rb +44 -0
- data/lib/vmc/cli/service/create.rb +126 -0
- data/lib/vmc/cli/service/delete.rb +86 -0
- data/lib/vmc/cli/service/rename.rb +35 -0
- data/lib/vmc/cli/service/service.rb +42 -0
- data/lib/vmc/cli/service/services.rb +114 -0
- data/lib/vmc/cli/service/unbind.rb +38 -0
- data/lib/vmc/cli/start/base.rb +94 -0
- data/lib/vmc/cli/start/colors.rb +13 -0
- data/lib/vmc/cli/start/info.rb +126 -0
- data/lib/vmc/cli/start/login.rb +97 -0
- data/lib/vmc/cli/start/logout.rb +17 -0
- data/lib/vmc/cli/start/target.rb +60 -0
- data/lib/vmc/cli/start/target_interactions.rb +37 -0
- data/lib/vmc/cli/start/targets.rb +16 -0
- data/lib/vmc/cli/user/base.rb +29 -0
- data/lib/vmc/cli/user/create.rb +39 -0
- data/lib/vmc/cli/user/delete.rb +27 -0
- data/lib/vmc/cli/user/passwd.rb +50 -0
- data/lib/vmc/cli/user/register.rb +42 -0
- data/lib/vmc/cli/user/users.rb +32 -0
- data/lib/vmc/cli/v2_check_cli.rb +16 -0
- data/lib/vmc/cli.rb +474 -0
- data/lib/vmc/constants.rb +13 -0
- data/lib/vmc/detect.rb +129 -0
- data/lib/vmc/errors.rb +19 -0
- data/lib/vmc/plugin.rb +56 -0
- data/lib/vmc/spacing.rb +89 -0
- data/lib/vmc/spec_helper.rb +1 -0
- data/lib/vmc/test_support.rb +6 -0
- data/lib/vmc/version.rb +3 -0
- data/lib/vmc.rb +8 -0
- data/vendor/errors/v1.yml +189 -0
- data/vendor/errors/v2.yml +360 -0
- metadata +303 -190
data/lib/vmc/cli.rb
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
require "socket"
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "multi_json"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
|
|
7
|
+
require "mothership"
|
|
8
|
+
|
|
9
|
+
require "cfoundry"
|
|
10
|
+
|
|
11
|
+
require "vmc/constants"
|
|
12
|
+
require "vmc/errors"
|
|
13
|
+
require "vmc/spacing"
|
|
14
|
+
|
|
15
|
+
require "vmc/cli/help"
|
|
16
|
+
require "vmc/cli/interactive"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
$vmc_asked_auth = false
|
|
20
|
+
|
|
21
|
+
module VMC
|
|
22
|
+
class CLI < Mothership
|
|
23
|
+
include VMC::Interactive
|
|
24
|
+
include VMC::Spacing
|
|
25
|
+
|
|
26
|
+
option :help, :desc => "Show command usage", :alias => "-h",
|
|
27
|
+
:default => false
|
|
28
|
+
|
|
29
|
+
option :version, :desc => "Print version number", :alias => "-v",
|
|
30
|
+
:default => false
|
|
31
|
+
|
|
32
|
+
option :verbose, :desc => "Print extra information", :alias => "-V",
|
|
33
|
+
:default => false
|
|
34
|
+
|
|
35
|
+
option :force, :desc => "Skip interaction when possible", :alias => "-f",
|
|
36
|
+
:type => :boolean, :default => proc { input[:script] }
|
|
37
|
+
|
|
38
|
+
option :debug, :desc => "Print full stack trace (instead of crash log)",
|
|
39
|
+
:type => :boolean, :default => false
|
|
40
|
+
|
|
41
|
+
option :quiet, :desc => "Simplify output format", :alias => "-q",
|
|
42
|
+
:type => :boolean, :default => proc { input[:script] }
|
|
43
|
+
|
|
44
|
+
option :script, :desc => "Shortcut for --quiet and --force",
|
|
45
|
+
:type => :boolean, :default => proc { !$stdout.tty? }
|
|
46
|
+
|
|
47
|
+
option :trace, :desc => "Show API traffic", :alias => "-t",
|
|
48
|
+
:default => false
|
|
49
|
+
|
|
50
|
+
option :color, :desc => "Use colorful output",
|
|
51
|
+
:type => :boolean, :default => proc { !input[:quiet] }
|
|
52
|
+
|
|
53
|
+
def default_action
|
|
54
|
+
if input[:version]
|
|
55
|
+
line "cloulu #{VERSION}"
|
|
56
|
+
else
|
|
57
|
+
super
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def check_target
|
|
62
|
+
unless client && client.target
|
|
63
|
+
fail "Please select a target with 'cl target'."
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def check_logged_in
|
|
68
|
+
unless client.logged_in?
|
|
69
|
+
if force?
|
|
70
|
+
fail "Please log in with 'cl login'."
|
|
71
|
+
else
|
|
72
|
+
line c("Please log in first to proceed.", :warning)
|
|
73
|
+
line
|
|
74
|
+
invoke :login
|
|
75
|
+
invalidate_client
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def precondition
|
|
81
|
+
check_target
|
|
82
|
+
check_logged_in
|
|
83
|
+
|
|
84
|
+
return unless v2?
|
|
85
|
+
|
|
86
|
+
unless client.current_organization
|
|
87
|
+
fail "Please select an organization with 'cl target --ask-org'."
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
unless client.current_space
|
|
91
|
+
fail "Please select a space with 'cl target --ask-space'."
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def wrap_errors
|
|
96
|
+
yield
|
|
97
|
+
rescue CFoundry::Timeout => e
|
|
98
|
+
err(e.message)
|
|
99
|
+
rescue Interrupt
|
|
100
|
+
exit_status 130
|
|
101
|
+
rescue Mothership::Error
|
|
102
|
+
raise
|
|
103
|
+
rescue UserError => e
|
|
104
|
+
log_error(e)
|
|
105
|
+
err e.message
|
|
106
|
+
rescue SystemExit
|
|
107
|
+
raise
|
|
108
|
+
rescue UserFriendlyError => e
|
|
109
|
+
err e.message
|
|
110
|
+
rescue CFoundry::Forbidden, CFoundry::InvalidAuthToken => e
|
|
111
|
+
if !$vmc_asked_auth
|
|
112
|
+
$vmc_asked_auth = true
|
|
113
|
+
|
|
114
|
+
line
|
|
115
|
+
line c("Not authenticated! Try logging in:", :warning)
|
|
116
|
+
|
|
117
|
+
# TODO: there's no color here; global flags not being passed
|
|
118
|
+
# through (mothership bug?)
|
|
119
|
+
invoke :login
|
|
120
|
+
|
|
121
|
+
retry
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
log_error(e)
|
|
125
|
+
|
|
126
|
+
err "Denied: #{e.description}"
|
|
127
|
+
|
|
128
|
+
rescue Exception => e
|
|
129
|
+
log_error(e)
|
|
130
|
+
|
|
131
|
+
msg = e.class.name
|
|
132
|
+
msg << ": #{e}" unless e.to_s.empty?
|
|
133
|
+
msg << "\nFor more information, see #{VMC::CRASH_FILE}"
|
|
134
|
+
err msg
|
|
135
|
+
|
|
136
|
+
raise if debug?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def execute(cmd, argv, global = {})
|
|
140
|
+
if input[:help]
|
|
141
|
+
invoke :help, :command => cmd.name.to_s
|
|
142
|
+
else
|
|
143
|
+
wrap_errors do
|
|
144
|
+
@command = cmd
|
|
145
|
+
precondition
|
|
146
|
+
|
|
147
|
+
save_token_if_it_changes do
|
|
148
|
+
super
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def save_token_if_it_changes
|
|
155
|
+
return yield unless client && client.token
|
|
156
|
+
|
|
157
|
+
before_token = client.token
|
|
158
|
+
|
|
159
|
+
yield
|
|
160
|
+
|
|
161
|
+
after_token = client.token
|
|
162
|
+
|
|
163
|
+
return unless after_token
|
|
164
|
+
|
|
165
|
+
if before_token != after_token
|
|
166
|
+
info = target_info
|
|
167
|
+
info[:token] = after_token.auth_header
|
|
168
|
+
save_target_info(info)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def log_error(e)
|
|
173
|
+
ensure_config_dir
|
|
174
|
+
|
|
175
|
+
msg = e.class.name
|
|
176
|
+
msg << ": #{e}" unless e.to_s.empty?
|
|
177
|
+
|
|
178
|
+
crash_file = File.expand_path(VMC::CRASH_FILE)
|
|
179
|
+
|
|
180
|
+
FileUtils.mkdir_p(File.dirname(crash_file))
|
|
181
|
+
|
|
182
|
+
File.open(crash_file, "w") do |f|
|
|
183
|
+
f.puts "Time of crash:"
|
|
184
|
+
f.puts " #{Time.now}"
|
|
185
|
+
f.puts ""
|
|
186
|
+
f.puts msg
|
|
187
|
+
f.puts ""
|
|
188
|
+
|
|
189
|
+
if e.respond_to?(:request_trace)
|
|
190
|
+
f.puts "<<<"
|
|
191
|
+
f.puts e.request_trace
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
if e.respond_to?(:response_trace)
|
|
195
|
+
f.puts e.response_trace
|
|
196
|
+
f.puts ">>>"
|
|
197
|
+
f.puts ""
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
vmc_dir = File.expand_path("../../../..", __FILE__) + "/"
|
|
201
|
+
e.backtrace.each do |loc|
|
|
202
|
+
if loc =~ /\/gems\//
|
|
203
|
+
f.puts loc.sub(/.*\/gems\//, "")
|
|
204
|
+
else
|
|
205
|
+
f.puts loc.sub(vmc_dir, "")
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def quiet?
|
|
212
|
+
input[:quiet]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def force?
|
|
216
|
+
input[:force]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def debug?
|
|
220
|
+
!!input[:debug]
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def color_enabled?
|
|
224
|
+
input[:color]
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def verbose?
|
|
228
|
+
input[:verbose]
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def user_colors
|
|
232
|
+
return @user_colors if @user_colors
|
|
233
|
+
|
|
234
|
+
colors = File.expand_path(COLORS_FILE)
|
|
235
|
+
|
|
236
|
+
@user_colors = super.dup
|
|
237
|
+
|
|
238
|
+
# most terminal schemes are stupid, so use cyan instead
|
|
239
|
+
@user_colors.each do |k, v|
|
|
240
|
+
if v == :blue
|
|
241
|
+
@user_colors[k] = :cyan
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
if File.exists?(colors)
|
|
246
|
+
YAML.load_file(colors).each do |k, v|
|
|
247
|
+
@user_colors[k.to_sym] = v.to_sym
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
@user_colors
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def err(msg, status = 1)
|
|
255
|
+
$stderr.puts c(msg, :error)
|
|
256
|
+
exit_status status
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def fail(msg)
|
|
260
|
+
raise UserError, msg
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def table(headers, rows)
|
|
264
|
+
tabular(
|
|
265
|
+
!quiet? && headers.collect { |h| h && b(h) },
|
|
266
|
+
*rows)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def name_list(xs)
|
|
270
|
+
if xs.empty?
|
|
271
|
+
d("none")
|
|
272
|
+
else
|
|
273
|
+
xs.collect { |x| c(x.name, :name) }.join(", ")
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def sane_target_url(url)
|
|
278
|
+
unless url =~ /^https?:\/\//
|
|
279
|
+
begin
|
|
280
|
+
TCPSocket.new(url, Net::HTTP.https_default_port)
|
|
281
|
+
url = "https://#{url}"
|
|
282
|
+
rescue Errno::ECONNREFUSED, SocketError, Timeout::Error
|
|
283
|
+
url = "http://#{url}"
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
url.gsub(/\/$/, "")
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def target_file
|
|
291
|
+
one_of(VMC::TARGET_FILE, VMC::OLD_TARGET_FILE)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def tokens_file
|
|
295
|
+
one_of(VMC::TOKENS_FILE, VMC::OLD_TOKENS_FILE)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def one_of(*paths)
|
|
299
|
+
paths.each do |p|
|
|
300
|
+
exp = File.expand_path(p)
|
|
301
|
+
return exp if File.exist? exp
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
File.expand_path(paths.first)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def client_target
|
|
308
|
+
if File.exists?(target_file)
|
|
309
|
+
File.read(target_file).chomp
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def ensure_config_dir
|
|
314
|
+
config = File.expand_path(VMC::CONFIG_DIR)
|
|
315
|
+
FileUtils.mkdir_p(config) unless File.exist? config
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def set_target(url)
|
|
319
|
+
ensure_config_dir
|
|
320
|
+
|
|
321
|
+
File.open(File.expand_path(VMC::TARGET_FILE), "w") do |f|
|
|
322
|
+
f.write(sane_target_url(url))
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
invalidate_client
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def targets_info
|
|
329
|
+
new_toks = File.expand_path(VMC::TOKENS_FILE)
|
|
330
|
+
old_toks = File.expand_path(VMC::OLD_TOKENS_FILE)
|
|
331
|
+
|
|
332
|
+
info =
|
|
333
|
+
if File.exist? new_toks
|
|
334
|
+
YAML.load_file(new_toks)
|
|
335
|
+
elsif File.exist? old_toks
|
|
336
|
+
MultiJson.load(File.read(old_toks))
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
info ||= {}
|
|
340
|
+
|
|
341
|
+
normalize_targets_info(info)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def normalize_targets_info(info_by_url)
|
|
345
|
+
info_by_url.reduce({}) do |hash, pair|
|
|
346
|
+
key, value = pair
|
|
347
|
+
hash[key] = value.is_a?(String) ? { :token => value } : value
|
|
348
|
+
hash
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def target_info(target = client_target)
|
|
353
|
+
targets_info[target] || {}
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def save_targets(ts)
|
|
357
|
+
ensure_config_dir
|
|
358
|
+
|
|
359
|
+
File.open(File.expand_path(VMC::TOKENS_FILE), "w") do |io|
|
|
360
|
+
YAML.dump(ts, io)
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def save_target_info(info, target = client_target)
|
|
365
|
+
ts = targets_info
|
|
366
|
+
ts[target] = info
|
|
367
|
+
save_targets(ts)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def remove_target_info(target = client_target)
|
|
371
|
+
ts = targets_info
|
|
372
|
+
ts.delete target
|
|
373
|
+
save_targets(ts)
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def no_v2
|
|
377
|
+
fail "Not implemented for v2." if v2?
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def v2?
|
|
381
|
+
client.version == 2
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def invalidate_client
|
|
385
|
+
@@client = nil
|
|
386
|
+
client
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def client(target = client_target)
|
|
390
|
+
return @@client if defined?(@@client) && @@client
|
|
391
|
+
return unless target
|
|
392
|
+
|
|
393
|
+
info = target_info(target)
|
|
394
|
+
token = info[:token] && CFoundry::AuthToken.from_hash(info)
|
|
395
|
+
|
|
396
|
+
@@client =
|
|
397
|
+
case info[:version]
|
|
398
|
+
when 2
|
|
399
|
+
fail "User switching not implemented for v2." if input[:proxy]
|
|
400
|
+
CFoundry::V2::Client.new(target, token)
|
|
401
|
+
when 1
|
|
402
|
+
CFoundry::V1::Client.new(target, token)
|
|
403
|
+
else
|
|
404
|
+
CFoundry::Client.new(target, token)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
@@client.proxy = input[:proxy]
|
|
408
|
+
#@@client.http_proxy = input[:http_proxy] || ENV['HTTP_PROXY'] || ENV['http_proxy'] || nil
|
|
409
|
+
@@client.trace = input[:trace]
|
|
410
|
+
|
|
411
|
+
uri = URI.parse(target)
|
|
412
|
+
@@client.log = File.expand_path("#{LOGS_DIR}/#{uri.host}.log")
|
|
413
|
+
|
|
414
|
+
unless info.key? :version
|
|
415
|
+
info[:version] = @@client.version
|
|
416
|
+
save_target_info(info, target)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
if org = info[:organization]
|
|
420
|
+
@@client.current_organization = @@client.organization(org)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
if space = info[:space]
|
|
424
|
+
@@client.current_space = @@client.space(space)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
@@client
|
|
428
|
+
rescue CFoundry::InvalidTarget
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def fail_unknown(display, name)
|
|
432
|
+
fail("Unknown #{display} '#{name}'.")
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
class << self
|
|
436
|
+
def client
|
|
437
|
+
@@client
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def client=(c)
|
|
441
|
+
@@client = c
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
private
|
|
445
|
+
|
|
446
|
+
def find_by_name(display, &blk)
|
|
447
|
+
proc { |name, *args|
|
|
448
|
+
choices, _ = args
|
|
449
|
+
choices ||= instance_exec(&blk) if block_given?
|
|
450
|
+
|
|
451
|
+
choices.find { |c| c.name == name } ||
|
|
452
|
+
fail_unknown(display, name)
|
|
453
|
+
}
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def by_name(what, display = what)
|
|
457
|
+
proc { |name, *_|
|
|
458
|
+
client.send(:"#{what}_by_name", name) ||
|
|
459
|
+
fail_unknown(display, name)
|
|
460
|
+
}
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def find_by_name_insensitive(display, &blk)
|
|
464
|
+
proc { |name, *args|
|
|
465
|
+
choices, _ = args
|
|
466
|
+
choices ||= instance_exec(&blk) if block_given?
|
|
467
|
+
|
|
468
|
+
choices.find { |c| c.name.upcase == name.upcase } ||
|
|
469
|
+
fail_unknown(display, name)
|
|
470
|
+
}
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module VMC
|
|
2
|
+
OLD_TARGET_FILE = "~/.cloulu_target".freeze
|
|
3
|
+
OLD_TOKENS_FILE = "~/.cloulu_token".freeze
|
|
4
|
+
|
|
5
|
+
CONFIG_DIR = "~/.cloulu".freeze
|
|
6
|
+
|
|
7
|
+
LOGS_DIR = "#{CONFIG_DIR}/logs".freeze
|
|
8
|
+
PLUGINS_FILE = "#{CONFIG_DIR}/plugins.yml".freeze
|
|
9
|
+
TARGET_FILE = "#{CONFIG_DIR}/target".freeze
|
|
10
|
+
TOKENS_FILE = "#{CONFIG_DIR}/tokens.yml".freeze
|
|
11
|
+
COLORS_FILE = "#{CONFIG_DIR}/colors.yml".freeze
|
|
12
|
+
CRASH_FILE = "#{CONFIG_DIR}/crash".freeze
|
|
13
|
+
end
|
data/lib/vmc/detect.rb
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require "set"
|
|
2
|
+
|
|
3
|
+
require "clouseau"
|
|
4
|
+
|
|
5
|
+
module VMC
|
|
6
|
+
class Detector
|
|
7
|
+
# "Basic" framework names for a detected language
|
|
8
|
+
PSEUDO_FRAMEWORKS = {
|
|
9
|
+
:node => "node",
|
|
10
|
+
:python => "wsgi",
|
|
11
|
+
:java => "java_web",
|
|
12
|
+
:php => "php",
|
|
13
|
+
:erlang => "otp_rebar",
|
|
14
|
+
:dotnet => "dotNet"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Mismatched framework names
|
|
18
|
+
FRAMEWORK_NAMES = {
|
|
19
|
+
:rails => "rails3"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Clouseau language symbol => matching runtime names
|
|
23
|
+
LANGUAGE_RUNTIMES = {
|
|
24
|
+
:ruby => /^ruby.*/,
|
|
25
|
+
:java => /^java.*/,
|
|
26
|
+
:node => /^node.*/,
|
|
27
|
+
:erlang => /^erlang.*/,
|
|
28
|
+
:dotnet => /^dotNet.*/,
|
|
29
|
+
:python => /^python.*/,
|
|
30
|
+
:php => /^php.*/
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
def initialize(client, path)
|
|
34
|
+
@client = client
|
|
35
|
+
@path = path
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# detect the framework
|
|
39
|
+
def detect_framework
|
|
40
|
+
detected && frameworks[detected]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# detect the language and return the appropriate runtimes
|
|
44
|
+
def detect_runtimes
|
|
45
|
+
if detected && lang = detected.language_name
|
|
46
|
+
runtimes_for(lang)
|
|
47
|
+
else
|
|
48
|
+
[]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# determine runtimes for a given framework based on the language its
|
|
53
|
+
# detector reports itself as
|
|
54
|
+
def runtimes(framework)
|
|
55
|
+
if detector = detectors[framework]
|
|
56
|
+
runtimes_for(detector.language_name)
|
|
57
|
+
else
|
|
58
|
+
[]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# determine suitable memory allocation via the framework's detector
|
|
63
|
+
def suggested_memory(framework)
|
|
64
|
+
if detector = detectors[framework]
|
|
65
|
+
detector.memory_suggestion
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# helper so that this is cached somewhere
|
|
70
|
+
def all_runtimes
|
|
71
|
+
@all_runtimes ||= @client.runtimes
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# helper so that this is cached somewhere
|
|
75
|
+
def all_frameworks
|
|
76
|
+
@all_frameworks ||= @client.frameworks
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def detected
|
|
80
|
+
@detected ||= Clouseau.detect(@path)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def map_detectors!
|
|
86
|
+
@framework_detectors = {}
|
|
87
|
+
@detector_frameworks = {}
|
|
88
|
+
|
|
89
|
+
Clouseau.detectors.each do |d|
|
|
90
|
+
name = d.framework_name
|
|
91
|
+
lang = d.language_name
|
|
92
|
+
|
|
93
|
+
framework = all_frameworks.find { |f|
|
|
94
|
+
f.name == name.to_s ||
|
|
95
|
+
f.name == FRAMEWORK_NAMES[name]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
framework ||= all_frameworks.find { |f|
|
|
99
|
+
f.name == PSEUDO_FRAMEWORKS[lang]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
next unless framework
|
|
103
|
+
|
|
104
|
+
@framework_detectors[framework] = d
|
|
105
|
+
@detector_frameworks[d] = framework
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Framework -> Detector
|
|
112
|
+
def detectors
|
|
113
|
+
map_detectors! unless @framework_detectors
|
|
114
|
+
@framework_detectors
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Detector -> Framework
|
|
118
|
+
def frameworks
|
|
119
|
+
map_detectors! unless @detector_frameworks
|
|
120
|
+
@detector_frameworks
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def runtimes_for(language)
|
|
124
|
+
all_runtimes.select do |r|
|
|
125
|
+
LANGUAGE_RUNTIMES[language] === r.name
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/vmc/errors.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module VMC
|
|
2
|
+
class UserFriendlyError < RuntimeError
|
|
3
|
+
def initialize(msg)
|
|
4
|
+
@message = msg
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def to_s
|
|
8
|
+
@message
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class UserError < UserFriendlyError; end
|
|
13
|
+
|
|
14
|
+
class NotAuthorized < UserError
|
|
15
|
+
def initialize
|
|
16
|
+
@message = "Not authorized."
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/vmc/plugin.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require "set"
|
|
2
|
+
require "yaml"
|
|
3
|
+
|
|
4
|
+
require "vmc/constants"
|
|
5
|
+
require "vmc/cli"
|
|
6
|
+
|
|
7
|
+
module VMC
|
|
8
|
+
module Plugin
|
|
9
|
+
@@plugins = []
|
|
10
|
+
|
|
11
|
+
def self.load_all
|
|
12
|
+
# auto-load gems with 'vmc-plugin' in their name
|
|
13
|
+
matching =
|
|
14
|
+
if Gem::Specification.respond_to? :find_all
|
|
15
|
+
Gem::Specification.find_all do |s|
|
|
16
|
+
s.name =~ /vmc-plugin/
|
|
17
|
+
end
|
|
18
|
+
else
|
|
19
|
+
Gem.source_index.find_name(/vmc-plugin/)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
enabled = Set.new(matching.collect(&:name))
|
|
23
|
+
|
|
24
|
+
vmc_gems = Gem.loaded_specs["vmc"]
|
|
25
|
+
((vmc_gems && vmc_gems.dependencies) || Gem.loaded_specs.values).each do |dep|
|
|
26
|
+
if dep.name =~ /vmc-plugin/
|
|
27
|
+
require "#{dep.name}/plugin"
|
|
28
|
+
enabled.delete dep.name
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# allow explicit enabling/disabling of gems via config
|
|
33
|
+
plugins = File.expand_path(VMC::PLUGINS_FILE)
|
|
34
|
+
if File.exists?(plugins) && yaml = YAML.load_file(plugins)
|
|
35
|
+
enabled += yaml["enabled"] if yaml["enabled"]
|
|
36
|
+
enabled -= yaml["disabled"] if yaml["disabled"]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# load up each gem's 'plugin' file
|
|
40
|
+
#
|
|
41
|
+
# we require this file specifically so people can require the gem
|
|
42
|
+
# without it plugging into VMC
|
|
43
|
+
enabled.each do |gemname|
|
|
44
|
+
begin
|
|
45
|
+
require "#{gemname}/plugin"
|
|
46
|
+
rescue Gem::LoadError => e
|
|
47
|
+
puts "Failed to load #{gemname}:"
|
|
48
|
+
puts " #{e}"
|
|
49
|
+
puts
|
|
50
|
+
puts "You may need to update or remove this plugin."
|
|
51
|
+
puts
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|