Skip to content

Commit c3ab524

Browse files
Add last_status_change to deployments object
* indicates last time status.reason or status.value was updated * status_updated_at column is set to updated_at for exisiting deployments. Unfortunately updated_at is nullable, so those with null updated_at (unclear if this is a real scenario) will have status_updated_at set to the current time Co-authored-by: Joao Pereira <[email protected]> Co-authored-by: Seth Boyles <[email protected]>
1 parent 7494b94 commit c3ab524

File tree

7 files changed

+106
-14
lines changed

7 files changed

+106
-14
lines changed

app/models/runtime/deployment_model.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ def deploying_count
6767
end
6868
end
6969

70+
def before_update
71+
super
72+
set_status_updated_at
73+
end
74+
7075
def deploying?
7176
state == DEPLOYING_STATE
7277
end
@@ -76,5 +81,13 @@ def cancelable?
7681
DeploymentModel::CANCELING_STATE]
7782
valid_states_for_cancel.include?(state)
7883
end
84+
85+
private
86+
87+
def set_status_updated_at
88+
return unless column_changed?(:status_reason) || column_changed?(:status_value)
89+
90+
self.status_updated_at = updated_at
91+
end
7992
end
8093
end

app/presenters/v3/deployment_presenter.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ def to_hash
1414
value: deployment.status_value,
1515
reason: deployment.status_reason,
1616
details: {
17-
last_successful_healthcheck: deployment.last_healthy_at
17+
last_successful_healthcheck: deployment.last_healthy_at,
18+
last_status_change: deployment.status_updated_at
1819
}
1920
},
2021
strategy: deployment.strategy,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Sequel.migration do
2+
up do
3+
alter_table(:deployments) do
4+
add_column :status_updated_at, DateTime, default: Sequel::CURRENT_TIMESTAMP, null: false
5+
end
6+
run 'update deployments set status_updated_at = updated_at where updated_at is not null'
7+
end
8+
9+
down do
10+
alter_table(:deployments) do
11+
drop_column :status_updated_at
12+
end
13+
end
14+
end

