vcap_common 1.0.10 → 2.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/json_message.rb +98 -45
- data/lib/services/api.rb +1 -0
- data/lib/services/api/async_requests.rb +45 -1
- data/lib/services/api/clients/sds_client.rb +84 -0
- data/lib/services/api/clients/service_gateway_client.rb +150 -73
- data/lib/services/api/const.rb +1 -0
- data/lib/services/api/messages.rb +35 -21
- data/lib/services/api/multipart.rb +191 -0
- data/lib/vcap/component.rb +1 -1
- data/lib/vcap/config.rb +3 -4
- data/lib/vcap/sorted_set_utils.rb +42 -0
- data/lib/vcap/spec/forked_component/base.rb +8 -3
- metadata +118 -37
- data/lib/json_schema.rb +0 -84
- data/lib/vcap/json_schema.rb +0 -202
data/lib/json_message.rb
CHANGED
@@ -1,46 +1,67 @@
|
|
1
|
-
# Copyright (c) 2009-2011 VMware, Inc
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc
|
2
2
|
require 'rubygems'
|
3
|
-
|
4
3
|
require 'yajl'
|
5
|
-
|
6
|
-
require 'json_schema'
|
4
|
+
require 'membrane'
|
7
5
|
|
8
6
|
class JsonMessage
|
9
|
-
# Base error class that all other JsonMessage related errors should
|
7
|
+
# Base error class that all other JsonMessage related errors should
|
8
|
+
# inherit from
|
10
9
|
class Error < StandardError
|
11
10
|
end
|
12
11
|
|
12
|
+
# Fields not defined properly.
|
13
|
+
class DefinitionError < Error
|
14
|
+
end
|
15
|
+
|
13
16
|
# Failed to parse json during +decode+
|
14
17
|
class ParseError < Error
|
15
18
|
end
|
16
19
|
|
17
20
|
# One or more field's values didn't match their schema
|
18
21
|
class ValidationError < Error
|
19
|
-
|
20
|
-
|
22
|
+
attr_reader :errors
|
23
|
+
|
24
|
+
def initialize(errors)
|
25
|
+
@errors = errors
|
21
26
|
end
|
22
27
|
|
23
28
|
def to_s
|
24
|
-
err_strs = @
|
29
|
+
err_strs = @errors.map { |f, e| "Field: #{f}, Error: #{e}" }
|
25
30
|
err_strs.join(', ')
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
29
34
|
class Field
|
30
|
-
attr_reader :name, :schema, :required
|
35
|
+
attr_reader :name, :schema, :required, :default
|
36
|
+
|
37
|
+
def initialize(name, options = {}, &blk)
|
38
|
+
blk ||= lambda { |*_| options[:schema] || any }
|
31
39
|
|
32
|
-
def initialize(name, schema, required=true)
|
33
40
|
@name = name
|
34
|
-
@schema =
|
35
|
-
@required = required
|
41
|
+
@schema = Membrane::SchemaParser.parse(&blk)
|
42
|
+
@required = options[:required] || false
|
43
|
+
@default = options[:default]
|
44
|
+
|
45
|
+
if @required && @default
|
46
|
+
raise DefinitionError, \
|
47
|
+
"Cannot define a default value for required field #{name}"
|
48
|
+
end
|
49
|
+
|
50
|
+
validate(@default) if @default
|
51
|
+
end
|
52
|
+
|
53
|
+
def validate(value)
|
54
|
+
begin
|
55
|
+
@schema.validate(value)
|
56
|
+
rescue Membrane::SchemaValidationError => e
|
57
|
+
raise ValidationError.new( { name => e.message } )
|
58
|
+
end
|
36
59
|
end
|
37
60
|
end
|
38
61
|
|
39
62
|
class << self
|
40
|
-
|
41
|
-
|
42
|
-
def schema(&blk)
|
43
|
-
instance_eval &blk
|
63
|
+
def fields
|
64
|
+
@fields ||= {}
|
44
65
|
end
|
45
66
|
|
46
67
|
def decode(json)
|
@@ -58,19 +79,23 @@ class JsonMessage
|
|
58
79
|
|
59
80
|
errs = {}
|
60
81
|
|
61
|
-
# Treat null values as if the keys aren't present. This isn't as strict
|
62
|
-
# but conforms to typical use cases.
|
82
|
+
# Treat null values as if the keys aren't present. This isn't as strict
|
83
|
+
# as one would like, but conforms to typical use cases.
|
63
84
|
dec_json.delete_if {|k, v| v == nil}
|
64
85
|
|
65
86
|
# Collect errors by field
|
66
|
-
|
87
|
+
fields.each do |name, field|
|
67
88
|
err = nil
|
68
|
-
|
69
|
-
|
70
|
-
|
89
|
+
if dec_json.has_key?(name.to_s)
|
90
|
+
begin
|
91
|
+
field.validate(dec_json[name.to_s])
|
92
|
+
rescue ValidationError => e
|
93
|
+
err = e.errors[name]
|
94
|
+
end
|
71
95
|
elsif field.required
|
72
96
|
err = "Missing field #{name}"
|
73
97
|
end
|
98
|
+
|
74
99
|
errs[name] = err if err
|
75
100
|
end
|
76
101
|
|
@@ -79,27 +104,27 @@ class JsonMessage
|
|
79
104
|
new(dec_json)
|
80
105
|
end
|
81
106
|
|
82
|
-
def required(
|
83
|
-
define_field(
|
107
|
+
def required(name, schema = nil, &blk)
|
108
|
+
define_field(name, :schema => schema, :required => true, &blk)
|
84
109
|
end
|
85
110
|
|
86
|
-
def optional(
|
87
|
-
define_field(
|
111
|
+
def optional(name, schema = nil, default = nil, &blk)
|
112
|
+
define_field(name, :schema => schema, :default => default, &blk)
|
88
113
|
end
|
89
114
|
|
90
115
|
protected
|
91
116
|
|
92
|
-
def define_field(name,
|
117
|
+
def define_field(name, options = {}, &blk)
|
93
118
|
name = name.to_sym
|
94
119
|
|
95
|
-
|
96
|
-
@fields[name] = Field.new(name, schema, required)
|
120
|
+
fields[name] = Field.new(name, options, &blk)
|
97
121
|
|
98
|
-
define_method
|
122
|
+
define_method(name) do
|
123
|
+
set_default(name)
|
99
124
|
@msg[name]
|
100
125
|
end
|
101
126
|
|
102
|
-
define_method
|
127
|
+
define_method("#{name}=") do |value|
|
103
128
|
set_field(name, value)
|
104
129
|
end
|
105
130
|
end
|
@@ -107,33 +132,61 @@ class JsonMessage
|
|
107
132
|
|
108
133
|
def initialize(fields={})
|
109
134
|
@msg = {}
|
110
|
-
fields.each {|
|
135
|
+
fields.each { |name, value| set_field(name, value) }
|
136
|
+
set_defaults
|
111
137
|
end
|
112
138
|
|
113
139
|
def encode
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
140
|
+
set_defaults
|
141
|
+
|
142
|
+
missing_fields = {}
|
143
|
+
|
144
|
+
self.class.fields.each do |name, field|
|
145
|
+
if field.required && !@msg.has_key?(name)
|
146
|
+
missing_fields[name] = "Missing field #{name}"
|
118
147
|
end
|
119
|
-
raise ValidationError.new(missing_fields) unless missing_fields.empty?
|
120
148
|
end
|
121
149
|
|
150
|
+
raise ValidationError.new(missing_fields) unless missing_fields.empty?
|
151
|
+
|
122
152
|
Yajl::Encoder.encode(@msg)
|
123
153
|
end
|
124
154
|
|
125
|
-
def extract
|
126
|
-
@msg.dup
|
155
|
+
def extract(opts = {})
|
156
|
+
hash = @msg.dup
|
157
|
+
if opts[:stringify_keys]
|
158
|
+
hash = hash.inject({}) { |memo,(k,v)| memo[k.to_s] = v; memo }.freeze
|
159
|
+
end
|
160
|
+
|
161
|
+
hash.freeze
|
127
162
|
end
|
128
163
|
|
129
164
|
protected
|
130
165
|
|
131
|
-
def set_field(
|
132
|
-
|
133
|
-
|
166
|
+
def set_field(name, value)
|
167
|
+
name = name.to_sym
|
168
|
+
field = self.class.fields[name]
|
169
|
+
|
170
|
+
unless field
|
171
|
+
raise ValidationError.new( { name => "Unknown field: #{name}" } )
|
172
|
+
end
|
134
173
|
|
135
|
-
|
136
|
-
|
137
|
-
|
174
|
+
field.validate(value)
|
175
|
+
@msg[name] = value
|
176
|
+
end
|
177
|
+
|
178
|
+
def set_defaults
|
179
|
+
self.class.fields.each do |name, _|
|
180
|
+
set_default(name)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def set_default(name)
|
185
|
+
unless @msg.has_key?(name)
|
186
|
+
field = self.class.fields[name]
|
187
|
+
if field
|
188
|
+
@msg[name] = field.default if field.default
|
189
|
+
end
|
190
|
+
end
|
138
191
|
end
|
139
192
|
end
|
data/lib/services/api.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'eventmachine'
|
3
3
|
require 'em-http-request'
|
4
4
|
require 'fiber'
|
5
|
+
require 'httpclient'
|
5
6
|
|
6
7
|
require 'services/api/const'
|
7
8
|
|
@@ -31,11 +32,54 @@ module VCAP::Services::Api
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
|
-
def
|
35
|
+
def request(url, token, verb, timeout, msg=VCAP::Services::Api::EMPTY_REQUEST)
|
35
36
|
req = new(url, token, verb, timeout, msg)
|
36
37
|
f = Fiber.current
|
37
38
|
req.callback { f.resume(req) }
|
38
39
|
req.errback { f.resume(req) }
|
40
|
+
http = Fiber.yield
|
41
|
+
raise UnexpectedResponse, "Error sending request #{msg.extract.to_json} to gateway #{@url}: #{http.error}" unless http.error.empty?
|
42
|
+
code = http.response_header.status.to_i
|
43
|
+
body = http.response
|
44
|
+
[code, body]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module SynchronousHttpRequest
|
50
|
+
def self.request(url, token, verb, timeout, msg=VCAP::Services::Api::EMPTY_REQUEST)
|
51
|
+
header = {
|
52
|
+
VCAP::Services::Api::GATEWAY_TOKEN_HEADER => token,
|
53
|
+
'Content-Type' => 'application/json',
|
54
|
+
}
|
55
|
+
body = msg.encode
|
56
|
+
client = HTTPClient.new
|
57
|
+
msg = client.request(verb.to_sym, url, :body => body, :header => header)
|
58
|
+
[msg.code, msg.body]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class AsyncHttpMultiPartUpload
|
63
|
+
class << self
|
64
|
+
def new(url, timeout, multipart, head={})
|
65
|
+
req = {
|
66
|
+
:head => head,
|
67
|
+
:body => "",
|
68
|
+
:multipart => multipart
|
69
|
+
}
|
70
|
+
|
71
|
+
if timeout
|
72
|
+
EM::HttpRequest.new(url, :inactivity_timeout => timeout).post req
|
73
|
+
else
|
74
|
+
EM::HttpRequest.new(url).post req
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def fibered(url, timeout, multipart, head={})
|
79
|
+
req = new(url, timeout, multipart, head)
|
80
|
+
f = Fiber.current
|
81
|
+
req.callback { f.resume(req) }
|
82
|
+
req.errback {f.resume(req)}
|
39
83
|
Fiber.yield
|
40
84
|
end
|
41
85
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/http/post/multipart'
|
4
|
+
require 'mime/types'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
require 'services/api/const'
|
8
|
+
require 'services/api/messages'
|
9
|
+
require 'services/api/multipart'
|
10
|
+
|
11
|
+
module VCAP
|
12
|
+
module Services
|
13
|
+
module Api
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module VCAP::Services::Api
|
19
|
+
class SDSClient
|
20
|
+
|
21
|
+
class SDSErrorResponse < StandardError; end
|
22
|
+
class UnexpectedResponse < StandardError; end
|
23
|
+
|
24
|
+
def initialize(url, upload_token, timeout=60, opts={})
|
25
|
+
@url = url
|
26
|
+
@timeout = timeout
|
27
|
+
@hdrs = {
|
28
|
+
'Content-Type' => 'application/json',
|
29
|
+
}
|
30
|
+
@upload_hdrs = {
|
31
|
+
'Content-Type' => 'multipart/form-data',
|
32
|
+
SDS_UPLOAD_TOKEN_HEADER => upload_token
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def import_from_data(args)
|
37
|
+
resp = perform_multipart_upload("/serialized/#{args[:service]}/#{args[:service_id]}/serialized/data", args[:msg])
|
38
|
+
SerializedURL.decode(resp)
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def perform_multipart_upload(path, file_path)
|
44
|
+
# upload file using multipart/form data
|
45
|
+
result = nil
|
46
|
+
uri = URI.parse(@url)
|
47
|
+
|
48
|
+
mime_types = MIME::Types.type_for(file_path) || []
|
49
|
+
mime_types << "application/octet-stream" if mime_types.empty?
|
50
|
+
|
51
|
+
if EM.reactor_running?
|
52
|
+
payload = {:_method => 'put', :data_file => EM::StreamUploadIO.new(file_path, mime_types[0])}
|
53
|
+
multipart = EM::Multipart.new(payload, @upload_hdrs)
|
54
|
+
url = URI.parse(uri.to_s + path)
|
55
|
+
http = AsyncHttpMultiPartUpload.fibered(url, @timeout, multipart)
|
56
|
+
raise UnexpectedResponse, "Error uploading #{file_path} to serialized_data_server #{@url}: #{http.error}" unless http.error.empty?
|
57
|
+
code = http.response_header.status.to_i
|
58
|
+
body = http.response
|
59
|
+
else
|
60
|
+
payload = {:_method => 'put', :data_file => UploadIO.new(file_path, mime_types[0])}
|
61
|
+
req = Net::HTTP::Post::Multipart.new(path, payload, @upload_hdrs)
|
62
|
+
resp = Net::HTTP.new(uri.host, uri.port).start do |http|
|
63
|
+
http.request(req)
|
64
|
+
end
|
65
|
+
code = resp.code.to_i
|
66
|
+
body = resp.body
|
67
|
+
end
|
68
|
+
case code
|
69
|
+
when 200
|
70
|
+
body
|
71
|
+
when 400
|
72
|
+
raise SDSErrorResponse, "Fail to upload the file to serialization_data_server."
|
73
|
+
when 403
|
74
|
+
raise SDSErrorResponse, "You are forbidden to access serialization_data_server."
|
75
|
+
when 404
|
76
|
+
raise SDSErrorResponse, "Not found in serialization_data_server."
|
77
|
+
when 501
|
78
|
+
raise SDSErrorResponse, "Serialized data file is recognized, but file not found in serialization_data_server."
|
79
|
+
else
|
80
|
+
raise UnexpectedResponse, "Unexpected exception in serialization_data_server: #{(uri.to_s + path)} #{code} #{body}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# Copyright (c) 2009-2011 VMware, Inc.
|
2
2
|
require 'net/http'
|
3
|
+
require 'uri'
|
3
4
|
|
4
5
|
require 'services/api/const'
|
5
6
|
require 'services/api/messages'
|
7
|
+
require 'services/api/async_requests'
|
6
8
|
|
7
9
|
module VCAP
|
8
10
|
module Services
|
@@ -11,97 +13,172 @@ module VCAP
|
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
14
|
-
|
16
|
+
module VCAP::Services::Api
|
17
|
+
class ServiceGatewayClient
|
18
|
+
METHODS_MAP = {
|
19
|
+
:get => Net::HTTP::Get,
|
20
|
+
:post=> Net::HTTP::Post,
|
21
|
+
:put => Net::HTTP::Put,
|
22
|
+
:delete => Net::HTTP::Delete,
|
23
|
+
}
|
15
24
|
|
16
|
-
|
17
|
-
|
25
|
+
# Public: Indicate gateway client encounter an unexpected error,
|
26
|
+
# such as can't connect to gateway or can't decode response.
|
27
|
+
#
|
28
|
+
class UnexpectedResponse < StandardError; end
|
29
|
+
|
30
|
+
# Public: Indicate an error response from gateway
|
31
|
+
#
|
32
|
+
class ErrorResponse < StandardError
|
33
|
+
attr_reader :status, :error
|
34
|
+
|
35
|
+
# status - the http status
|
36
|
+
# error - a ServiceErrorResponse object
|
37
|
+
#
|
38
|
+
def initialize(status, error)
|
39
|
+
@status = status
|
40
|
+
@error = error
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
"Reponse status:#{status},error:[#{error.extract}]"
|
45
|
+
end
|
46
|
+
end
|
18
47
|
|
19
|
-
|
20
|
-
|
48
|
+
class NotFoundResponse < ErrorResponse
|
49
|
+
def initialize(error)
|
50
|
+
super(404, error)
|
51
|
+
end
|
21
52
|
end
|
22
|
-
end
|
23
53
|
|
24
|
-
|
54
|
+
class GatewayInternalResponse < ErrorResponse
|
55
|
+
def initialize(error)
|
56
|
+
super(503, error)
|
57
|
+
end
|
58
|
+
end
|
25
59
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
60
|
+
attr_reader :host, :port, :token
|
61
|
+
attr_reader :requester
|
62
|
+
def initialize(url, token, timeout, opts={})
|
63
|
+
@url = url
|
64
|
+
@timeout = timeout
|
65
|
+
@token = token
|
66
|
+
@hdrs = {
|
67
|
+
'Content-Type' => 'application/json',
|
68
|
+
GATEWAY_TOKEN_HEADER => @token
|
69
|
+
}
|
70
|
+
# contract: @requester.responds_to? :request(url, token, timeout, [msg])
|
71
|
+
# contract @requester.request(url, token, timeout, [msg]) => [code, body]
|
72
|
+
@requester = opts[:requester] || AsyncHttpRequest
|
73
|
+
end
|
35
74
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
75
|
+
def provision(args)
|
76
|
+
msg = GatewayProvisionRequest.new(args)
|
77
|
+
resp = perform_request(:post, '/gateway/v1/configurations', msg)
|
78
|
+
GatewayHandleResponse.decode(resp)
|
79
|
+
end
|
41
80
|
|
42
|
-
|
43
|
-
|
44
|
-
|
81
|
+
def unprovision(args)
|
82
|
+
resp = perform_request(:delete, "/gateway/v1/configurations/#{args[:service_id]}")
|
83
|
+
EMPTY_REQUEST
|
84
|
+
end
|
45
85
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
86
|
+
def create_snapshot(args)
|
87
|
+
resp = perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/snapshots")
|
88
|
+
Job.decode(resp)
|
89
|
+
end
|
50
90
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
91
|
+
def enum_snapshots(args)
|
92
|
+
resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/snapshots")
|
93
|
+
SnapshotList.decode(resp)
|
94
|
+
end
|
55
95
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
96
|
+
def snapshot_details(args)
|
97
|
+
resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
98
|
+
Snapshot.decode(resp)
|
99
|
+
end
|
60
100
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
101
|
+
def update_snapshot_name(args)
|
102
|
+
perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}/name", args[:msg])
|
103
|
+
EMPTY_REQUEST
|
104
|
+
end
|
65
105
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
106
|
+
def rollback_snapshot(args)
|
107
|
+
resp = perform_request(:put, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
108
|
+
Job.decode(resp)
|
109
|
+
end
|
70
110
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
111
|
+
def delete_snapshot(args)
|
112
|
+
resp = perform_request(:delete, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
113
|
+
Job.decode(resp)
|
114
|
+
end
|
75
115
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
116
|
+
def create_serialized_url(args)
|
117
|
+
resp = perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url/snapshots/#{args[:snapshot_id]}")
|
118
|
+
Job.decode(resp)
|
119
|
+
end
|
80
120
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
121
|
+
def serialized_url(args)
|
122
|
+
resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url/snapshots/#{args[:snapshot_id]}")
|
123
|
+
SerializedURL.decode(resp)
|
124
|
+
end
|
85
125
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
126
|
+
def import_from_url(args)
|
127
|
+
resp = perform_request(:put, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url", args[:msg])
|
128
|
+
Job.decode(resp)
|
129
|
+
end
|
91
130
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
131
|
+
def job_info(args)
|
132
|
+
resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/jobs/#{args[:job_id]}")
|
133
|
+
Job.decode(resp)
|
134
|
+
end
|
96
135
|
|
97
|
-
|
136
|
+
def bind(args)
|
137
|
+
msg = GatewayBindRequest.new(args)
|
138
|
+
resp = perform_request(:post, "/gateway/v1/configurations/#{msg.service_id}/handles", msg)
|
139
|
+
GatewayHandleResponse.decode(resp)
|
140
|
+
end
|
98
141
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
resp
|
105
|
-
end
|
142
|
+
def unbind(args)
|
143
|
+
msg = GatewayUnbindRequest.new(args)
|
144
|
+
perform_request(:delete, "/gateway/v1/configurations/#{msg.service_id}/handles/#{msg.handle_id}", msg)
|
145
|
+
EMPTY_REQUEST
|
146
|
+
end
|
106
147
|
|
148
|
+
protected
|
149
|
+
|
150
|
+
def perform_request(http_method, path, msg=VCAP::Services::Api::EMPTY_REQUEST)
|
151
|
+
result = nil
|
152
|
+
uri = URI.parse(@url)
|
153
|
+
if EM.reactor_running?
|
154
|
+
url = URI.parse(uri.to_s + path)
|
155
|
+
code, body = requester.request(url, @token, http_method, @timeout, msg)
|
156
|
+
else
|
157
|
+
klass = METHODS_MAP[http_method]
|
158
|
+
req = klass.new(path, initheader=@hdrs)
|
159
|
+
req.body = msg.encode
|
160
|
+
resp = Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req)}
|
161
|
+
code = resp.code.to_i
|
162
|
+
body = resp.body
|
163
|
+
end
|
164
|
+
case code
|
165
|
+
when 200
|
166
|
+
body
|
167
|
+
when 404
|
168
|
+
err = ServiceErrorResponse.decode(body)
|
169
|
+
raise NotFoundResponse.new(err)
|
170
|
+
when 503
|
171
|
+
err = ServiceErrorResponse.decode(body)
|
172
|
+
raise GatewayInternalResponse.new(err)
|
173
|
+
else
|
174
|
+
begin
|
175
|
+
# try to decode the response
|
176
|
+
err = ServiceErrorResponse.decode(body)
|
177
|
+
rescue => e
|
178
|
+
raise UnexpectedResponse, "Can't decode gateway response. status code:#{code}, response body:#{body}"
|
179
|
+
end
|
180
|
+
raise ErrorResponse.new(code, err)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
107
184
|
end
|