Skip to content

Commit b0e4288

Browse files
author
Michael Fraenkel
committed
Add network egress rules for Diego
- flow network egress rules for staging and desiring [#79330234] Signed-off-by: Hristo Iliev <hsiliev@gmail.com> Signed-off-by: Atul Kshirsagar <atul.kshirsagar@gmail.com>
1 parent 62d32d0 commit b0e4288

File tree

7 files changed

+113
-34
lines changed

7 files changed

+113
-34
lines changed

lib/cloud_controller/diego/common/protocol.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ def stop_index_request(app, index)
66
['diego.stop.index', stop_index_message(app, index).to_json]
77
end
88

9+
def staging_egress_rules
10+
staging_security_groups = SecurityGroup.where(staging_default: true).all
11+
EgressNetworkRulesPresenter.new(staging_security_groups).to_array.collect { |sg| transform_rule(sg) }.flatten
12+
end
13+
14+
def running_egress_rules(app)
15+
EgressNetworkRulesPresenter.new(app.space.security_groups).to_array.collect { |sg| transform_rule(sg) }.flatten
16+
end
17+
918
private
1019

1120
def stop_index_message(app, index)
@@ -14,6 +23,30 @@ def stop_index_message(app, index)
1423
'index' => index,
1524
}
1625
end
26+
27+
def transform_rule(rule)
28+
protocol = rule['protocol']
29+
template = {
30+
'protocol' => protocol,
31+
'destination' => rule['destination'],
32+
}
33+
34+
case protocol
35+
when 'icmp'
36+
template['icmp_info'] = { 'type' => rule['type'], 'code' => rule['code'] }
37+
when 'tcp', 'udp'
38+
range = rule['ports'].split('-')
39+
if range.size == 1
40+
template['ports'] = range[0].split(',').collect(&:to_i)
41+
else
42+
template['port_range'] = { 'start' => range[0].to_i, 'end' => range[1].to_i }
43+
end
44+
end
45+
46+
template['log'] = rule['log'] if rule['log']
47+
48+
template
49+
end
1750
end
1851
end
1952
end

lib/cloud_controller/diego/docker/protocol.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def stage_app_message(app, staging_timeout)
2222
'file_descriptors' => app.file_descriptors,
2323
'stack' => app.stack.name,
2424
'docker_image' => app.docker_image,
25+
'egress_rules' => @common_protocol.staging_egress_rules,
2526
'timeout' => staging_timeout,
2627
}
2728
end
@@ -49,6 +50,7 @@ def desire_app_message(app)
4950
'log_guid' => app.guid,
5051
'docker_image' => app.docker_image,
5152
'health_check_type' => app.health_check_type,
53+
'egress_rules' => @common_protocol.running_egress_rules(app),
5254
'etag' => app.updated_at.to_f.to_s
5355
}
5456

lib/cloud_controller/diego/traditional/protocol.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def stage_app_message(app, staging_timeout)
3838
'droplet_upload_uri' => @blobstore_url_generator.droplet_upload_url(app),
3939
'build_artifacts_cache_download_uri' => @blobstore_url_generator.buildpack_cache_download_url(app),
4040
'build_artifacts_cache_upload_uri' => @blobstore_url_generator.buildpack_cache_upload_url(app),
41+
'egress_rules' => @common_protocol.staging_egress_rules,
4142
'timeout' => staging_timeout,
4243
}
4344
end
@@ -57,6 +58,7 @@ def desire_app_message(app)
5758
'routes' => app.uris,
5859
'log_guid' => app.guid,
5960
'health_check_type' => app.health_check_type,
61+
'egress_rules' => @common_protocol.running_egress_rules(app),
6062
'etag' => app.updated_at.to_f.to_s
6163
}
6264

