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

Commit fed6547

Browse files
improve internal route error message on Kubernetes
- return a meaningful error for now when a user attempts to create an internal route when running on Kubernetes -- eventually this can be removed once internal routes are supported - no longer allocate VIPs when creating an internal route and running on Kubernetes -- these were only used for Istio on BOSH and have no purpose on Kubernetes - related issue cloudfoundry#1928 [#175420211](https://www.pivotaltracker.com/story/show/175420211) Co-authored-by: Tim Downey <tdowney@vmware.com> Co-authored-by: Piyali Banerjee <pbanerjee@pivotal.io>
1 parent 8c07baf commit fed6547

File tree

7 files changed

+139
-48
lines changed

7 files changed

+139
-48
lines changed

app/actions/route_create.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ def initialize(user_audit_info)
99

1010
def create(message:, space:, domain:, manifest_triggered: false)
1111
validate_tcp_route!(domain, message)
12+
validate_internal_kubernetes_domain!(domain)
1213

1314
route = Route.new(
1415
host: message.host || '',
@@ -51,6 +52,12 @@ def validate_tcp_route!(domain, message)
5152
end
5253
end
5354

55+
def validate_internal_kubernetes_domain!(domain)
56+
if domain.internal? && VCAP::CloudController::Config.config.kubernetes_api_configured?
57+
error!('Internal domains are currently not supported on Kubernetes')
58+
end
59+
end
60+
5461
def port(message, domain)
5562
generated_port = if !message.requested?(:port) && domain.protocols.include?('tcp')
5663
PortGenerator.generate_port(domain.guid, router_group(domain).reservable_ports)

app/models/runtime/domain.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ def protocols
147147
['http']
148148
end
149149

150+
def internal?
151+
!!internal
152+
end
153+
150154
private
151155

152156
def k8s_enabled?

app/models/runtime/route.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ def find_next_vip_offset
218218
end
219219

220220
def before_save
221+
return if VCAP::CloudController::Config.kubernetes_api_configured?
222+
221223
if internal? && vip_offset.nil?
222224
len = internal_route_vip_range_len
223225
raise OutOfVIPException.new('out of vip_offset slots') if self.class.exclude(vip_offset: nil).count >= len

app/models/runtime/shared_domain.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,6 @@ def transient_attrs
9292
router_group_type.blank? ? [] : [:router_group_type]
9393
end
9494

95-
def internal?
96-
!!internal
97-
end
98-
9995
def routing_api_client
10096
@routing_api_client ||= CloudController::DependencyLocator.instance.routing_api_client
10197
end

spec/unit/actions/route_create_spec.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,52 @@ module VCAP::CloudController
529529
subject.create(message: message, space: space, domain: internal_domain)
530530
}.to raise_error(RouteCreate::Error, 'Paths are not supported for internal domains.')
531531
end
532+
533+
context 'when the Kubernetes API is configured' do
534+
before do
535+
TestConfig.override(
536+
kubernetes: { host_url: 'https://api.default.svc.cluster-domain.example' }
537+
)
538+
end
539+
540+
it 'raises an error' do
541+
message = RouteCreateMessage.new({
542+
host: 'a',
543+
relationships: {
544+
space: {
545+
data: { guid: space.guid }
546+
},
547+
domain: {
548+
data: { guid: internal_domain.guid }
549+
},
550+
},
551+
})
552+
553+
expect {
554+
subject.create(message: message, space: space, domain: internal_domain)
555+
}.to raise_error(RouteCreate::Error, 'Internal domains are currently not supported on Kubernetes')
556+
end
557+
end
558+
559+
context 'when the Kubernetes API is not configured' do
560+
it 'does not raise an error' do
561+
message = RouteCreateMessage.new({
562+
host: 'a',
563+
relationships: {
564+
space: {
565+
data: { guid: space.guid }
566+
},
567+
domain: {
568+
data: { guid: internal_domain.guid }
569+
},
570+
},
571+
})
572+
573+
expect {
574+
subject.create(message: message, space: space, domain: internal_domain)
575+
}.not_to raise_error
576+
end
577+
end
532578
end
533579

534580
context 'when using a reserved system hostname' do

