Skip to content

Commit 9c4bc81

Browse files
committed
chore(TNZ-44895): Create a recreate deployment action for the cc_deployment_updater
1 parent 40debd0 commit 9c4bc81

File tree

5 files changed

+135
-3
lines changed

5 files changed

+135
-3
lines changed

app/actions/deployment_create.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,11 @@ def starting_process_instances(deployment, desired_instances)
247247
else
248248
desired_instances
249249
end
250-
251-
[deployment.max_in_flight, starting_process_count].min
250+
if deployment.strategy == DeploymentModel::RECREATE_STRATEGY
251+
starting_process_count
252+
else
253+
[deployment.max_in_flight, starting_process_count].min
254+
end
252255
end
253256

254257
def log_rollback_event(app_guid, user_id, revision_id, strategy, max_in_flight, canary_steps)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
require 'cloud_controller/deployment_updater/actions/scale_down_canceled_processes'
2+
require 'cloud_controller/deployment_updater/actions/finalize'
3+
require 'cloud_controller/deployment_updater/actions/down_scaler'
4+
require 'cloud_controller/deployment_updater/actions/up_scaler'
5+
require 'cloud_controller/diego/constants'
6+
7+
module VCAP::CloudController
8+
module DeploymentUpdater
9+
module Actions
10+
class Recreate
11+
attr_reader :deployment, :logger, :app, :target_total_instance_count, :interim_desired_instance_count
12+
13+
def initialize(deployment, logger, target_total_instance_count, interim_desired_instance_count=nil)
14+
@deployment = deployment
15+
@logger = logger
16+
@app = deployment.app
17+
@target_total_instance_count = target_total_instance_count
18+
@interim_desired_instance_count = interim_desired_instance_count || target_total_instance_count
19+
end
20+
21+
def call
22+
logger.info("RECREATE Starting down scaler #{deployment.guid}")
23+
down_scaler = DownScaler.new(deployment, logger, target_total_instance_count, instance_count_summary.routable_instances_count)
24+
logger.info("RECREATE starting db transaction for #{deployment.guid}")
25+
deployment.db.transaction do
26+
return unless [DeploymentModel::DEPLOYING_STATE, DeploymentModel::PREPAUSED_STATE].include?(deployment.lock!.state)
27+
return unless can_scale? || down_scaler.can_downscale?
28+
29+
logger.info("RECREATE lock the app for #{deployment.guid}")
30+
app.lock!
31+
logger.info("RECREATE lock the web_processes for #{deployment.guid}")
32+
app.web_processes.each(&:lock!)
33+
logger.info("RECREATE set status to active/deploying for #{deployment.guid}")
34+
deployment.update(
35+
status_value: DeploymentModel::ACTIVE_STATUS_VALUE,
36+
status_reason: DeploymentModel::DEPLOYING_STATUS_REASON,
37+
error: nil
38+
)
39+
logger.info("RECREATE scale down canceled processes for #{deployment.guid}")
40+
ScaleDownCanceledProcesses.new(deployment).call
41+
logger.info("RECREATE scale down web processes for #{deployment.guid}")
42+
down_scaler.scale_down if down_scaler.can_downscale?
43+
logger.info("are we finished scaling for #{deployment.guid}")
44+
return true if finished_scaling?
45+
46+
logger.info("not finished scaling, scaling up web processes for #{deployment.guid}")
47+
scale_up if can_scale?
48+
end
49+
false
50+
rescue CloudController::Errors::ApiError # the instances_reporter re-raises InstancesUnavailable as ApiError
51+
logger.info("skipping-deployment-update-for-#{deployment.guid}")
52+
false
53+
end
54+
55+
private
56+
57+
def scale_up
58+
return unless can_scale?
59+
60+
deploying_web_process.update(instances: desired_new_instances)
61+
deployment.update(last_healthy_at: Time.now)
62+
end
63+
64+
def instance_count_summary
65+
@instance_count_summary ||= instance_reporters.instance_count_summary(deploying_web_process)
66+
end
67+
68+
def deploying_web_process
69+
@deploying_web_process ||= deployment.deploying_web_process
70+
end
71+
72+
def instance_reporters
73+
CloudController::DependencyLocator.instance.instances_reporters
74+
end
75+
76+
def can_scale
77+
deploying_web_process.instances < interim_desired_instance_count && @routable_instances_count < interim_desired_instance_count
78+
end
79+
80+
def finished_scaling
81+
deploying_web_process.instances >= interim_desired_instance_count && @routable_instances_count >= interim_desired_instance_count
82+
end
83+
end
84+
end
85+
end
86+
end

