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
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
require "cfoundry/trace_helpers"
|
|
2
|
+
require "net/https"
|
|
3
|
+
require "net/http/post/multipart"
|
|
4
|
+
require "multi_json"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
require "forwardable"
|
|
7
|
+
|
|
8
|
+
module CFoundry
|
|
9
|
+
class BaseClient # :nodoc:
|
|
10
|
+
extend Forwardable
|
|
11
|
+
|
|
12
|
+
attr_reader :rest_client
|
|
13
|
+
|
|
14
|
+
def_delegators :rest_client, :target, :target=, :token,
|
|
15
|
+
:proxy, :proxy=, :trace, :backtrace, :backtrace=,
|
|
16
|
+
:log, :log=
|
|
17
|
+
|
|
18
|
+
def initialize(target = "https://api.cloudfoundry.com", token = nil)
|
|
19
|
+
@rest_client = CFoundry::RestClient.new(target, token)
|
|
20
|
+
self.trace = false
|
|
21
|
+
self.backtrace = false
|
|
22
|
+
self.log = false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def uaa
|
|
26
|
+
@uaa ||= begin
|
|
27
|
+
if(endpoint = info[:authorization_endpoint])
|
|
28
|
+
uaa = CFoundry::UAAClient.new(endpoint)
|
|
29
|
+
uaa.trace = trace
|
|
30
|
+
uaa.token = token
|
|
31
|
+
uaa
|
|
32
|
+
else
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def password_score(password)
|
|
39
|
+
uaa ? uaa.password_score(password) : :unknown
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def token=(token)
|
|
43
|
+
if token.is_a?(String)
|
|
44
|
+
token = CFoundry::AuthToken.new(token)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@rest_client.token = token
|
|
48
|
+
@uaa.token = token if @uaa
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def trace=(trace)
|
|
52
|
+
@rest_client.trace = trace
|
|
53
|
+
@uaa.trace = trace if @uaa
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Cloud metadata
|
|
57
|
+
def info
|
|
58
|
+
get("info", :accept => :json)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def get(*args)
|
|
62
|
+
request("GET", *args)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def delete(*args)
|
|
66
|
+
request("DELETE", *args)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def post(*args)
|
|
70
|
+
request("POST", *args)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def put(*args)
|
|
74
|
+
request("PUT", *args)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def request(method, *args)
|
|
78
|
+
if needs_token_refresh?
|
|
79
|
+
token.auth_header = nil
|
|
80
|
+
refresh_token!
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
path, options = normalize_arguments(args)
|
|
84
|
+
request, response = request_raw(method, path, options)
|
|
85
|
+
handle_response(response, options, request)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def request_raw(method, path, options)
|
|
89
|
+
@rest_client.request(method, path, options)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def refresh_token!
|
|
93
|
+
self.token = uaa.try_to_refresh_token!
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def stream_url(url, &blk)
|
|
97
|
+
uri = URI.parse(url)
|
|
98
|
+
|
|
99
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
|
100
|
+
http.read_timeout = 10
|
|
101
|
+
|
|
102
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
|
103
|
+
req["Authorization"] = token.auth_header if token
|
|
104
|
+
|
|
105
|
+
http.request(req) do |response|
|
|
106
|
+
case response
|
|
107
|
+
when Net::HTTPOK
|
|
108
|
+
response.read_body(&blk)
|
|
109
|
+
when Net::HTTPNotFound
|
|
110
|
+
raise CFoundry::NotFound.new(response.body, 404)
|
|
111
|
+
when Net::HTTPForbidden
|
|
112
|
+
raise CFoundry::Denied.new(response.body, 403)
|
|
113
|
+
else
|
|
114
|
+
raise CFoundry::BadResponse.new(response.body, response.code)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
def needs_token_refresh?
|
|
123
|
+
token && token.auth_header && token.refresh_token && \
|
|
124
|
+
token.expires_soon?
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def status_is_successful?(code)
|
|
128
|
+
(code >= 200) && (code < 400)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def handle_response(response, options, request)
|
|
132
|
+
if status_is_successful?(response[:status].to_i)
|
|
133
|
+
handle_successful_response(response, options)
|
|
134
|
+
else
|
|
135
|
+
handle_error_response(response, request)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def handle_successful_response(response, options)
|
|
140
|
+
if options[:return_response]
|
|
141
|
+
response
|
|
142
|
+
elsif options[:accept] == :json
|
|
143
|
+
parse_json(response[:body])
|
|
144
|
+
else
|
|
145
|
+
response[:body]
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def handle_error_response(response, request)
|
|
150
|
+
body_json = parse_json(response[:body])
|
|
151
|
+
body_code = body_json && body_json[:code]
|
|
152
|
+
code = body_code || response[:status].to_i
|
|
153
|
+
|
|
154
|
+
if body_code
|
|
155
|
+
error_class = CFoundry::APIError.error_classes[body_code] || CFoundry::APIError
|
|
156
|
+
raise error_class.new(body_json[:description], body_code, request, response)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
case code
|
|
160
|
+
when 404
|
|
161
|
+
raise CFoundry::NotFound.new(nil, code, request, response)
|
|
162
|
+
when 403
|
|
163
|
+
raise CFoundry::Denied.new(nil, code, request, response)
|
|
164
|
+
else
|
|
165
|
+
raise CFoundry::BadResponse.new(nil, code, request, response)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def normalize_arguments(args)
|
|
170
|
+
if args.last.is_a?(Hash)
|
|
171
|
+
options = args.pop
|
|
172
|
+
else
|
|
173
|
+
options = {}
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
[normalize_path(args), options]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
URI_ENCODING_PATTERN = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
|
|
180
|
+
|
|
181
|
+
def normalize_path(segments)
|
|
182
|
+
if segments.size == 1 && segments.first =~ /^\//
|
|
183
|
+
segments.first
|
|
184
|
+
else
|
|
185
|
+
segments.flatten.collect { |x|
|
|
186
|
+
URI.encode(x.to_s, URI_ENCODING_PATTERN)
|
|
187
|
+
}.join("/")
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def parse_json(x)
|
|
192
|
+
if x.empty?
|
|
193
|
+
raise MultiJson::DecodeError.new("Empty JSON string", [], "")
|
|
194
|
+
else
|
|
195
|
+
MultiJson.load(x, :symbolize_keys => true)
|
|
196
|
+
end
|
|
197
|
+
rescue MultiJson::DecodeError
|
|
198
|
+
nil
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module CFoundry
|
|
2
|
+
class ChattyHash
|
|
3
|
+
include Enumerable
|
|
4
|
+
|
|
5
|
+
def initialize(callback, hash = {})
|
|
6
|
+
@callback = callback
|
|
7
|
+
@hash = hash
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def [](name)
|
|
11
|
+
@hash[name]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def []=(name, value)
|
|
15
|
+
@hash[name] = value
|
|
16
|
+
@callback.call(self)
|
|
17
|
+
value
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def each(&blk)
|
|
21
|
+
@hash.each(&blk)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delete(key)
|
|
25
|
+
value = @hash.delete(key)
|
|
26
|
+
@callback.call(self)
|
|
27
|
+
value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_json(*args)
|
|
31
|
+
@hash.to_json(*args)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_hash
|
|
35
|
+
@hash
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_s
|
|
39
|
+
@hash.to_s
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def inspect
|
|
43
|
+
@hash.inspect
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "cfoundry/baseclient"
|
|
2
|
+
require "cfoundry/rest_client"
|
|
3
|
+
require "cfoundry/auth_token"
|
|
4
|
+
|
|
5
|
+
require "cfoundry/v1/app"
|
|
6
|
+
require "cfoundry/v1/framework"
|
|
7
|
+
require "cfoundry/v1/runtime"
|
|
8
|
+
require "cfoundry/v1/service"
|
|
9
|
+
require "cfoundry/v1/service_plan"
|
|
10
|
+
require "cfoundry/v1/service_instance"
|
|
11
|
+
require "cfoundry/v1/user"
|
|
12
|
+
require "cfoundry/v1/base"
|
|
13
|
+
require "cfoundry/v1/client"
|
|
14
|
+
|
|
15
|
+
require "cfoundry/v2/app"
|
|
16
|
+
require "cfoundry/v2/framework"
|
|
17
|
+
require "cfoundry/v2/runtime"
|
|
18
|
+
require "cfoundry/v2/service"
|
|
19
|
+
require "cfoundry/v2/service_binding"
|
|
20
|
+
require "cfoundry/v2/service_instance"
|
|
21
|
+
require "cfoundry/v2/service_plan"
|
|
22
|
+
require "cfoundry/v2/service_auth_token"
|
|
23
|
+
require "cfoundry/v2/user"
|
|
24
|
+
require "cfoundry/v2/organization"
|
|
25
|
+
require "cfoundry/v2/space"
|
|
26
|
+
require "cfoundry/v2/domain"
|
|
27
|
+
require "cfoundry/v2/route"
|
|
28
|
+
require "cfoundry/v2/base"
|
|
29
|
+
require "cfoundry/v2/client"
|
|
30
|
+
|
|
31
|
+
module CFoundry
|
|
32
|
+
class Client < BaseClient
|
|
33
|
+
def self.new(*args)
|
|
34
|
+
target, _ = args
|
|
35
|
+
|
|
36
|
+
base = super(target)
|
|
37
|
+
|
|
38
|
+
case base.info[:version]
|
|
39
|
+
when 2
|
|
40
|
+
CFoundry::V2::Client.new(*args)
|
|
41
|
+
else
|
|
42
|
+
CFoundry::V1::Client.new(*args)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
require "net/https"
|
|
2
|
+
require "multi_json"
|
|
3
|
+
require "yaml"
|
|
4
|
+
|
|
5
|
+
module CFoundry
|
|
6
|
+
# Base class for CFoundry errors (not from the server).
|
|
7
|
+
class Error < RuntimeError
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Deprecated < Error
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class Mismatch < Error
|
|
14
|
+
def initialize(expected, got)
|
|
15
|
+
@expected = expected
|
|
16
|
+
@got = got
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
"Invalid value type; expected #{@expected.inspect}, got #{@got.inspect}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class InvalidTarget < Error
|
|
25
|
+
attr_reader :target
|
|
26
|
+
|
|
27
|
+
def initialize(target)
|
|
28
|
+
@target = target
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
"Invalid target URI: #{@target}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class TargetRefused < Error
|
|
37
|
+
# Error message.
|
|
38
|
+
attr_reader :message
|
|
39
|
+
|
|
40
|
+
# Message varies as this represents various network errors.
|
|
41
|
+
def initialize(message)
|
|
42
|
+
@message = message
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Exception message.
|
|
46
|
+
def to_s
|
|
47
|
+
"target refused connection (#@message)"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Timeout < Timeout::Error
|
|
52
|
+
attr_reader :method, :uri, :parent
|
|
53
|
+
|
|
54
|
+
def initialize(method, uri, parent = nil)
|
|
55
|
+
@method = method
|
|
56
|
+
@uri = uri
|
|
57
|
+
@parent = parent
|
|
58
|
+
super(to_s)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def to_s
|
|
62
|
+
"#{method} #{uri} timed out"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Exception representing errors returned by the API.
|
|
67
|
+
class APIError < RuntimeError
|
|
68
|
+
include TraceHelpers
|
|
69
|
+
|
|
70
|
+
class << self
|
|
71
|
+
def error_classes
|
|
72
|
+
@error_classes ||= {}
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
attr_reader :error_code, :description, :request, :response
|
|
77
|
+
|
|
78
|
+
# Create an APIError with a given request and response.
|
|
79
|
+
def initialize(description = nil, error_code = nil, request = nil, response = nil)
|
|
80
|
+
@response = response
|
|
81
|
+
@request = request
|
|
82
|
+
@error_code = error_code || (response ? response[:status] : nil)
|
|
83
|
+
@description = description || parse_description
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Exception message.
|
|
87
|
+
def to_s
|
|
88
|
+
"#{error_code}: #{description}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def request_trace
|
|
92
|
+
super(request)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def response_trace
|
|
96
|
+
super(response)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def parse_description
|
|
102
|
+
return unless response
|
|
103
|
+
|
|
104
|
+
parse_json(response[:body])[:description]
|
|
105
|
+
rescue MultiJson::DecodeError
|
|
106
|
+
response[:body]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def parse_json(x)
|
|
110
|
+
if x.empty?
|
|
111
|
+
raise MultiJson::DecodeError.new("Empty JSON string", [], "")
|
|
112
|
+
else
|
|
113
|
+
MultiJson.load(x, :symbolize_keys => true)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class NotFound < APIError
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class Denied < APIError
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
class BadResponse < APIError
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
class UAAError < APIError
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.define_error(class_name, code)
|
|
131
|
+
base =
|
|
132
|
+
case class_name
|
|
133
|
+
when /NotFound$/
|
|
134
|
+
NotFound
|
|
135
|
+
else
|
|
136
|
+
APIError
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
klass =
|
|
140
|
+
if const_defined?(class_name)
|
|
141
|
+
const_get(class_name)
|
|
142
|
+
else
|
|
143
|
+
Class.new(base)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
APIError.error_classes[code] = klass
|
|
147
|
+
|
|
148
|
+
unless const_defined?(class_name)
|
|
149
|
+
const_set(class_name, klass)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
VENDOR_DIR = File.expand_path("../../../vendor", __FILE__)
|
|
154
|
+
|
|
155
|
+
%w{errors/v1.yml errors/v2.yml}.each do |errors|
|
|
156
|
+
YAML.load_file("#{VENDOR_DIR}/#{errors}").each do |code, meta|
|
|
157
|
+
define_error(meta["name"], code)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|