spec/unit/lib/cloud_controller/copilot/adapter_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module VCAP::CloudController
1515
allow(CloudController::DependencyLocator.instance).to receive(:copilot_client).and_return(copilot_client)
1616
allow(Steno).to receive(:logger).and_return(fake_logger)
1717
allow(fake_logger).to receive(:debug)
18-
TestConfig.override(copilot: { enabled: true, temporary_istio_domains: [istio_domain.name, internal_istio_domain.name] })
18+
TestConfig.override(copilot: { enabled: true, temporary_istio_domains: [istio_domain.name, internal_istio_domain.name] }, kubernetes: {})
1919
end
2020

2121
describe '#create_route' do

spec/unit/models/runtime/route_spec.rb

Lines changed: 79 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,12 @@ def assert_invalid_path(path)
13311331
end
13321332

13331333
context '#internal?' do
1334+
before do
1335+
TestConfig.override(
1336+
kubernetes: {}
1337+
)
1338+
end
1339+
13341340
let(:internal_domain) { SharedDomain.make(name: 'apps.internal', internal: true) }
13351341
let(:internal_route) { Route.make(host: 'meow', domain: internal_domain) }
13361342
let(:external_private_route) { Route.make }
@@ -1350,7 +1356,7 @@ def assert_invalid_path(path)
13501356

