diff --git a/app/actions/manifest_route_update.rb b/app/actions/manifest_route_update.rb index a6fbc2af9fa..e00182e0295 100644 --- a/app/actions/manifest_route_update.rb +++ b/app/actions/manifest_route_update.rb @@ -92,7 +92,7 @@ def find_or_create_valid_route(app, manifest_route, user_audit_info) domain: existing_domain, manifest_triggered: true ) - elsif route.space.guid != app.space_guid + elsif !route.available_in_space?(app.space) raise InvalidRoute.new('Routes cannot be mapped to destinations in different spaces') elsif manifest_route[:options] && route[:options] != manifest_route[:options] # remove nil values from options diff --git a/app/controllers/v3/routes_controller.rb b/app/controllers/v3/routes_controller.rb index 4d2220e761d..86f042dc3a7 100644 --- a/app/controllers/v3/routes_controller.rb +++ b/app/controllers/v3/routes_controller.rb @@ -362,7 +362,7 @@ def validate_app_guids!(apps_hash, desired_app_guids) end def validate_app_spaces!(apps_hash, route) - return unless apps_hash.values.any? { |app| app.space != route.space && route.shared_spaces.exclude?(app.space) } + return unless apps_hash.values.any? { |app| !route.available_in_space?(app.space) } unprocessable!("Routes destinations must be in either the route's space or the route's shared spaces") end diff --git a/app/models/runtime/route.rb b/app/models/runtime/route.rb index 7ec7a0b2264..48bec5c9e42 100644 --- a/app/models/runtime/route.rb +++ b/app/models/runtime/route.rb @@ -194,6 +194,10 @@ def self.user_visibility_filter(user) } end + def available_in_space?(other_space) + other_space == space || shared_spaces.include?(other_space) + end + delegate :in_suspended_org?, to: :space def tcp? diff --git a/spec/unit/actions/manifest_route_update_spec.rb b/spec/unit/actions/manifest_route_update_spec.rb index 51f0f4a693c..623aa6384b6 100644 --- a/spec/unit/actions/manifest_route_update_spec.rb +++ b/spec/unit/actions/manifest_route_update_spec.rb @@ -121,6 +121,18 @@ module VCAP::CloudController 'Routes cannot be mapped to destinations in different spaces') end end + + context 'when the route is shared' do + let!(:route_share) { RouteShare.new } + let!(:outside_app) { AppModel.make } + let!(:shared_route) { route_share.create(route, [outside_app.space], user_audit_info) } + + it 'succeeds after route share' do + expect do + ManifestRouteUpdate.update(outside_app.guid, message, user_audit_info) + end.not_to raise_error + end + end end end diff --git a/spec/unit/models/runtime/route_spec.rb b/spec/unit/models/runtime/route_spec.rb index 173d4cf1234..c97c3ad0a4d 100644 --- a/spec/unit/models/runtime/route_spec.rb +++ b/spec/unit/models/runtime/route_spec.rb @@ -1570,5 +1570,35 @@ def assert_invalid_path(path) end end end + + describe 'app spaces and route shared spaces' do + let!(:domain) { SharedDomain.make } + + context 'when app and route space not shared' do + let!(:app) { AppModel.make } + let!(:route) { Route.make(host: 'potato', domain: domain, path: '/some-path') } + + it 'no space match and not shared and returns false' do + expect(route.available_in_space?(app.space)).to be(false) + end + + it 'match space and returns true' do + route.space = app.space + expect(route.available_in_space?(app.space)).to be(true) + end + end + + context 'when app and route space shared' do + let!(:app) { AppModel.make } + let!(:route_share) { RouteShare.new } + let(:user_audit_info) { instance_double(UserAuditInfo).as_null_object } + let!(:route) { Route.make(host: 'potato', domain: domain, path: '/some-path') } + let!(:shared_route) { route_share.create(route, [app.space], user_audit_info) } + + it 'shared space match and returns true' do + expect(route.available_in_space?(app.space)).to be(true) + end + end + end end end