Skip to content

Commit c0be516

Browse files
committed
add disk and log rate limit
1 parent 5d33b60 commit c0be516

File tree

10 files changed

+379
-24
lines changed

10 files changed

+379
-24
lines changed

app/actions/deployment_create.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ def create(app:, user_audit_info:, message:)
5050
end
5151

5252
process.memory = message.memory_in_mb if message.memory_in_mb
53+
process.disk_quota = message.disk_in_mb if message.disk_in_mb
54+
process.log_rate_limit = message.log_rate_limit_in_bytes_per_second if message.log_rate_limit_in_bytes_per_second
5355

5456
if app.stopped?
5557
process.instances = message.web_instances if message.web_instances
@@ -172,6 +174,8 @@ def validate_quota!(message, app)
172174
current_web_process = app.newest_web_process
173175
current_web_process.instances = message.web_instances if message.web_instances
174176
current_web_process.memory = message.memory_in_mb if message.memory_in_mb
177+
current_web_process.disk_quota = message.disk_in_mb if message.disk_in_mb
178+
current_web_process.log_rate_limit = message.log_rate_limit_in_bytes_per_second if message.log_rate_limit_in_bytes_per_second
175179
# Quotas wont get checked unless the process is started
176180
current_web_process.state = ProcessModel::STARTED
177181
current_web_process.validate
@@ -181,7 +185,7 @@ def validate_quota!(message, app)
181185
current_web_process.reload
182186
end
183187

184-
def create_deployment(app, message, previous_deployment, previous_droplet, revision, target_state, user_audit_info)
188+
def create_deployment(app, message, previous_deployment, previous_droplet, revision, target_state, _user_audit_info)
185189
deployment = DeploymentModel.create(
186190
app: app,
187191
state: starting_state(message),
@@ -193,8 +197,10 @@ def create_deployment(app, message, previous_deployment, previous_droplet, revis
193197
revision_guid: revision&.guid,
194198
revision_version: revision&.version,
195199
strategy: message.strategy,
196-
memory_in_mb: message.memory_in_mb,
197200
max_in_flight: message.max_in_flight,
201+
memory_in_mb: message.memory_in_mb,
202+
disk_in_mb: message.disk_in_mb,
203+
log_rate_limit_in_bytes_per_second: message.log_rate_limit_in_bytes_per_second,
198204
canary_steps: message.options&.dig(:canary, :steps),
199205
web_instances: message.web_instances || desired_instances(app.oldest_web_process, previous_deployment)
200206
)

app/messages/deployment_create_message.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class DeploymentCreateMessage < MetadataBaseMessage
1616
max_in_flight
1717
web_instances
1818
memory_in_mb
19+
disk_in_mb
20+
log_rate_limit_in_bytes_per_second
1921
].freeze
2022

2123
ALLOWED_STEP_KEYS = [
@@ -54,6 +56,14 @@ def memory_in_mb
5456
options&.dig(:memory_in_mb)
5557
end
5658

59+
def disk_in_mb
60+
options&.dig(:disk_in_mb)
61+
end
62+
63+
def log_rate_limit_in_bytes_per_second
64+
options&.dig(:log_rate_limit_in_bytes_per_second)
65+
end
66+
5767
private
5868

5969
def mutually_exclusive_droplet_sources
@@ -81,7 +91,9 @@ def validate_options
8191
def validate_scaling_options
8292
scaling_options = {
8393
instances: options[:web_instances],
84-
memory_in_mb: options[:memory_in_mb]
94+
memory_in_mb: options[:memory_in_mb],
95+
disk_in_mb: options[:disk_in_mb],
96+
log_rate_limit_in_bytes_per_second: options[:log_rate_limit_in_bytes_per_second]
8597
}
8698

8799
message = ProcessScaleMessage.new(scaling_options)

app/models/runtime/constraints/max_memory_policy.rb

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,6 @@ def field
3434
end
3535

3636
class AppMaxMemoryPolicy < BaseMaxMemoryPolicy
37-
def validate
38-
return unless policy_target
39-
return unless additional_checks
40-
41-
return if policy_target.has_remaining_memory(requested_memory)
42-
43-
resource.errors.add(field, error_name)
44-
end
45-
4637
private
4738

4839
def additional_checks

app/presenters/v3/deployment_presenter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ def options(deployment)
6161
web_instances: deployment.desired_web_instances
6262
}
6363

