vcap_common 1.0.10 → 2.0.8
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/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
|