spec/unit/lib/cloud_controller/diego/common/protocol_spec.rb

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,46 @@ module Common
1818
expect(request.last).to match_json({ 'process_guid' => 'guid-versioned', 'index' => 33 })
1919
end
2020
end
21+
22+
describe 'staging_egress_rules' do
23+
before do
24+
SecurityGroup.make(rules: [{ 'protocol' => 'udp', 'ports' => '8080-9090', 'destination' => '198.41.191.47/1' }], staging_default: true)
25+
SecurityGroup.make(rules: [{ 'protocol' => 'tcp', 'ports' => '8080,9090', 'destination' => '198.41.191.48/1', 'log' => true }], staging_default: true)
26+
SecurityGroup.make(rules: [{ 'protocol' => 'tcp', 'ports' => '443', 'destination' => '198.41.191.49/1' }], staging_default: true)
27+
SecurityGroup.make(rules: [{ 'protocol' => 'icmp', 'destination' => '0.0.0.0/0', 'type' => 0, 'code' => 1 }], staging_default: true)
28+
SecurityGroup.make(rules: [{ 'protocol' => 'tcp', 'ports' => '80', 'destination' => '0.0.0.0/0' }], staging_default: false)
29+
end
30+
31+
it 'includes egress security group staging information by aggregating all sg with staging_default=true' do
32+
expect(protocol.staging_egress_rules).to match_array([
33+
{ 'protocol' => 'udp', 'port_range' => { 'start' => 8080, 'end' => 9090 }, 'destination' => '198.41.191.47/1' },
34+
{ 'protocol' => 'tcp', 'ports' => [8080, 9090], 'destination' => '198.41.191.48/1', 'log' => true },
35+
{ 'protocol' => 'tcp', 'ports' => [443], 'destination' => '198.41.191.49/1' },
36+
{ 'protocol' => 'icmp', 'icmp_info' => { 'type' => 0, 'code' => 1 }, 'destination' => '0.0.0.0/0' },
37+
])
38+
end
39+
end
40+
41+
describe 'running_egress_rules' do
42+
let(:app) { AppFactory.make }
43+
let(:sg_default_rules_1) { [{ 'protocol' => 'udp', 'ports' => '8080', 'destination' => '198.41.191.47/1' }] }
44+
let(:sg_default_rules_2) { [{ 'protocol' => 'tcp', 'ports' => '9090-9095', 'destination' => '198.41.191.48/1', 'log' => true }] }
45+
let(:sg_for_space_rules) { [{ 'protocol' => 'udp', 'ports' => '1010,2020', 'destination' => '198.41.191.49/1' }] }
46+
47+
before do
48+
SecurityGroup.make(rules: sg_default_rules_1, running_default: true)
49+
SecurityGroup.make(rules: sg_default_rules_2, running_default: true)
50+
app.space.add_security_group(SecurityGroup.make(rules: sg_for_space_rules))
51+
end
52+
53+
it 'should provide the egress rules in the start message' do
54+
expect(protocol.running_egress_rules(app)).to match_array([
55+
{ 'protocol' => 'udp', 'ports' => [8080], 'destination' => '198.41.191.47/1' },
56+
{ 'protocol' => 'tcp', 'port_range' => { 'start' => 9090, 'end' => 9095 }, 'destination' => '198.41.191.48/1', 'log' => true },
57+
{ 'protocol' => 'udp', 'ports' => [1010, 2020], 'destination' => '198.41.191.49/1' },
58+
])
59+
end
60+
end
2161
end
2262
end
2363
end

spec/unit/lib/cloud_controller/diego/docker/protocol_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ module Docker
2121
Protocol.new(common_protocol)
2222
end
2323

24+
before do
25+
allow(common_protocol).to receive(:staging_egress_rules).and_return(['staging_egress_rule'])
26+
allow(common_protocol).to receive(:running_egress_rules).with(app).and_return(['running_egress_rule'])
27+
end
28+
2429
describe '#stage_app_request' do
2530
subject(:request) do
2631
protocol.stage_app_request(app, 900)
@@ -47,6 +52,7 @@ module Docker
4752
'file_descriptors' => app.file_descriptors,
4853
'stack' => app.stack.name,
4954
'docker_image' => app.docker_image,
55+
'egress_rules' => ['staging_egress_rule'],
5056
'timeout' => 900,
5157
})
5258
end
@@ -84,6 +90,7 @@ module Docker
8490
'log_guid' => app.guid,
8591
'docker_image' => app.docker_image,
8692
'health_check_type' => app.health_check_type,
93+
'egress_rules' => ['running_egress_rule'],
8794
'etag' => app.updated_at.to_f.to_s,
8895
})
8996
end

spec/unit/lib/cloud_controller/diego/messenger_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ module Diego
5050
'app_bits_download_uri' => 'http://app-package.com',
5151
'buildpacks' => Traditional::BuildpackEntryGenerator.new(blobstore_url_generator).buildpack_entries(app),
5252
'droplet_upload_uri' => 'http://droplet-upload-uri',
53+
'egress_rules' => [],
5354
'timeout' => 90,
5455
}
5556

@@ -77,6 +78,7 @@ module Diego
7778
'health_check_type' => app.health_check_type,
7879
'health_check_timeout_in_seconds' => 120,
7980
'log_guid' => app.guid,
81+
'egress_rules' => [],
8082
'etag' => app.updated_at.to_f.to_s,
8183
}
8284
end

spec/unit/lib/cloud_controller/diego/traditional/protocol_spec.rb

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ module Traditional
1616

1717
let(:common_protocol) { double(:common_protocol) }
1818

19+
let(:app) do
20+
AppFactory.make
21+
end
22+
1923
subject(:protocol) do
2024
Protocol.new(blobstore_url_generator, common_protocol)
2125
end
2226

23-
describe '#stage_app_request' do
24-
let(:app) do
25-
AppFactory.make
26-
end
27+
before do
28+
allow(common_protocol).to receive(:staging_egress_rules).and_return(['staging_egress_rule'])
29+
allow(common_protocol).to receive(:running_egress_rules).with(app).and_return(['running_egress_rule'])
30+
end
2731

28-
subject(:request) do
29-
protocol.stage_app_request(app, 900)
30-
end
32+
describe '#stage_app_request' do
33+
let(:request) { protocol.stage_app_request(app, 900) }
3134

