Skip to content

Commit d710940

Browse files
authored
Merge pull request #3306 from reubenmiller/fix-in-progress-workflows-ignored-after-self-update
fix: process non-versioned in-progress commands on startup
2 parents 8abce11 + f48eedd commit d710940

File tree

4 files changed

+154
-3
lines changed

4 files changed

+154
-3
lines changed

crates/core/tedge_api/src/workflow/supervisor.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,25 @@ impl WorkflowSupervisor {
7676
}
7777

7878
/// Update on start the set of pending commands
79-
pub fn load_pending_commands(&mut self, commands: CommandBoard) -> Vec<GenericCommandState> {
79+
pub fn load_pending_commands(
80+
&mut self,
81+
mut commands: CommandBoard,
82+
) -> Vec<GenericCommandState> {
83+
// If the resumed commands have been triggered by an agent without workflow version management
84+
// then these commands are assigned the current version for the operation.
85+
// These currents versions have also to be marked as in use.
86+
for (_, ref mut command) in commands.iter_mut() {
87+
if command.workflow_version().is_none() {
88+
if let Some(versions) = command
89+
.operation()
90+
.and_then(|operation| self.workflows.get_mut(&operation.as_str().into()))
91+
{
92+
if let Some(current_version) = versions.use_current_version() {
93+
*command = command.clone().set_workflow_version(current_version);
94+
}
95+
}
96+
}
97+
}
8098
self.commands = commands;
8199
self.commands
82100
.iter()
@@ -279,8 +297,15 @@ impl WorkflowSupervisor {
279297
timestamp: &Timestamp,
280298
command: &GenericCommandState,
281299
) -> Option<GenericCommandState> {
282-
let Ok(action) = self.get_action(command) else {
283-
return None;
300+
let action = match self.get_action(command) {
301+
Ok(action) => action,
302+
Err(err) => {
303+
return Some(
304+
command
305+
.clone()
306+
.fail_with(format!("Fail to resume on start: {err:?}")),
307+
);
308+
}
284309
};
285310

286311
let epoch = format!("{}.{}", timestamp.unix_timestamp(), timestamp.millisecond());
@@ -464,6 +489,10 @@ impl CommandBoard {
464489
self.commands.values()
465490
}
466491

492+
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (Timestamp, GenericCommandState)> {
493+
self.commands.values_mut()
494+
}
495+
467496
/// Insert a new operation request into the [CommandBoard]
468497
///
469498
/// Reject the request if there is already an entry with the same command id, but in a different state
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
Package: tedge-full
2+
Pin: version %%VERSION%%
3+
Pin-Priority: 1001
4+
5+
Package: tedge
6+
Pin: version %%VERSION%%
7+
Pin-Priority: 1001
8+
9+
Package: tedge-mapper
10+
Pin: version %%VERSION%%
11+
Pin-Priority: 1001
12+
13+
Package: tedge-agent
14+
Pin: version %%VERSION%%
15+
Pin-Priority: 1001
16+
17+
Package: c8y-firmware-plugin
18+
Pin: version %%VERSION%%
19+
Pin-Priority: 1001
20+
21+
Package: c8y-remote-access-plugin
22+
Pin: version %%VERSION%%
23+
Pin-Priority: 1001
24+
25+
Package: tedge-apt-plugin
26+
Pin: version %%VERSION%%
27+
Pin-Priority: 1001
28+
29+
Package: tedge-watchdog
30+
Pin: version %%VERSION%%
31+
Pin-Priority: 1001
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
operation = "software_update"
2+
3+
[init]
4+
action = "proceed"
5+
on_success = "executing"
6+
7+
[executing]
8+
action = "proceed"
9+
on_success = "prepare"
10+
11+
[prepare]
12+
script = "sudo /etc/tedge/sm-plugins/apt prepare"
13+
on_success = "self-update"
14+
15+
[self-update]
16+
# Note: update tedge as it is used by the tedge-agent (as tedge is a multi-call binary)
17+
# Note: installing the new tedge package will not restart the tedge-agent service
18+
script = "sudo /etc/tedge/sm-plugins/apt install tedge"
19+
on_success = "restart-agent"
20+
21+
[restart-agent]
22+
background_script = "sudo systemctl restart tedge-agent"
23+
on_exec = "await-restart-agent"
24+
25+
[await-restart-agent]
26+
script = "sleep 10"
27+
on_success = "finalize"
28+
on_kill = "finalize"
29+
30+
[finalize]
31+
script = "sh -c 'echo Executing state: ${.payload.status}'"
32+
on_success = "successful"
33+
34+
[successful]
35+
action = "cleanup"
36+
37+
[failed]
38+
action = "cleanup"

tests/RobotFramework/tests/cumulocity/self-update/tedge_self_update.robot

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,49 @@ Update tedge version from base to current using Cumulocity
144144
${pid_after}= Service Should Be Running tedge-agent
145145
Should Not Be Equal ${pid_before} ${pid_after}
146146

147+
Update tedge Using a Custom Software Update Workflow
148+
[Documentation] thin-edge.io needs to support updating across a non-versioned workflow
149+
... which occurs when users are updating from tedge <= 1.3.1 to tedge >= 1.4.0
150+
... Once the new version of tedge-agent starts, it needs to recognize workflows
151+
... that don't have a version (as the workflow version feature did not exist prior to tedge 1.4.0)
152+
${PREV_VERSION}= Set Variable 1.3.1
153+
154+
# Install base version (using apt package pinning, then remove it)
155+
Pin thin-edge.io APT Packages ${PREV_VERSION}
156+
Execute Command cmd=curl -fsSL thin-edge.io/install.sh | sh -s
157+
Unpin thin-edge.io APT Packages
158+
159+
# Register device (using already installed version)
160+
Execute Command
161+
... cmd=test -f ./bootstrap.sh && env DEVICE_ID=${DEVICE_SN} ./bootstrap.sh --no-install --no-secure || true
162+
Device Should Exist ${DEVICE_SN}
163+
164+
Device Should Have Installed Software
165+
... tedge-agent,${PREV_VERSION}
166+
167+
${agent_version}= Execute Command tedge-agent --version strip=${True}
168+
Should Be Equal As Strings ${agent_version} tedge-agent ${PREV_VERSION}
169+
170+
# Allow tedge user to restart services (used in the workflow)
171+
Execute Command
172+
... cmd=echo "tedge ALL = (ALL) NOPASSWD: /usr/bin/systemctl restart *" | sudo tee /etc/sudoers.d/tedge_admin
173+
# Copy Workflow
174+
Transfer To Device ${CURDIR}/software_update.toml /etc/tedge/operations/
175+
# Reload the workflows (as tedge <= 1.3.1 did not support reloading workflows at runtime)
176+
Restart Service tedge-agent
177+
178+
# Configure local repository containing the new version
179+
Create Local Repository
180+
181+
# Note: this just trigger the operation, the contents does not
182+
# actually matter as the workflow uses some hardcoded values
183+
${operation}= Install Software
184+
... tedge-agent,${NEW_VERSION}
185+
Operation Should Be SUCCESSFUL ${operation} timeout=120
186+
187+
${agent_version}= Execute Command tedge-agent --version strip=${True}
188+
Should Be Equal As Strings ${agent_version} tedge-agent ${NEW_VERSION}
189+
147190

148191
*** Keywords ***
149192
Custom Setup
@@ -172,3 +215,13 @@ Create Local Repository
172215
Execute Command cd /opt/repository/local && dpkg-scanpackages -m . > Packages
173216
Execute Command
174217
... cmd=echo 'deb [trusted=yes] file:/opt/repository/local /' > /etc/apt/sources.list.d/tedge-local.list
218+
219+
Pin thin-edge.io APT Packages
220+
[Arguments] ${VERSION}
221+
Transfer To Device ${CURDIR}/apt_package_pinning /etc/apt/preferences.d/tedge
222+
Execute Command cmd=sed -i 's/%%VERSION%%/${VERSION}/g' /etc/apt/preferences.d/tedge
223+
224+
Unpin thin-edge.io APT Packages
225+
Execute Command cmd=rm -f /etc/apt/preferences.d/tedge
226+
# Remove thin-edge.io public repositories to avoid affecting the selected version
227+
Execute Command cmd=rm -f /etc/apt/sources.list.d/thinedge-*.list

0 commit comments

Comments
 (0)