Skip to content
This repository was archived by the owner on Jun 2, 2021. It is now read-only.

Commit 7bcfee6

Browse files
authored
v3(services): create route binding for user-provided service instance (cloudfoundry#1799)
[#174085457](https://www.pivotaltracker.com/story/show/174085457)
1 parent e7c68a1 commit 7bcfee6

4 files changed

Lines changed: 415 additions & 36 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
module VCAP::CloudController
2+
module V3
3+
class ServiceRouteBindingCreate
4+
def initialize(service_event_repository)
5+
@service_event_repository = service_event_repository
6+
end
7+
8+
def preflight(service_instance, route)
9+
not_supported! unless service_instance.route_service?
10+
route_is_internal! if route.try(:internal?)
11+
space_mismatch! unless route.space == service_instance.space
12+
already_exists! if route.service_instance == service_instance
13+
already_bound! if route.service_instance
14+
end
15+
16+
def create(service_instance, route)
17+
binding = RouteBinding.new
18+
binding.service_instance = service_instance
19+
binding.route = route
20+
21+
client = VCAP::Services::ServiceClientProvider.provide(instance: service_instance)
22+
details = client.bind(binding)
23+
24+
binding.route_service_url = details[:binding][:route_service_url]
25+
binding.save
26+
27+
binding.notify_diego
28+
29+
service_event_repository.record_service_instance_event(:bind_route, service_instance, { route_guid: route.guid })
30+
31+
binding
32+
end
33+
34+
class UnprocessableCreate < StandardError; end
35+
class RouteBindingAlreadyExists < StandardError; end
36+
37+
private
38+
39+
attr_reader :service_event_repository
40+
41+
def route_is_internal!
42+
raise UnprocessableCreate.new('Route services cannot be bound to internal routes')
43+
end
44+
45+
def space_mismatch!
46+
raise UnprocessableCreate.new('The service instance and the route are in different spaces')
47+
end
48+
49+
def already_bound!
50+
raise UnprocessableCreate.new('A route may only be bound to a single service instance')
51+
end
52+
53+
def not_supported!
54+
raise UnprocessableCreate.new('This service instance does not support route binding')
55+
end
56+
57+
def already_exists!
58+
raise RouteBindingAlreadyExists.new('The route and service instance are already bound')
59+
end
60+
end
61+
end
62+
end
Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
require 'messages/service_route_binding_create_message'
2+
require 'actions/service_route_binding_create'
23

34
class ServiceRouteBindingsController < ApplicationController
45
def create
5-
message = parse_request
6+
route_services_disabled! unless route_services_enabled?
7+
message = parse_create_request
68

79
service_instance = fetch_service_instance(message.service_instance_guid)
810
route = fetch_route(message.route_guid)
9-
check_space(service_instance, route)
1011

11-
head :not_implemented
12+
action = V3::ServiceRouteBindingCreate.new(service_event_repository)
13+
action.preflight(service_instance, route)
14+
15+
case service_instance
16+
when ManagedServiceInstance
17+
head :not_implemented
18+
when UserProvidedServiceInstance
19+
binding = action.create(service_instance, route)
20+
render status: :created, json: { guid: binding.guid }.to_json
21+
end
22+
rescue V3::ServiceRouteBindingCreate::UnprocessableCreate => e
23+
unprocessable!(e.message)
24+
rescue V3::ServiceRouteBindingCreate::RouteBindingAlreadyExists
25+
already_exists!
1226
end
1327

1428
private
1529

16-
def parse_request
30+
def parse_create_request
1731
message = ServiceRouteBindingCreateMessage.new(hashed_params[:body])
1832
unprocessable!(message.errors.full_messages) unless message.valid?
1933
message
@@ -22,23 +36,25 @@ def parse_request
2236
def fetch_service_instance(guid)
2337
service_instance = VCAP::CloudController::ServiceInstance.first(guid: guid)
2438
unless service_instance && can_read_space?(service_instance.space)
25-
unprocessable_service_instance!(guid)
39+
service_instance_not_found!(guid)
2640
end
41+
42+
unauthorized! unless can_write_space?(service_instance.space)
43+
2744
service_instance
2845
end
2946

3047
def fetch_route(guid)
3148
route = VCAP::CloudController::Route.first(guid: guid)
3249
unless route && can_read_space?(route.space)
33-
unprocessable_route!(guid)
50+
route_not_found!(guid)
3451
end
52+
3553
route
3654
end
3755

38-
def check_space(service_instance, route)
39-
space = service_instance.space
40-
space_mismatch! unless space == route.space
41-
unauthorized! unless can_write_space?(space)
56+
def service_event_repository
57+
VCAP::CloudController::Repositories::ServiceEventRepository::WithUserActor.new(user_audit_info)
4258
end
4359

4460
def can_read_space?(space)
@@ -49,15 +65,23 @@ def can_write_space?(space)
4965
permission_queryer.can_write_to_space?(space.guid)
5066
end
5167

52-
def unprocessable_service_instance!(guid)
68+
def route_services_enabled?
69+
VCAP::CloudController::Config.config.get(:route_services_enabled)
70+
end
71+
72+
def service_instance_not_found!(guid)
5373
unprocessable!("The service instance could not be found: #{guid}")
5474
end
5575

56-
def unprocessable_route!(guid)
76+
def route_not_found!(guid)
5777
unprocessable!("The route could not be found: #{guid}")
5878
end
5979

60-
def space_mismatch!
61-
unprocessable!('The service instance and the route are in different spaces.')
80+
def route_services_disabled!
81+
unprocessable!('Support for route services is disabled')
82+
end
83+
84+
def already_exists!
85+
raise CloudController::Errors::ApiError.new_from_details('ServiceInstanceAlreadyBoundToSameRoute')
6286
end
6387
end

0 commit comments

Comments
 (0)