docs/v3/source/includes/resources/deployments/_object.md.erb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ Name | Type | Description
1414
**updated_at** | _[timestamp](#timestamps)_ | The time with zone when the object was last updated
1515
**status.value** | _string_ | The current status of the deployment; valid values are `ACTIVE` (meaning in progress) and `FINALIZED` (meaning finished, either successfully or not)
1616
**status.reason** | _string_ | The reason for the status of the deployment;<br>following list represents valid values:<br>1. If **status.value** is `ACTIVE`<br>- `DEPLOYING`<br>- `CANCELING`<br>2. If **status.value** is `FINALIZED`<br>- `DEPLOYED`<br>- `CANCELED`<br>- `SUPERSEDED` (another deployment created for app before completion)<br>
17-
**status.details** | _object_ | The details for the status of the deployment shows a timestamp of the last successful healthcheck
17+
**status.details.last_successful_healthcheck** | _[timestamp](#timestamps)_ | Timestamp of the last successful healthcheck
18+
**status.details.last_status_change** | _[timestamp](#timestamps)_ | Timestamp of last change to status.value or status.reason
1819
**strategy** | _string_ | Strategy used for the deployment; supported strategies are `rolling` only
1920
**droplet.guid** | _string_ | The droplet guid that the deployment is transitioning the app to
2021
**previous_droplet.guid** | _string_ | The app's [current droplet guid](#get-current-droplet-association-for-an-app) before the deployment was created

spec/request/deployments_spec.rb

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
4040
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
4141
'details' => {
42-
'last_successful_healthcheck' => iso8601
42+
'last_successful_healthcheck' => iso8601,
43+
'last_status_change' => iso8601
4344
}
4445
},
4546
'strategy' => 'rolling',
@@ -136,7 +137,8 @@
136137
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
137138
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
138139
'details' => {
139-
'last_successful_healthcheck' => iso8601
140+
'last_successful_healthcheck' => iso8601,
141+
'last_status_change' => iso8601
140142
}
141143
},
142144
'strategy' => 'rolling',
@@ -218,7 +220,8 @@
218220
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
219221
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
220222
'details' => {
221-
'last_successful_healthcheck' => iso8601
223+
'last_successful_healthcheck' => iso8601,
224+
'last_status_change' => iso8601
222225
}
223226
},
224227
'strategy' => 'rolling',
@@ -336,7 +339,8 @@
336339
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
337340
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
338341
'details' => {
339-
'last_successful_healthcheck' => iso8601
342+
'last_successful_healthcheck' => iso8601,
343+
'last_status_change' => iso8601
340344
}
341345
},
342346
'strategy' => 'rolling',
@@ -414,7 +418,8 @@
414418
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
415419
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
416420
'details' => {
417-
'last_successful_healthcheck' => iso8601
421+
'last_successful_healthcheck' => iso8601,
422+
'last_status_change' => iso8601
418423
}
419424
},
420425
'strategy' => 'rolling',
@@ -494,7 +499,8 @@
494499
'value' => VCAP::CloudController::DeploymentModel::FINALIZED_STATUS_VALUE,
495500
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYED_STATUS_REASON,
496501
'details' => {
497-
'last_successful_healthcheck' => iso8601
502+
'last_successful_healthcheck' => iso8601,
503+
'last_status_change' => iso8601
498504
}
499505
},
500506
'strategy' => 'rolling',
@@ -661,7 +667,8 @@
661667
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
662668
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
663669
'details' => {
664-
'last_successful_healthcheck' => iso8601
670+
'last_successful_healthcheck' => iso8601,
671+
'last_status_change' => iso8601
665672
}
666673
},
667674
'strategy' => 'rolling',
@@ -721,7 +728,8 @@
721728
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
722729
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
723730
'details' => {
724-
'last_successful_healthcheck' => iso8601
731+
'last_successful_healthcheck' => iso8601,
732+
'last_status_change' => iso8601
725733
}
726734
},
727735
'strategy' => 'rolling',
@@ -839,7 +847,8 @@
839847
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
840848
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
841849
'details' => {
842-
'last_successful_healthcheck' => iso8601
850+
'last_successful_healthcheck' => iso8601,
851+
'last_status_change' => iso8601
843852
}
844853
},
845854
'strategy' => 'rolling',
@@ -929,7 +938,8 @@
929938
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
930939
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
931940
'details' => {
932-
'last_successful_healthcheck' => iso8601
941+
'last_successful_healthcheck' => iso8601,
942+
'last_status_change' => iso8601
933943
}
934944
},
935945
'droplet' => {
@@ -1051,7 +1061,8 @@ def json_for_deployment(deployment, app_model, droplet, status_value, status_rea
10511061
value: status_value,
10521062
reason: status_reason,
10531063
details: {
1054-
last_successful_healthcheck: iso8601
1064+
last_successful_healthcheck: iso8601,
1065+
last_status_change: iso8601
10551066
}
10561067
},
10571068
strategy: 'rolling',
@@ -1345,7 +1356,8 @@ def json_for_deployment(deployment, app_model, droplet, status_value, status_rea
13451356
'value' => VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
13461357
'reason' => VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON,
13471358
'details' => {
1348-
'last_successful_healthcheck' => iso8601
1359+
'last_successful_healthcheck' => iso8601,
1360+
'last_status_change' => iso8601
13491361
}
13501362
},
13511363
'strategy' => 'rolling',

spec/unit/models/runtime/deployment_model_spec.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,54 @@ module VCAP::CloudController
103103
expect(deployment.cancelable?).to be(false)
104104
end
105105
end
106+
107+
describe '#status_updated_at' do
108+
let(:deployment) do
109+
DeploymentModel.make(
110+
app: app,
111+
droplet: droplet,
112+
deploying_web_process: deploying_web_process,
113+
status_reason: DeploymentModel::DEPLOYING_STATUS_REASON,
114+
status_value: DeploymentModel::ACTIVE_STATUS_VALUE
115+
)
116+
end
117+
118+
# Can't use Timecop with created_at since its set by the DB
119+
let(:creation_time) { deployment.created_at }
120+
let(:update_time) { deployment.created_at + 24.hours }
121+
122+
before do
123+
Timecop.freeze(creation_time)
124+
end
125+
126+
after do
127+
Timecop.return
128+
end
129+
130+
it 'is defaulted with the created_at time' do
131+
expect(deployment.status_updated_at).to eq(deployment.created_at)
132+
end
133+
134+
it 'updates when status_reason has changed' do
135+
deployment.status_reason = DeploymentModel::CANCELING_STATUS_REASON
136+
Timecop.freeze(update_time)
137+
deployment.save
138+
expect(deployment.status_updated_at).to eq update_time
139+
end
140+
141+
it 'updates when status_value has changed' do
142+
deployment.status_value = DeploymentModel::FINALIZED_STATUS_VALUE
143+
Timecop.freeze(update_time)
144+
deployment.save
145+
expect(deployment.status_updated_at).to eq update_time
146+
end
147+
148+
it 'doesnt update when status_value or status_reason is unchanged' do
149+
deployment.strategy = 'faux_strategy'
150+
Timecop.freeze(update_time)
151+
deployment.save
152+
expect(deployment.status_updated_at).to eq creation_time
153+
end
154+
end
106155
end
107156
end

spec/unit/presenters/v3/deployment_presenter_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module VCAP::CloudController::Presenters::V3
1515
previous_droplet: previous_droplet,
1616
deploying_web_process: process,
1717
last_healthy_at: '2019-07-12 19:01:54',
18+
status_updated_at: '2019-07-11 19:01:54',
1819
state: deployment_state,
1920
status_value: VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE,
2021
status_reason: VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON
@@ -29,6 +30,7 @@ module VCAP::CloudController::Presenters::V3
2930
expect(result[:status][:value]).to eq(VCAP::CloudController::DeploymentModel::ACTIVE_STATUS_VALUE)
3031
expect(result[:status][:reason]).to eq(VCAP::CloudController::DeploymentModel::DEPLOYING_STATUS_REASON)
3132
expect(result[:status][:details][:last_successful_healthcheck]).to eq('2019-07-12 19:01:54')
33+
expect(result[:status][:details][:last_status_change]).to eq('2019-07-11 19:01:54')
3234

3335
expect(result[:strategy]).to eq('rolling')
3436

0 commit comments

Comments
 (0)