Skip to content

Commit b344bce

Browse files
authored
Merge pull request #23 from lucab/ups/finalize
update_agent: add update finalization
2 parents a96f0ad + 280f3d6 commit b344bce

File tree

7 files changed

+123
-26
lines changed

7 files changed

+123
-26
lines changed

src/cincinnati/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl Cincinnati {
2828
bail!("empty Cincinnati base URL");
2929
}
3030

31-
/// Substitute templated key with agent runtime values.
31+
// Substitute templated key with agent runtime values.
3232
let base_url = if envsubst::is_templated(&cfg.base_url) {
3333
let context = id.url_variables();
3434
envsubst::validate_vars(&context)?;

src/rpm_ostree/actor.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ impl Handler<StageDeployment> for RpmOstreeClient {
3636

3737
fn handle(&mut self, msg: StageDeployment, _ctx: &mut Self::Context) -> Self::Result {
3838
trace!("request to stage release: {:?}", msg.release);
39-
super::cli_upgrade::locked_upgrade(msg.release)
39+
super::cli_deploy::deploy_locked(msg.release)
40+
}
41+
}
42+
43+
/// Request: finalize a staged deployment (by unlocking it and rebooting).
44+
#[derive(Debug, Clone)]
45+
pub struct FinalizeDeployment {
46+
/// Finalized release to finalize.
47+
pub release: Release,
48+
}
49+
50+
impl Message for FinalizeDeployment {
51+
type Result = Fallible<Release>;
52+
}
53+
54+
impl Handler<FinalizeDeployment> for RpmOstreeClient {
55+
type Result = Fallible<Release>;
56+
57+
fn handle(&mut self, msg: FinalizeDeployment, _ctx: &mut Self::Context) -> Self::Result {
58+
trace!("request to finalize release: {:?}", msg.release);
59+
super::cli_finalize::finalize_deployment(msg.release)
4060
}
4161
}

src/rpm_ostree/cli_upgrade.rs src/rpm_ostree/cli_deploy.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
//! Interface to `rpm-ostree upgrade --lock-finalization`.
1+
//! Interface to `rpm-ostree deploy --lock-finalization`.
22
33
use super::Release;
44
use failure::{bail, format_err, Fallible, ResultExt};
55

6-
/// Upgrade and leave the new deployment locked.
7-
pub fn locked_upgrade(release: Release) -> Fallible<Release> {
6+
/// Deploy an upgrade (by checksum) and leave the new deployment locked.
7+
pub fn deploy_locked(release: Release) -> Fallible<Release> {
88
let cmd = std::process::Command::new("rpm-ostree")
99
.arg("deploy")
1010
.arg("--lock-finalization")
11-
.arg(release.reference_id())
11+
.arg(format!("revision={}", release.checksum))
1212
.output()
1313
.with_context(|e| format_err!("failed to run rpm-ostree: {}", e))?;
1414

src/rpm_ostree/cli_finalize.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! Interface to `rpm-ostree finalize-deployment`.
2+
3+
use super::Release;
4+
use failure::{bail, format_err, Fallible, ResultExt};
5+
6+
/// Unlock and finalize the new deployment.
7+
pub fn finalize_deployment(release: Release) -> Fallible<Release> {
8+
let cmd = std::process::Command::new("rpm-ostree")
9+
.arg("finalize-deployment")
10+
.arg(&release.checksum)
11+
.output()
12+
.with_context(|e| format_err!("failed to run rpm-ostree: {}", e))?;
13+
14+
if !cmd.status.success() {
15+
bail!(
16+
"rpm-ostree finalize-deployment failed:\n{}",
17+
String::from_utf8_lossy(&cmd.stderr)
18+
);
19+
}
20+
21+
Ok(release)
22+
}

src/rpm_ostree/mod.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
mod cli_deploy;
2+
mod cli_finalize;
13
mod cli_status;
2-
mod cli_upgrade;
34

45
mod actor;
5-
pub use actor::{RpmOstreeClient, StageDeployment};
6+
pub use actor::{FinalizeDeployment, RpmOstreeClient, StageDeployment};
67

78
use crate::cincinnati::Node;
89

@@ -23,9 +24,4 @@ impl Release {
2324
checksum: node.payload,
2425
}
2526
}
26-
27-
/// Returns the reference ID for this release.
28-
pub fn reference_id(&self) -> String {
29-
format!("revision={}", self.checksum)
30-
}
3127
}

src/update_agent/actor.rs

+50-8
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,15 @@ impl Handler<RefreshTick> for UpdateAgent {
3838
let update = release.clone();
3939
self.try_stage_update(update)
4040
}
41-
UpdateAgentState::UpdateStaged(_release) => self.todo(),
42-
UpdateAgentState::_EndState => self.nop(),
41+
UpdateAgentState::UpdateStaged(release) => {
42+
let update = release.clone();
43+
self.try_finalize_update(update)
44+
}
45+
UpdateAgentState::UpdateFinalized(release) => {
46+
let update = release.clone();
47+
self.end(update)
48+
}
49+
UpdateAgentState::EndState => self.nop(),
4350
};
4451