64+
options[:memory_in_mb] = deployment.memory_in_mb if deployment.memory_in_mb
65+
options[:disk_in_mb] = deployment.disk_in_mb if deployment.disk_in_mb
66+
options[:log_rate_limit_in_bytes_per_second] = deployment.log_rate_limit_in_bytes_per_second if deployment.log_rate_limit_in_bytes_per_second
67+
6468
if deployment.strategy == VCAP::CloudController::DeploymentModel::CANARY_STRATEGY && deployment.canary_steps
6569
options[:canary] = {
6670
steps: deployment.canary_steps

config/cloud_controller.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ readiness_port:
1111

1212
external_protocol: http
1313
external_domain: api2.vcap.me
14-
temporary_disable_deployments: true
14+
temporary_disable_deployments: false
1515
deployment_updater:
1616
update_frequency_in_seconds: 30
1717
lock_key: 'cf-deployment-updater'

db/migrations/20250312233355_add_scaling_columns_to_deployments.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
up do
33
alter_table(:deployments) do
44
add_column :memory_in_mb, :integer, null: true
5+
add_column :disk_in_mb, :integer, null: true
6+
add_column :log_rate_limit_in_bytes_per_second, :integer, null: true
57
end
68
end
79
down do
810
alter_table(:deployments) do
911
drop_column :memory_in_mb
12+
drop_column :disk_in_mb
13+
drop_column :log_rate_limit_in_bytes_per_second
1014
end
1115
end
1216
end

spec/request/deployments_spec.rb

Lines changed: 132 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@
11641164
context 'memory_in_mb' do
11651165
let!(:process_model) { VCAP::CloudController::ProcessModel.make(app: app_model, instances: 10) }
11661166
let(:user) { make_developer_for_space(space) }
1167-
let(:memory_in_mb) { 5 }
1167+
let(:memory_in_mb) { 500 }
11681168
let(:create_request) do
11691169
{
11701170
options: {
@@ -1185,13 +1185,13 @@
11851185
post '/v3/deployments', create_request.to_json, user_header
11861186
expect(last_response.status).to eq(201), last_response.body
11871187

1188-
expect(parsed_response['options']['memory_in_mb']).to eq(5)
1188+
expect(parsed_response['options']['memory_in_mb']).to eq(500)
11891189
end
11901190
end
11911191

11921192
context 'when memory_in_mb violates a quota' do
1193-
let(:memory_in_mb) { 100_000 }
1194-
let(:quota) { VCAP::CloudController::QuotaDefinition.make(memory_limit: 1_000_000) }
1193+
let(:memory_in_mb) { 1001 }
1194+
let(:quota) { VCAP::CloudController::QuotaDefinition.make(memory_limit: 10_000) }
11951195

11961196
before do
11971197
org.quota_definition = quota
@@ -1227,9 +1227,135 @@
12271227
end
12281228
end
12291229

1230-
context 'disk_in_mb'
1230+
context 'disk_in_mb' do
1231+
let!(:process_model) { VCAP::CloudController::ProcessModel.make(app: app_model, instances: 10) }
1232+
let(:user) { make_developer_for_space(space) }
1233+
let(:disk_in_mb) { 500 }
1234+
let(:create_request) do
1235+
{
1236+
options: {
1237+
disk_in_mb:
1238+
},
1239+
relationships: {
1240+
app: {
1241+
data: {
1242+
guid: app_model.guid
1243+
}
1244+
}
1245+
}
1246+
}
1247+
end
1248+
1249+
context 'when disk_in_mb is provided' do
1250+
it 'is set on the resource' do
1251+
post '/v3/deployments', create_request.to_json, user_header
1252+
expect(last_response.status).to eq(201), last_response.body
1253+
1254+
expect(parsed_response['options']['disk_in_mb']).to eq(500)
1255+
end
1256+
end
1257+
1258+
context 'when disk_in_mb violates a quota' do
1259+
let(:disk_in_mb) { 1001 }
1260+
1261+
before do
1262+
TestConfig.override(maximum_app_disk_in_mb: 1000)
1263+
end
1264+
1265+
it 'is set on the resource' do
1266+
post '/v3/deployments', create_request.to_json, user_header
1267+
expect(last_response.status).to eq(422), last_response.body
1268+
expect(parsed_response['errors'][0]['detail']).to match('disk_quota too much disk requested (requested 1024 MB - must be less than 1000 MB)')
1269+
end
1270+
end
1271+
1272+
context 'when disk_in_mb is not provided' do
1273+
let(:create_request) do
1274+
{
1275+
relationships: {
1276+
app: {
1277+
data: {
1278+
guid: app_model.guid
1279+
}
1280+
}
1281+
}
1282+
}
1283+
end
1284+
1285+
it 'is not returned as part of the deployment options' do
1286+
post '/v3/deployments', create_request.to_json, user_header
1287+
expect(last_response.status).to eq(201), last_response.body
1288+
1289+
expect(parsed_response['options'].key?('disk_in_mb')).to be false
1290+
end
1291+
end
1292+
end
1293+
1294+
context 'log_rate_limit_in_bytes_per_second' do
1295+
let!(:process_model) { VCAP::CloudController::ProcessModel.make(app: app_model, instances: 10) }
1296+
let(:user) { make_developer_for_space(space) }
1297+
let(:log_rate_limit_in_bytes_per_second) { 500 }
1298+
let(:create_request) do
1299+
{
1300+
options: {
1301+
log_rate_limit_in_bytes_per_second:
1302+
},
1303+
relationships: {
1304+
app: {
1305+
data: {
1306+
guid: app_model.guid
1307+
}
1308+
}
1309+
}
1310+
}
1311+
end
12311312

1232-
context 'log_rate_limit_in_bytes_per_second'
1313+
context 'when log_rate_limit_in_bytes_per_second is provided' do
1314+
it 'is set on the resource' do
1315+
post '/v3/deployments', create_request.to_json, user_header
1316+
expect(last_response.status).to eq(201), last_response.body
1317+
1318+
expect(parsed_response['options']['log_rate_limit_in_bytes_per_second']).to eq(500)
1319+
end
1320+
end
1321+
1322+
context 'when log_rate_limit_in_bytes_per_second violates a quota' do
1323+
let(:log_rate_limit_in_bytes_per_second) { 1001 }
1324+
let(:quota) { VCAP::CloudController::QuotaDefinition.make(log_rate_limit: 1000) }
1325+
1326+
before do
1327+
org.quota_definition = quota
1328+
org.save
1329+
end
1330+
1331+
it 'is set on the resource' do
1332+
post '/v3/deployments', create_request.to_json, user_header
1333+
expect(last_response.status).to eq(422), last_response.body
1334+
expect(parsed_response['errors'][0]['detail']).to match('log_rate_limit exceeds organization log rate quota')
1335+
end
1336+
end
1337+
1338+
context 'when log_rate_limit_in_bytes_per_second is not provided' do
1339+
let(:create_request) do
1340+
{
1341+
relationships: {
1342+
app: {
1343+
data: {
1344+
guid: app_model.guid
1345+
}
1346+
}
1347+
}
1348+
}
1349+
end
1350+
1351+
it 'is not returned as part of the deployment options' do
1352+
post '/v3/deployments', create_request.to_json, user_header
1353+
expect(last_response.status).to eq(201), last_response.body
1354+
1355+
expect(parsed_response['options'].key?('log_rate_limit_in_bytes_per_second')).to be false
1356+
end
1357+
end
1358+
end
12331359

12341360
context 'web_instances' do
12351361
let!(:process_model) { VCAP::CloudController::ProcessModel.make(app: app_model, instances: 10) }

0 commit comments

Comments
 (0)