vcap_services_base 0.2.10
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.
- checksums.yaml +7 -0
- data/lib/base/abstract.rb +11 -0
- data/lib/base/api/message.rb +31 -0
- data/lib/base/asynchronous_service_gateway.rb +529 -0
- data/lib/base/backup.rb +206 -0
- data/lib/base/barrier.rb +54 -0
- data/lib/base/base.rb +159 -0
- data/lib/base/base_async_gateway.rb +164 -0
- data/lib/base/base_job.rb +5 -0
- data/lib/base/catalog_manager_base.rb +67 -0
- data/lib/base/catalog_manager_v1.rb +225 -0
- data/lib/base/catalog_manager_v2.rb +291 -0
- data/lib/base/cloud_controller_services.rb +75 -0
- data/lib/base/datamapper_l.rb +148 -0
- data/lib/base/gateway.rb +167 -0
- data/lib/base/gateway_service_catalog.rb +68 -0
- data/lib/base/http_handler.rb +101 -0
- data/lib/base/job/async_job.rb +71 -0
- data/lib/base/job/config.rb +27 -0
- data/lib/base/job/lock.rb +153 -0
- data/lib/base/job/package.rb +112 -0
- data/lib/base/job/serialization.rb +365 -0
- data/lib/base/job/snapshot.rb +354 -0
- data/lib/base/node.rb +471 -0
- data/lib/base/node_bin.rb +154 -0
- data/lib/base/plan.rb +63 -0
- data/lib/base/provisioner.rb +1120 -0
- data/lib/base/provisioner_v1.rb +125 -0
- data/lib/base/provisioner_v2.rb +193 -0
- data/lib/base/service.rb +93 -0
- data/lib/base/service_advertiser.rb +184 -0
- data/lib/base/service_error.rb +122 -0
- data/lib/base/service_message.rb +94 -0
- data/lib/base/service_plan_change_set.rb +11 -0
- data/lib/base/simple_aop.rb +63 -0
- data/lib/base/snapshot_v2/snapshot.rb +227 -0
- data/lib/base/snapshot_v2/snapshot_client.rb +158 -0
- data/lib/base/snapshot_v2/snapshot_job.rb +95 -0
- data/lib/base/utils.rb +63 -0
- data/lib/base/version.rb +7 -0
- data/lib/base/warden/instance_utils.rb +161 -0
- data/lib/base/warden/node_utils.rb +205 -0
- data/lib/base/warden/service.rb +426 -0
- data/lib/base/worker_bin.rb +76 -0
- data/lib/vcap_services_base.rb +16 -0
- metadata +364 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7305761e681e387c91d65dac8b89f8e2b64e8d30
|
4
|
+
data.tar.gz: 05c46995ea778aa60afa54f126d04e44fcf4c141
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9f4566a5e13cb08ddec54346c25d94e8ee33fc9274077fe268600444fed05a8ee324ae857b082a13aaececcb9cdf118ef31bb3cb3c15c8af2075c174168f561e
|
7
|
+
data.tar.gz: 5471d45f69760f4bf963eda9cfdb4cb51e505e9ec722ef8a4d94a1580086dbd446e86ae82be880426ea72d4ada5cc89fd9c03b12517724497cb66235be4c9b67
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
class Class
|
3
|
+
def abstract(*args)
|
4
|
+
args.each do |method_name|
|
5
|
+
define_method(method_name) do |*args|
|
6
|
+
raise NotImplementedError.new("Unimplemented abstract method #{self.class.name}##{method_name}")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
#
|
3
|
+
$:.unshift(File.expand_path("../..", __FILE__))
|
4
|
+
require 'json_message'
|
5
|
+
require 'base'
|
6
|
+
|
7
|
+
class ServiceMessage < JsonMessage
|
8
|
+
|
9
|
+
def set_field(field, value)
|
10
|
+
field = field.to_sym
|
11
|
+
return unless self.class.fields.has_key?(field)
|
12
|
+
f = self.class.fields[field]
|
13
|
+
# delete an optional field
|
14
|
+
if value.nil? and f.required == false
|
15
|
+
@msg.delete(field)
|
16
|
+
else
|
17
|
+
errs = f.schema.validate(value)
|
18
|
+
raise ValidationError.new({field => errs}) if errs
|
19
|
+
@msg[field] = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return a deep copy of @msg
|
24
|
+
def dup
|
25
|
+
@msg.deep_dup
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
@msg.inspect
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,529 @@
|
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
require 'base_async_gateway'
|
3
|
+
require 'gateway_service_catalog'
|
4
|
+
|
5
|
+
$:.unshift(File.dirname(__FILE__))
|
6
|
+
|
7
|
+
# A simple service gateway that proxies requests onto an asynchronous service provisioners.
|
8
|
+
# NB: Do not use this with synchronous provisioners, it will produce unexpected results.
|
9
|
+
#
|
10
|
+
# TODO(mjp): This needs to handle unknown routes
|
11
|
+
module VCAP::Services
|
12
|
+
class AsynchronousServiceGateway < BaseAsynchronousServiceGateway
|
13
|
+
|
14
|
+
REQ_OPTS = %w(service token provisioner cloud_controller_uri).map { |o| o.to_sym }
|
15
|
+
attr_reader :event_machine, :logger, :service
|
16
|
+
|
17
|
+
def initialize(opts)
|
18
|
+
super(opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
# setup the environment
|
22
|
+
def setup(opts)
|
23
|
+
missing_opts = REQ_OPTS.select { |o| !opts.has_key? o }
|
24
|
+
raise ArgumentError, "Missing options: #{missing_opts.join(', ')}" unless missing_opts.empty?
|
25
|
+
@service = opts[:service]
|
26
|
+
@token = opts[:token]
|
27
|
+
@logger = opts[:logger] || make_logger()
|
28
|
+
@cld_ctrl_uri = http_uri(opts[:cloud_controller_uri])
|
29
|
+
@provisioner = opts[:provisioner]
|
30
|
+
@hb_interval = opts[:heartbeat_interval] || 60
|
31
|
+
@node_timeout = opts[:node_timeout]
|
32
|
+
@handle_fetch_interval = opts[:handle_fetch_interval] || 1
|
33
|
+
@check_orphan_interval = opts[:check_orphan_interval] || -1
|
34
|
+
@double_check_orphan_interval = opts[:double_check_orphan_interval] || 300
|
35
|
+
@handle_fetched = opts[:handle_fetched] || false
|
36
|
+
@fetching_handles = false
|
37
|
+
@version_aliases = (service[:version_aliases] ||= {})
|
38
|
+
|
39
|
+
opts[:gateway_name] ||= "Service Gateway"
|
40
|
+
|
41
|
+
@cc_api_version = opts[:cc_api_version] || "v1"
|
42
|
+
if @cc_api_version == "v1"
|
43
|
+
require 'catalog_manager_v1'
|
44
|
+
@catalog_manager = VCAP::Services::CatalogManagerV1.new(opts)
|
45
|
+
elsif @cc_api_version == "v2"
|
46
|
+
require 'catalog_manager_v2'
|
47
|
+
@catalog_manager = VCAP::Services::CatalogManagerV2.new(opts)
|
48
|
+
else
|
49
|
+
raise "Unknown cc_api_version: #{@cc_api_version}"
|
50
|
+
end
|
51
|
+
|
52
|
+
@event_machine = opts[:event_machine] || EM
|
53
|
+
|
54
|
+
# Setup heartbeats and exit handlers
|
55
|
+
event_machine.add_periodic_timer(@hb_interval) { send_heartbeat }
|
56
|
+
event_machine.next_tick { send_heartbeat }
|
57
|
+
Kernel.at_exit do
|
58
|
+
if event_machine.reactor_running?
|
59
|
+
# :/ We can't stop others from killing the event-loop here. Let's hope that they play nice
|
60
|
+
send_deactivation_notice(false)
|
61
|
+
else
|
62
|
+
event_machine.run { send_deactivation_notice }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Add any necessary handles we don't know about
|
67
|
+
update_callback = Proc.new do |resp|
|
68
|
+
@provisioner.update_handles(resp.handles)
|
69
|
+
@handle_fetched = true
|
70
|
+
event_machine.cancel_timer(@fetch_handle_timer)
|
71
|
+
|
72
|
+
# TODO remove it when we finish the migration
|
73
|
+
current_version = @version_aliases && @version_aliases[:current]
|
74
|
+
if current_version
|
75
|
+
@provisioner.update_version_info(current_version)
|
76
|
+
else
|
77
|
+
logger.info("No current version alias is supplied, skip update version in CCDB.")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
@fetch_handle_timer = event_machine.add_periodic_timer(@handle_fetch_interval) { fetch_handles(&update_callback) }
|
82
|
+
event_machine.next_tick { fetch_handles(&update_callback) }
|
83
|
+
|
84
|
+
if @check_orphan_interval > 0
|
85
|
+
handler_check_orphan = Proc.new do |resp|
|
86
|
+
check_orphan(resp.handles,
|
87
|
+
lambda { logger.info("Check orphan is requested") },
|
88
|
+
lambda { |errmsg| logger.error("Error on requesting to check orphan #{errmsg}") })
|
89
|
+
end
|
90
|
+
event_machine.add_periodic_timer(@check_orphan_interval) { fetch_handles(&handler_check_orphan) }
|
91
|
+
end
|
92
|
+
|
93
|
+
# Register update handle callback
|
94
|
+
@provisioner.register_update_handle_callback { |handle, &blk| update_service_handle(handle, &blk) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_current_catalog
|
98
|
+
GatewayServiceCatalog.new([service]).to_hash
|
99
|
+
end
|
100
|
+
|
101
|
+
def check_orphan(handles, callback, errback)
|
102
|
+
@provisioner.check_orphan(handles) do |msg|
|
103
|
+
if msg['success']
|
104
|
+
callback.call
|
105
|
+
event_machine.add_timer(@double_check_orphan_interval) { fetch_handles { |rs| @provisioner.double_check_orphan(rs.handles) } }
|
106
|
+
else
|
107
|
+
errback.call(msg['response'])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Validate the incoming request
|
113
|
+
def validate_incoming_request
|
114
|
+
unless request.media_type == Rack::Mime.mime_type('.json')
|
115
|
+
error_msg = ServiceError.new(ServiceError::INVALID_CONTENT).to_hash
|
116
|
+
logger.error("Validation failure: #{error_msg.inspect}, request media type: #{request.media_type} is not json")
|
117
|
+
abort_request(error_msg)
|
118
|
+
end
|
119
|
+
unless auth_token && (auth_token == @token)
|
120
|
+
error_msg = ServiceError.new(ServiceError::NOT_AUTHORIZED).to_hash
|
121
|
+
logger.error("Validation failure: #{error_msg.inspect}, expected token: #{@token}, specified token: #{auth_token}")
|
122
|
+
abort_request(error_msg)
|
123
|
+
end
|
124
|
+
unless @handle_fetched
|
125
|
+
error_msg = ServiceError.new(ServiceError::SERVICE_UNAVAILABLE).to_hash
|
126
|
+
logger.error("Validation failure: #{error_msg.inspect}, handles not fetched")
|
127
|
+
abort_request(error_msg)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
#################### Handlers ####################
|
132
|
+
|
133
|
+
# Provisions an instance of the service
|
134
|
+
#
|
135
|
+
post '/gateway/v1/configurations' do
|
136
|
+
req = VCAP::Services::Api::GatewayProvisionRequest.decode(request_body)
|
137
|
+
@logger.debug("Provision request for unique_id=#{req.unique_id}")
|
138
|
+
|
139
|
+
unless plan_exists?(req)
|
140
|
+
error_msg = ServiceError.new(ServiceError::UNKNOWN_PLAN_UNIQUE_ID).to_hash
|
141
|
+
abort_request(error_msg)
|
142
|
+
end
|
143
|
+
|
144
|
+
@provisioner.provision_service(req) do |msg|
|
145
|
+
if msg['success']
|
146
|
+
async_reply(VCAP::Services::Api::GatewayHandleResponse.new(msg['response']).encode)
|
147
|
+
else
|
148
|
+
async_reply_error(msg['response'])
|
149
|
+
end
|
150
|
+
end
|
151
|
+
async_mode
|
152
|
+
end
|
153
|
+
|
154
|
+
# Unprovisions a previously provisioned instance of the service
|
155
|
+
#
|
156
|
+
delete '/gateway/v1/configurations/:service_id' do
|
157
|
+
logger.debug("Unprovision request for service_id=#{params['service_id']}")
|
158
|
+
|
159
|
+
@provisioner.unprovision_service(params['service_id']) do |msg|
|
160
|
+
if msg['success']
|
161
|
+
async_reply
|
162
|
+
else
|
163
|
+
async_reply_error(msg['response'])
|
164
|
+
end
|
165
|
+
end
|
166
|
+
async_mode
|
167
|
+
end
|
168
|
+
|
169
|
+
# Binds a previously provisioned instance of the service to an application
|
170
|
+
#
|
171
|
+
post '/gateway/v1/configurations/:service_id/handles' do
|
172
|
+
logger.info("Binding request for service=#{params['service_id']}")
|
173
|
+
|
174
|
+
req = VCAP::Services::Api::GatewayBindRequest.decode(request_body)
|
175
|
+
logger.debug("Binding request: #{req.extract}")
|
176
|
+
|
177
|
+
@provisioner.bind_instance(req.service_id, req.binding_options) do |msg|
|
178
|
+
if msg['success']
|
179
|
+
async_reply(VCAP::Services::Api::GatewayHandleResponse.new(msg['response']).encode)
|
180
|
+
else
|
181
|
+
async_reply_error(msg['response'])
|
182
|
+
end
|
183
|
+
end
|
184
|
+
async_mode
|
185
|
+
end
|
186
|
+
|
187
|
+
# Unbinds a previously bound instance of the service
|
188
|
+
#
|
189
|
+
delete '/gateway/v1/configurations/:service_id/handles/:handle_id' do
|
190
|
+
logger.info("Unbind request for service_id={params['service_id']} handle_id=#{params['handle_id']}")
|
191
|
+
|
192
|
+
req = VCAP::Services::Api::GatewayUnbindRequest.decode(request_body)
|
193
|
+
|
194
|
+
@provisioner.unbind_instance(req.service_id, req.handle_id, req.binding_options) do |msg|
|
195
|
+
if msg['success']
|
196
|
+
async_reply
|
197
|
+
else
|
198
|
+
async_reply_error(msg['response'])
|
199
|
+
end
|
200
|
+
end
|
201
|
+
async_mode
|
202
|
+
end
|
203
|
+
|
204
|
+
post "/gateway/v2/configurations/:service_id/snapshots" do
|
205
|
+
service_id = params["service_id"]
|
206
|
+
name = Yajl::Parser.parse(request_body).fetch('name')
|
207
|
+
|
208
|
+
@provisioner.create_snapshot_v2(service_id, name) do |msg|
|
209
|
+
if msg['success']
|
210
|
+
async_reply(VCAP::Services::Api::SnapshotV2.new(msg['response']).encode)
|
211
|
+
else
|
212
|
+
async_reply_error(msg['response'])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
async_mode
|
216
|
+
end
|
217
|
+
|
218
|
+
# create a snapshot
|
219
|
+
post "/gateway/v1/configurations/:service_id/snapshots" do
|
220
|
+
service_id = params["service_id"]
|
221
|
+
@provisioner.create_snapshot(service_id) do |msg|
|
222
|
+
if msg['success']
|
223
|
+
async_reply(VCAP::Services::Api::Job.new(msg['response']).encode)
|
224
|
+
else
|
225
|
+
async_reply_error(msg['response'])
|
226
|
+
end
|
227
|
+
async_reply
|
228
|
+
end
|
229
|
+
async_mode
|
230
|
+
end
|
231
|
+
|
232
|
+
# Get snapshot details
|
233
|
+
get "/gateway/v1/configurations/:service_id/snapshots/:snapshot_id" do
|
234
|
+
service_id = params["service_id"]
|
235
|
+
snapshot_id = params["snapshot_id"]
|
236
|
+
logger.info("Get snapshot_id=#{snapshot_id} request for service_id=#{service_id}")
|
237
|
+
@provisioner.get_snapshot(service_id, snapshot_id) do |msg|
|
238
|
+
if msg['success']
|
239
|
+
async_reply(VCAP::Services::Api::Snapshot.new(msg['response']).encode)
|
240
|
+
else
|
241
|
+
async_reply_error(msg['response'])
|
242
|
+
end
|
243
|
+
end
|
244
|
+
async_mode
|
245
|
+
end
|
246
|
+
|
247
|
+
# Update snapshot name
|
248
|
+
post "/gateway/v1/configurations/:service_id/snapshots/:snapshot_id/name" do
|
249
|
+
req = VCAP::Services::Api::UpdateSnapshotNameRequest.decode(request_body)
|
250
|
+
service_id = params["service_id"]
|
251
|
+
snapshot_id = params["snapshot_id"]
|
252
|
+
logger.info("Update name of snapshot=#{snapshot_id} for service_id=#{service_id} to '#{req.name}'")
|
253
|
+
@provisioner.update_snapshot_name(service_id, snapshot_id, req.name) do |msg|
|
254
|
+
if msg['success']
|
255
|
+
async_reply
|
256
|
+
else
|
257
|
+
async_reply_error(msg['response'])
|
258
|
+
end
|
259
|
+
end
|
260
|
+
async_mode
|
261
|
+
end
|
262
|
+
|
263
|
+
# Enumerate snapshot
|
264
|
+
get "/gateway/v1/configurations/:service_id/snapshots" do
|
265
|
+
service_id = params["service_id"]
|
266
|
+
logger.info("Enumerate snapshots request for service_id=#{service_id}")
|
267
|
+
@provisioner.enumerate_snapshots(service_id) do |msg|
|
268
|
+
if msg['success']
|
269
|
+
async_reply(VCAP::Services::Api::SnapshotList.new(msg['response']).encode)
|
270
|
+
else
|
271
|
+
async_reply_error(msg['response'])
|
272
|
+
end
|
273
|
+
end
|
274
|
+
async_mode
|
275
|
+
end
|
276
|
+
|
277
|
+
get "/gateway/v2/configurations/:service_id/snapshots" do
|
278
|
+
service_id = params["service_id"]
|
279
|
+
logger.info("Enumerate snapshots request for service_id=#{service_id}")
|
280
|
+
@provisioner.enumerate_snapshots_v2(params["service_id"]) do |msg|
|
281
|
+
if msg['success']
|
282
|
+
async_reply(VCAP::Services::Api::SnapshotListV2.new(:snapshots => msg['response']).encode)
|
283
|
+
else
|
284
|
+
async_reply_error(msg['response'])
|
285
|
+
end
|
286
|
+
end
|
287
|
+
async_mode
|
288
|
+
end
|
289
|
+
|
290
|
+
# Rollback to a snapshot
|
291
|
+
put "/gateway/v1/configurations/:service_id/snapshots/:snapshot_id" do
|
292
|
+
service_id = params["service_id"]
|
293
|
+
snapshot_id = params["snapshot_id"]
|
294
|
+
logger.info("Rollback service_id=#{service_id} to snapshot_id=#{snapshot_id}")
|
295
|
+
@provisioner.rollback_snapshot(service_id, snapshot_id) do |msg|
|
296
|
+
if msg['success']
|
297
|
+
async_reply(VCAP::Services::Api::Job.new(msg['response']).encode)
|
298
|
+
else
|
299
|
+
async_reply_error(msg['response'])
|
300
|
+
end
|
301
|
+
end
|
302
|
+
async_mode
|
303
|
+
end
|
304
|
+
|
305
|
+
# Delete a snapshot
|
306
|
+
delete "/gateway/v1/configurations/:service_id/snapshots/:snapshot_id" do
|
307
|
+
service_id = params["service_id"]
|
308
|
+
snapshot_id = params["snapshot_id"]
|
309
|
+
logger.info("Delete service_id=#{service_id} to snapshot_id=#{snapshot_id}")
|
310
|
+
@provisioner.delete_snapshot(service_id, snapshot_id) do |msg|
|
311
|
+
if msg['success']
|
312
|
+
async_reply(VCAP::Services::Api::Job.new(msg['response']).encode)
|
313
|
+
else
|
314
|
+
async_reply_error(msg['response'])
|
315
|
+
end
|
316
|
+
end
|
317
|
+
async_mode
|
318
|
+
end
|
319
|
+
|
320
|
+
# Create a serialized url for a service snapshot
|
321
|
+
post "/gateway/v1/configurations/:service_id/serialized/url/snapshots/:snapshot_id" do
|
322
|
+
service_id = params["service_id"]
|
323
|
+
snapshot_id = params["snapshot_id"]
|
324
|
+
logger.info("Create serialized url for snapshot=#{snapshot_id} of service_id=#{service_id} ")
|
325
|
+
@provisioner.create_serialized_url(service_id, snapshot_id) do |msg|
|
326
|
+
if msg['success']
|
327
|
+
async_reply(VCAP::Services::Api::Job.new(msg['response']).encode)
|
328
|
+
else
|
329
|
+
async_reply_error(msg['response'])
|
330
|
+
end
|
331
|
+
end
|
332
|
+
async_mode
|
333
|
+
end
|
334
|
+
|
335
|
+
# Get serialized url for a service snapshot
|
336
|
+
get "/gateway/v1/configurations/:service_id/serialized/url/snapshots/:snapshot_id" do
|
337
|
+
service_id = params["service_id"]
|
338
|
+
snapshot_id = params["snapshot_id"]
|
339
|
+
logger.info("Get serialized url for snapshot=#{snapshot_id} of service_id=#{service_id} ")
|
340
|
+
@provisioner.get_serialized_url(service_id, snapshot_id) do |msg|
|
341
|
+
if msg['success']
|
342
|
+
async_reply(VCAP::Services::Api::SerializedURL.new(msg['response']).encode)
|
343
|
+
else
|
344
|
+
async_reply_error(msg['response'])
|
345
|
+
end
|
346
|
+
end
|
347
|
+
async_mode
|
348
|
+
end
|
349
|
+
|
350
|
+
# Import serialized data from url
|
351
|
+
put "/gateway/v1/configurations/:service_id/serialized/url" do
|
352
|
+
req = VCAP::Services::Api::SerializedURL.decode(request_body)
|
353
|
+
service_id = params["service_id"]
|
354
|
+
logger.info("Import serialized data from url:#{req.url} for service_id=#{service_id}")
|
355
|
+
@provisioner.import_from_url(service_id, req.url) do |msg|
|
356
|
+
if msg['success']
|
357
|
+
async_reply(VCAP::Services::Api::Job.new(msg['response']).encode)
|
358
|
+
else
|
359
|
+
async_reply_error(msg['response'])
|
360
|
+
end
|
361
|
+
end
|
362
|
+
async_mode
|
363
|
+
end
|
364
|
+
|
365
|
+
# Get Job details
|
366
|
+
get "/gateway/v1/configurations/:service_id/jobs/:job_id" do
|
367
|
+
service_id = params["service_id"]
|
368
|
+
job_id = params["job_id"]
|
369
|
+
logger.info("Get job=#{job_id} for service_id=#{service_id}")
|
370
|
+
@provisioner.job_details(service_id, job_id) do |msg|
|
371
|
+
if msg['success']
|
372
|
+
async_reply(VCAP::Services::Api::Job.new(msg['response']).encode)
|
373
|
+
else
|
374
|
+
async_reply_error(msg['response'])
|
375
|
+
end
|
376
|
+
end
|
377
|
+
async_mode
|
378
|
+
end
|
379
|
+
|
380
|
+
# Restore an instance of the service
|
381
|
+
#
|
382
|
+
post '/service/internal/v1/restore' do
|
383
|
+
logger.info("Restore service")
|
384
|
+
|
385
|
+
req = Yajl::Parser.parse(request_body)
|
386
|
+
# TODO add json format check
|
387
|
+
|
388
|
+
@provisioner.restore_instance(req['instance_id'], req['backup_path']) do |msg|
|
389
|
+
if msg['success']
|
390
|
+
async_reply
|
391
|
+
else
|
392
|
+
async_reply_error(msg['response'])
|
393
|
+
end
|
394
|
+
end
|
395
|
+
async_mode
|
396
|
+
end
|
397
|
+
|
398
|
+
# Recovery an instance if node is crashed.
|
399
|
+
post '/service/internal/v1/recover' do
|
400
|
+
logger.info("Recover service request.")
|
401
|
+
request = Yajl::Parser.parse(request_body)
|
402
|
+
instance_id = request['instance_id']
|
403
|
+
backup_path = request['backup_path']
|
404
|
+
fetch_handles do |resp|
|
405
|
+
@provisioner.recover(instance_id, backup_path, resp.handles) do |msg|
|
406
|
+
if msg['success']
|
407
|
+
async_reply
|
408
|
+
else
|
409
|
+
async_reply_error(msg['response'])
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
async_mode
|
414
|
+
end
|
415
|
+
|
416
|
+
post '/service/internal/v1/check_orphan' do
|
417
|
+
logger.info("Request to check orphan")
|
418
|
+
fetch_handles do |resp|
|
419
|
+
check_orphan(resp.handles,
|
420
|
+
lambda { async_reply },
|
421
|
+
lambda { |errmsg| async_reply_error(errmsg) })
|
422
|
+
end
|
423
|
+
async_mode
|
424
|
+
end
|
425
|
+
|
426
|
+
delete '/service/internal/v1/purge_orphan' do
|
427
|
+
logger.info("Purge orphan request")
|
428
|
+
req = Yajl::Parser.parse(request_body)
|
429
|
+
orphan_ins_hash = req["orphan_instances"]
|
430
|
+
orphan_binding_hash = req["orphan_bindings"]
|
431
|
+
@provisioner.purge_orphan(orphan_ins_hash, orphan_binding_hash) do |msg|
|
432
|
+
if msg['success']
|
433
|
+
async_reply
|
434
|
+
else
|
435
|
+
async_reply_error(msg['response'])
|
436
|
+
end
|
437
|
+
end
|
438
|
+
async_mode
|
439
|
+
end
|
440
|
+
|
441
|
+
# Service migration API
|
442
|
+
post "/service/internal/v1/migration/:node_id/:instance_id/:action" do
|
443
|
+
logger.info("Migration: #{params["action"]} instance #{params["instance_id"]} in #{params["node_id"]}")
|
444
|
+
@provisioner.migrate_instance(params["node_id"], params["instance_id"], params["action"]) do |msg|
|
445
|
+
if msg["success"]
|
446
|
+
async_reply(msg["response"].to_json)
|
447
|
+
else
|
448
|
+
async_reply_error(msg["response"])
|
449
|
+
end
|
450
|
+
end
|
451
|
+
async_mode
|
452
|
+
end
|
453
|
+
|
454
|
+
get "/service/internal/v1/migration/:node_id/instances" do
|
455
|
+
logger.info("Migration: get instance id list of node #{params["node_id"]}")
|
456
|
+
@provisioner.get_instance_id_list(params["node_id"]) do |msg|
|
457
|
+
if msg["success"]
|
458
|
+
async_reply(msg["response"].to_json)
|
459
|
+
else
|
460
|
+
async_reply_error(msg["response"])
|
461
|
+
end
|
462
|
+
end
|
463
|
+
async_mode
|
464
|
+
end
|
465
|
+
|
466
|
+
###################### V2 handlers ########################
|
467
|
+
|
468
|
+
|
469
|
+
#################### Helpers ####################
|
470
|
+
|
471
|
+
helpers do
|
472
|
+
|
473
|
+
# Fetches canonical state (handles) from the Cloud Controller
|
474
|
+
def fetch_handles(&cb)
|
475
|
+
f = Fiber.new do
|
476
|
+
@catalog_manager.fetch_handles_from_cc(service[:label], cb)
|
477
|
+
end
|
478
|
+
f.resume
|
479
|
+
end
|
480
|
+
|
481
|
+
# Update a service handle using REST
|
482
|
+
def update_service_handle(handle, &cb)
|
483
|
+
f = Fiber.new do
|
484
|
+
@catalog_manager.update_handle_in_cc(
|
485
|
+
service[:label],
|
486
|
+
handle,
|
487
|
+
lambda {
|
488
|
+
# Update local array in provisioner
|
489
|
+
@provisioner.update_handles([handle])
|
490
|
+
cb.call(true) if cb
|
491
|
+
},
|
492
|
+
lambda { cb.call(false) if cb }
|
493
|
+
)
|
494
|
+
end
|
495
|
+
f.resume
|
496
|
+
end
|
497
|
+
|
498
|
+
# Lets the cloud controller know we're alive and where it can find us
|
499
|
+
def send_heartbeat
|
500
|
+
@catalog_manager.update_catalog(
|
501
|
+
true,
|
502
|
+
lambda { return get_current_catalog },
|
503
|
+
nil
|
504
|
+
)
|
505
|
+
end
|
506
|
+
|
507
|
+
# Lets the cloud controller know that we're going away
|
508
|
+
def send_deactivation_notice(stop_event_loop=true)
|
509
|
+
@catalog_manager.update_catalog(
|
510
|
+
false,
|
511
|
+
lambda { return get_current_catalog },
|
512
|
+
lambda { event_machine.stop if stop_event_loop }
|
513
|
+
)
|
514
|
+
end
|
515
|
+
|
516
|
+
def plan_exists?(req)
|
517
|
+
return true if req.plan.nil?
|
518
|
+
|
519
|
+
plan_unique_ids = service.fetch(:plans).values.map { |p| p.fetch(:unique_id) }
|
520
|
+
return true if plan_unique_ids.include?(req.unique_id)
|
521
|
+
|
522
|
+
plan_names = service.fetch(:plans).values.map { |p| p.fetch(:name).to_s }
|
523
|
+
return true if plan_names.include?(req.plan.to_s)
|
524
|
+
|
525
|
+
return false
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end
|
529
|
+
end
|