4552
let update_machine = state_action.then(move |_r, actor, ctx| {
@@ -127,6 +134,26 @@ impl UpdateAgent {
127134
Box::new(state_change)
128135
}
129136

137+
/// Try to finalize an update.
138+
fn try_finalize_update(&mut self, release: Release) -> ResponseActFuture<Self, (), ()> {
139+
trace!("trying to finalize an update");
140+
141+
let can_finalize = self.strategy.can_finalize(&self.identity);
142+
let state_change = actix::fut::wrap_future::<_, Self>(can_finalize)
143+
.and_then(|can_finalize, actor, _ctx| actor.finalize_deployment(can_finalize, release))
144+
.map(|release, actor, _ctx| actor.state.update_finalized(release));
145+
146+
Box::new(state_change)
147+
}
148+
149+
/// Actor job is done.
150+
fn end(&mut self, release: Release) -> ResponseActFuture<Self, (), ()> {
151+
log::info!("update applied, waiting for reboot: {}", release.version);
152+
let state_change = self.nop().map(|_r, actor, _ctx| actor.state.end());
153+
154+
Box::new(state_change)
155+
}
156+
130157
/// Fetch and stage an update, in finalization-locked mode.
131158
fn locked_upgrade(
132159
&mut self,
@@ -148,15 +175,30 @@ impl UpdateAgent {
148175
Box::new(upgrade)
149176
}
150177

178+
/// Finalize a deployment (unlock and reboot).
179+
fn finalize_deployment(
180+
&mut self,
181+
can_finalize: bool,
182+
release: Release,
183+
) -> ResponseActFuture<Self, Release, ()> {
184+
if !can_finalize {
185+
return Box::new(actix::fut::err(()));
186+
}
187+
188+
let msg = rpm_ostree::FinalizeDeployment { release };
189+
let upgrade = self
190+
.rpm_ostree_actor
191+
.send(msg)
192+
.flatten()
193+
.map_err(|e| log::error!("failed to finalize update: {}", e))
194+
.into_actor(self);
195+
196+
Box::new(upgrade)
197+
}
198+
151199
/// Do nothing, without errors.
152200
fn nop(&mut self) -> ResponseActFuture<Self, (), ()> {
153201
let nop = actix::fut::ok(());
154202
Box::new(nop)
155203
}
156-
157-
/// Pending implementation.
158-
fn todo(&mut self) -> ResponseActFuture<Self, (), ()> {
159-
log::error!("pending implementation");
160-
self.nop()
161-
}
162204
}

src/update_agent/mod.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ enum UpdateAgentState {
2727
UpdateAvailable(Release),
2828
/// Update staged by rpm-ostree.
2929
UpdateStaged(Release),
30-
// TODO(lucab): add all the "update in progress" states.
30+
/// Update finalized by rpm-ostree.
31+
UpdateFinalized(Release),
3132
/// Final state upon actor end.
32-
_EndState,
33+
EndState,
3334
}
3435

3536
impl Default for UpdateAgentState {
@@ -71,6 +72,16 @@ impl UpdateAgentState {
7172
fn update_staged(&mut self, update: Release) {
7273
*self = UpdateAgentState::UpdateStaged(update);
7374
}
75+
76+
/// Transition to the UpdateFinalized state.
77+
fn update_finalized(&mut self, update: Release) {
78+
*self = UpdateAgentState::UpdateFinalized(update);
79+
}
80+
81+
/// Transition to the End state.
82+
fn end(&mut self) {
83+
*self = UpdateAgentState::EndState;
84+
}
7485
}
7586

7687
/// Update agent.
@@ -143,9 +154,15 @@ mod tests {
143154
checksum: "ostree-checksum".to_string(),
144155
};
145156
machine.update_available(Some(update.clone()));
157+
assert_eq!(machine, UpdateAgentState::UpdateAvailable(update.clone()));
158+
159+
machine.update_staged(update.clone());
160+
assert_eq!(machine, UpdateAgentState::UpdateStaged(update.clone()));
161+
162+
machine.update_finalized(update.clone());
163+
assert_eq!(machine, UpdateAgentState::UpdateFinalized(update.clone()));
146164

147-
machine.update_staged(update);
148-
// TODO(lucab): complete the full path till reaching EndState.
149-
// assert_eq!(machine, UpdateAgentState::_EndState);
165+
machine.end();
166+
assert_eq!(machine, UpdateAgentState::EndState);
150167
}
151168
}

0 commit comments

Comments
 (0)