lib/cloud_controller/deployment_updater/actions/scale.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ def initialize(deployment, logger, target_total_instance_count, interim_desired_
1919
end
2020

2121
def call
22+
logger.info("Starting down scaler #{deployment.guid}")
2223
down_scaler = DownScaler.new(deployment, logger, target_total_instance_count, instance_count_summary.routable_instances_count)
24+
logger.info("Starting up scaler #{deployment.guid}")
2325
up_scaler = UpScaler.new(deployment, logger, interim_desired_instance_count, instance_count_summary)
2426

2527
deployment.db.transaction do

lib/cloud_controller/deployment_updater/updater.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ def initialize(deployment, logger)
1414

1515
def scale
1616
with_error_logging('error-scaling-deployment') do
17-
finished = Actions::Scale.new(deployment, logger, deployment.desired_web_instances).call
17+
if deployment.strategy == DeploymentModel::RECREATE_STRATEGY
18+
logger.info("recreating deployment for -#{deployment.guid}")
19+
finished = Actions::Recreate.new(deployment, logger, deployment.desired_web_instances).call
20+
else
21+
finished = Actions::Scale.new(deployment, logger, deployment.desired_web_instances).call
22+
end
23+
1824
Actions::Finalize.new(deployment).call if finished
1925
logger.info("ran-deployment-update-for-#{deployment.guid}")
2026
end

spec/unit/actions/deployment_create_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ module VCAP::CloudController
4242
})
4343
end
4444

45+
let(:recreate_message) do
46+
DeploymentCreateMessage.new({
47+
relationships: { app: { data: { guid: app.guid } } },
48+
droplet: { guid: next_droplet.guid },
49+
strategy: 'recreate',
50+
options: { web_instances:, memory_in_mb:, disk_in_mb:, log_rate_limit_in_bytes_per_second: }
51+
})
52+
end
53+
4554
before do
4655
app.update(droplet: original_droplet)
4756
end
@@ -350,6 +359,32 @@ module VCAP::CloudController
350359
).to contain_exactly(deployment.deploying_web_process.type)
351360
end
352361

362+
it 'when the strategy is recreate' do
363+
deployment = DeploymentCreate.create(app: app, message: recreate_message, user_audit_info: user_audit_info)
364+
event = VCAP::CloudController::Event.find(type: 'audit.app.deployment.create')
365+
expect(event).not_to be_nil
366+
expect(event.actor).to eq('123')
367+
expect(event.actor_type).to eq('user')
368+
expect(event.actor_name).to eq('[email protected]')
369+
expect(event.actor_username).to eq('braa')
370+
expect(event.actee).to eq(app.guid)
371+
expect(event.actee_type).to eq('app')
372+
expect(event.actee_name).to eq(app.name)
373+
expect(event.timestamp).to be
374+
expect(event.space_guid).to eq(app.space_guid)
375+
expect(event.organization_guid).to eq(app.space.organization.guid)
376+
expect(event.metadata).to eq({
377+
'droplet_guid' => next_droplet.guid,
378+
'deployment_guid' => deployment.guid,
379+
'type' => nil,
380+
'revision_guid' => app.latest_revision.guid,
381+
'request' => message.audit_hash,
382+
'strategy' => 'recreate'
383+
})
384+
385+
expect(deployment.deploying_web_process.instances).to eq(2)
386+
end
387+
353388
context 'when the app does not have a droplet set' do
354389
let(:app_without_current_droplet) { AppModel.make }
355390
let(:next_droplet) { DropletModel.make(app: app_without_current_droplet, process_types: { 'web' => 'asdf' }) }

0 commit comments

Comments
 (0)