13511357
describe 'vip_offset' do
13521358
before do
1353-
TestConfig.override( # 8 theoretical available ips, 6 actual
1359+
TestConfig.override(
13541360
internal_route_vip_range: '127.128.99.0/29',
13551361
kubernetes: {}
13561362
)
@@ -1363,62 +1369,86 @@ def assert_invalid_path(path)
13631369
let!(:internal_route_3) { Route.make(host: 'quack', domain: internal_domain) }
13641370
let(:external_private_route) { Route.make }
13651371

1366-
it 'auto-assigns vip_offset to internal routes only' do
1367-
expect(internal_route_1.vip_offset).not_to be_nil
1368-
expect(external_private_route.vip_offset).to be_nil
1369-
end
1370-
1371-
it 'assigns multiple vips in ascending order without duplicates' do
1372-
expect(internal_route_1.vip_offset).to eq(1)
1373-
expect(internal_route_2.vip_offset).to eq(2)
1374-
end
1375-
1376-
it 'never assigns the same vip_offset to multiple internal routes' do
1377-
expect {
1378-
Route.make(host: 'ants', vip_offset: 1)
1379-
}.to raise_error(Sequel::UniqueConstraintViolation, /duplicate.*routes_vip_offset_index/i)
1380-
end
1372+
context 'when the kubernetes API is configured' do
1373+
before do
1374+
TestConfig.override(
1375+
internal_route_vip_range: '',
1376+
kubernetes: { host_url: 'api.k8s.example.com' }
1377+
)
1378+
end
13811379

1382-
it 'finds an available offset' do
1383-
Route.make(host: 'gulp', domain: internal_domain)
1384-
expect(Route.all.map(&:vip_offset)).to match_array((1..4).to_a)
1380+
it 'does not assign vip_offset' do
1381+
internal_route_4 = Route.make(host: 'moo', domain: internal_domain)
1382+
expect(internal_route_4.vip_offset).to be_nil
1383+
expect(internal_route_4.vip).to be_nil
1384+
end
13851385
end
13861386

1387-
context 'when the taken offset is not the first' do
1387+
context 'when the Kubernetes API is not configured' do
13881388
before do
1389-
TestConfig.override(
1389+
TestConfig.override( # 8 theoretical available ips, 6 actual
1390+
internal_route_vip_range: '127.128.99.0/29',
13901391
kubernetes: {}
13911392
)
13921393
end
1393-
it 'finds the first offset' do
1394-
internal_route_1.destroy
1395-
expect(Route.make(host: 'gulp', domain: internal_domain).vip_offset).to eq(1)
1394+
1395+
it 'auto-assigns vip_offset to internal routes only' do
1396+
expect(internal_route_1.vip_offset).not_to be_nil
1397+
expect(external_private_route.vip_offset).to be_nil
1398+
end
1399+
1400+
it 'assigns multiple vips in ascending order without duplicates' do
1401+
expect(internal_route_1.vip_offset).to eq(1)
1402+
expect(internal_route_2.vip_offset).to eq(2)
1403+
end
1404+
1405+
it 'never assigns the same vip_offset to multiple internal routes' do
1406+
expect {
1407+
Route.make(host: 'ants', vip_offset: 1)
1408+
}.to raise_error(Sequel::UniqueConstraintViolation, /duplicate.*routes_vip_offset_index/i)
13961409
end
1397-
end
13981410

1399-
context 'when the taken offsets include first and not second' do
14001411
it 'finds an available offset' do
1401-
internal_route_2.destroy
1402-
expect(Route.make(host: 'gulp', domain: internal_domain).vip_offset).to eq(2)
1412+
Route.make(host: 'gulp', domain: internal_domain)
1413+
expect(Route.all.map(&:vip_offset)).to match_array((1..4).to_a)
1414+
end
1415+
1416+
context 'when the taken offset is not the first' do
1417+
before do
1418+
TestConfig.override(
1419+
kubernetes: {}
1420+
)
1421+
end
1422+
it 'finds the first offset' do
1423+
internal_route_1.destroy
1424+
expect(Route.make(host: 'gulp', domain: internal_domain).vip_offset).to eq(1)
1425+
end
14031426
end
1404-
end
14051427

1406-
context 'when filling the vip range' do
1407-
it 'can make 3 more new routes only' do
1408-
expect { Route.make(host: 'route4', domain: internal_domain) }.not_to raise_error
1409-
expect { Route.make(host: 'route5', domain: internal_domain) }.not_to raise_error
1410-
expect { Route.make(host: 'route6', domain: internal_domain) }.not_to raise_error
1411-
expect { Route.make(host: 'route7', domain: internal_domain) }.to raise_error(Route::OutOfVIPException)
1428+
context 'when the taken offsets include first and not second' do
1429+
it 'finds an available offset' do
1430+
internal_route_2.destroy
1431+
expect(Route.make(host: 'gulp', domain: internal_domain).vip_offset).to eq(2)
1432+
end
14121433
end
14131434

1414-
it 'can reclaim lost vips' do
1415-
expect { Route.make(host: 'route4', domain: internal_domain) }.not_to raise_error
1416-
expect { Route.make(host: 'route5', domain: internal_domain) }.not_to raise_error
1417-
expect { Route.make(host: 'route6', domain: internal_domain) }.not_to raise_error
1418-
Route.last.destroy
1419-
internal_route_2.destroy
1420-
expect(Route.make(host: 'new2', domain: internal_domain).vip_offset).to eq(2)
1421-
expect(Route.make(host: 'new6', domain: internal_domain).vip_offset).to eq(6)
1435+
context 'when filling the vip range' do
1436+
it 'can make 3 more new routes only' do
1437+
expect { Route.make(host: 'route4', domain: internal_domain) }.not_to raise_error
1438+
expect { Route.make(host: 'route5', domain: internal_domain) }.not_to raise_error
1439+
expect { Route.make(host: 'route6', domain: internal_domain) }.not_to raise_error
1440+
expect { Route.make(host: 'route7', domain: internal_domain) }.to raise_error(Route::OutOfVIPException)
1441+
end
1442+
1443+
it 'can reclaim lost vips' do
1444+
expect { Route.make(host: 'route4', domain: internal_domain) }.not_to raise_error
1445+
expect { Route.make(host: 'route5', domain: internal_domain) }.not_to raise_error
1446+
expect { Route.make(host: 'route6', domain: internal_domain) }.not_to raise_error
1447+
Route.last.destroy
1448+
internal_route_2.destroy
1449+
expect(Route.make(host: 'new2', domain: internal_domain).vip_offset).to eq(2)
1450+
expect(Route.make(host: 'new6', domain: internal_domain).vip_offset).to eq(6)
1451+
end
14221452
end
14231453
end
14241454
end
@@ -1476,6 +1506,12 @@ def assert_invalid_path(path)
14761506
end
14771507

14781508
describe 'vip' do
1509+
before do
1510+
TestConfig.override(
1511+
kubernetes: {}
1512+
)
1513+
end
1514+
14791515
let(:internal_domain) { SharedDomain.make(name: 'apps.internal', internal: true) }
14801516
let!(:internal_route_1) { Route.make(host: 'meow', domain: internal_domain, vip_offset: 1) }
14811517
let!(:internal_route_2) { Route.make(host: 'woof', domain: internal_domain, vip_offset: 2) }

0 commit comments

Comments
 (0)