3235
it 'returns arguments intended for CfMessageBus::MessageBus#publish' do
3336
expect(request.size).to eq(2)
@@ -37,37 +40,36 @@ module Traditional
3740
end
3841

3942
describe '#stage_app_message' do
40-
let(:staging_app) { AppFactory.make }
41-
subject(:message) { protocol.stage_app_message(staging_app, 900) }
43+
let(:message) { protocol.stage_app_message(app, 900) }
4244

4345
before do
44-
staging_app.update(staging_task_id: 'fake-staging-task-id') # Mimic Diego::Messenger#send_stage_request
46+
app.update(staging_task_id: 'fake-staging-task-id') # Mimic Diego::Messenger#send_stage_request
4547
end
4648

4749
it 'is a nats message with the appropriate staging subject and payload' do
4850
buildpack_entry_generator = BuildpackEntryGenerator.new(blobstore_url_generator)
4951

5052
expect(message).to eq(
51-
'app_id' => staging_app.guid,
53+
'app_id' => app.guid,
5254
'task_id' => 'fake-staging-task-id',
53-
'memory_mb' => staging_app.memory,
54-
'disk_mb' => staging_app.disk_quota,
55-
'file_descriptors' => staging_app.file_descriptors,
56-
'environment' => Environment.new(staging_app).as_json,
57-
'stack' => staging_app.stack.name,
55+
'memory_mb' => app.memory,
56+
'disk_mb' => app.disk_quota,
57+
'file_descriptors' => app.file_descriptors,
58+
'environment' => Environment.new(app).as_json,
59+
'stack' => app.stack.name,
5860
'build_artifacts_cache_download_uri' => 'http://buildpack-artifacts-cache.com',
5961
'build_artifacts_cache_upload_uri' => 'http://buildpack-artifacts-cache.up.com',
6062
'app_bits_download_uri' => 'http://app-package.com',
61-
'buildpacks' => buildpack_entry_generator.buildpack_entries(staging_app),
63+
'buildpacks' => buildpack_entry_generator.buildpack_entries(app),
6264
'droplet_upload_uri' => 'http://droplet-upload-uri',
65+
'egress_rules' => ['staging_egress_rule'],
6366
'timeout' => 900,
6467
)
6568
end
6669
end
6770

6871
describe '#desire_app_request' do
69-
let(:app) { AppFactory.make }
70-
subject(:request) { protocol.desire_app_request(app) }
72+
let(:request) { protocol.desire_app_request(app) }
7173

7274
it 'returns arguments intended for CfMessageBus::MessageBus#publish' do
7375
expect(request.size).to eq(2)
@@ -95,15 +97,13 @@ module Traditional
9597
)
9698
end
9799

100+
let(:message) { protocol.desire_app_message(app) }
101+
98102
before do
99103
environment = instance_double(Environment, as_json: [{ 'name' => 'fake', 'value' => 'environment' }])
100104
allow(Environment).to receive(:new).with(app).and_return(environment)
101105
end
102106

103-
subject(:message) do
104-
protocol.desire_app_message(app)
105-
end
106-
107107
it 'is a messsage with the information nsync needs to desire the app' do
108108
expect(message).to eq(
109109
'disk_mb' => 222,
@@ -120,6 +120,7 @@ module Traditional
120120
'start_command' => 'the-custom-command',
121121
'execution_metadata' => 'staging-metadata',
122122
'routes' => ['fake-uris'],
123+
'egress_rules' => ['running_egress_rule'],
123124
'etag' => '12345.6789'
124125
)
125126
end
@@ -136,14 +137,8 @@ module Traditional
136137
end
137138

138139
describe '#stop_staging_app_request' do
139-
let(:app) do
140-
AppFactory.make
141-
end
142140
let(:task_id) { 'staging_task_id' }
143-
144-
subject(:request) do
145-
protocol.stop_staging_app_request(app, task_id)
146-
end
141+
let(:request) { protocol.stop_staging_app_request(app, task_id) }
147142

148143
it 'returns an array of arguments including the subject and message' do
149144
expect(request.size).to eq(2)
@@ -153,20 +148,18 @@ module Traditional
153148
end
154149

155150
describe '#stop_staging_message' do
156-
let(:staging_app) { AppFactory.make }
157151
let(:task_id) { 'staging_task_id' }
158-
subject(:message) { protocol.stop_staging_message(staging_app, task_id) }
152+
let(:message) { protocol.stop_staging_message(app, task_id) }
159153

160154
it 'is a nats message with the appropriate staging subject and payload' do
161155
expect(message).to eq(
162-
'app_id' => staging_app.guid,
156+
'app_id' => app.guid,
163157
'task_id' => task_id,
164158
)
165159
end
166160
end
167161

168162
describe '#stop_index_request' do
169-
let(:app) { AppFactory.make }
170163
before { allow(common_protocol).to receive(:stop_index_request) }
171164

172165
it 'delegates to the common protocol' do

0 commit comments

Comments
 (0)