Skip to content

Commit

Permalink
Merge pull request #3306 from reubenmiller/fix-in-progress-workflows-…
Browse files Browse the repository at this point in the history
…ignored-after-self-update

fix: process non-versioned in-progress commands on startup
  • Loading branch information
didier-wenzek authored Dec 17, 2024
2 parents 8abce11 + f48eedd commit 8ed469e
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 3 deletions.
35 changes: 32 additions & 3 deletions crates/core/tedge_api/src/workflow/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,25 @@ impl WorkflowSupervisor {
}

/// Update on start the set of pending commands
pub fn load_pending_commands(&mut self, commands: CommandBoard) -> Vec<GenericCommandState> {
pub fn load_pending_commands(
&mut self,
mut commands: CommandBoard,
) -> Vec<GenericCommandState> {
// If the resumed commands have been triggered by an agent without workflow version management
// then these commands are assigned the current version for the operation.
// These currents versions have also to be marked as in use.
for (_, ref mut command) in commands.iter_mut() {
if command.workflow_version().is_none() {
if let Some(versions) = command
.operation()
.and_then(|operation| self.workflows.get_mut(&operation.as_str().into()))
{
if let Some(current_version) = versions.use_current_version() {
*command = command.clone().set_workflow_version(current_version);
}
}
}
}
self.commands = commands;
self.commands
.iter()
Expand Down Expand Up @@ -279,8 +297,15 @@ impl WorkflowSupervisor {
timestamp: &Timestamp,
command: &GenericCommandState,
) -> Option<GenericCommandState> {
let Ok(action) = self.get_action(command) else {
return None;
let action = match self.get_action(command) {
Ok(action) => action,
Err(err) => {
return Some(
command
.clone()
.fail_with(format!("Fail to resume on start: {err:?}")),
);
}
};

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

pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (Timestamp, GenericCommandState)> {
self.commands.values_mut()
}

/// Insert a new operation request into the [CommandBoard]
///
/// Reject the request if there is already an entry with the same command id, but in a different state
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Package: tedge-full
Pin: version %%VERSION%%
Pin-Priority: 1001

Package: tedge
Pin: version %%VERSION%%
Pin-Priority: 1001

Package: tedge-mapper
Pin: version %%VERSION%%
Pin-Priority: 1001

Package: tedge-agent
Pin: version %%VERSION%%
Pin-Priority: 1001

Package: c8y-firmware-plugin
Pin: version %%VERSION%%
Pin-Priority: 1001

Package: c8y-remote-access-plugin
Pin: version %%VERSION%%
Pin-Priority: 1001

Package: tedge-apt-plugin
Pin: version %%VERSION%%
Pin-Priority: 1001

Package: tedge-watchdog
Pin: version %%VERSION%%
Pin-Priority: 1001
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
operation = "software_update"

[init]
action = "proceed"
on_success = "executing"

[executing]
action = "proceed"
on_success = "prepare"

[prepare]
script = "sudo /etc/tedge/sm-plugins/apt prepare"
on_success = "self-update"

[self-update]
# Note: update tedge as it is used by the tedge-agent (as tedge is a multi-call binary)
# Note: installing the new tedge package will not restart the tedge-agent service
script = "sudo /etc/tedge/sm-plugins/apt install tedge"
on_success = "restart-agent"

[restart-agent]
background_script = "sudo systemctl restart tedge-agent"
on_exec = "await-restart-agent"

[await-restart-agent]
script = "sleep 10"
on_success = "finalize"
on_kill = "finalize"

[finalize]
script = "sh -c 'echo Executing state: ${.payload.status}'"
on_success = "successful"

[successful]
action = "cleanup"

[failed]
action = "cleanup"
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,49 @@ Update tedge version from base to current using Cumulocity
${pid_after}= Service Should Be Running tedge-agent
Should Not Be Equal ${pid_before} ${pid_after}

Update tedge Using a Custom Software Update Workflow
[Documentation] thin-edge.io needs to support updating across a non-versioned workflow
... which occurs when users are updating from tedge <= 1.3.1 to tedge >= 1.4.0
... Once the new version of tedge-agent starts, it needs to recognize workflows
... that don't have a version (as the workflow version feature did not exist prior to tedge 1.4.0)
${PREV_VERSION}= Set Variable 1.3.1

# Install base version (using apt package pinning, then remove it)
Pin thin-edge.io APT Packages ${PREV_VERSION}
Execute Command cmd=curl -fsSL thin-edge.io/install.sh | sh -s
Unpin thin-edge.io APT Packages

# Register device (using already installed version)
Execute Command
... cmd=test -f ./bootstrap.sh && env DEVICE_ID=${DEVICE_SN} ./bootstrap.sh --no-install --no-secure || true
Device Should Exist ${DEVICE_SN}

Device Should Have Installed Software
... tedge-agent,${PREV_VERSION}

${agent_version}= Execute Command tedge-agent --version strip=${True}
Should Be Equal As Strings ${agent_version} tedge-agent ${PREV_VERSION}

# Allow tedge user to restart services (used in the workflow)
Execute Command
... cmd=echo "tedge ALL = (ALL) NOPASSWD: /usr/bin/systemctl restart *" | sudo tee /etc/sudoers.d/tedge_admin
# Copy Workflow
Transfer To Device ${CURDIR}/software_update.toml /etc/tedge/operations/
# Reload the workflows (as tedge <= 1.3.1 did not support reloading workflows at runtime)
Restart Service tedge-agent

# Configure local repository containing the new version
Create Local Repository

# Note: this just trigger the operation, the contents does not
# actually matter as the workflow uses some hardcoded values
${operation}= Install Software
... tedge-agent,${NEW_VERSION}
Operation Should Be SUCCESSFUL ${operation} timeout=120

${agent_version}= Execute Command tedge-agent --version strip=${True}
Should Be Equal As Strings ${agent_version} tedge-agent ${NEW_VERSION}


*** Keywords ***
Custom Setup
Expand Down Expand Up @@ -172,3 +215,13 @@ Create Local Repository
Execute Command cd /opt/repository/local && dpkg-scanpackages -m . > Packages
Execute Command
... cmd=echo 'deb [trusted=yes] file:/opt/repository/local /' > /etc/apt/sources.list.d/tedge-local.list

Pin thin-edge.io APT Packages
[Arguments] ${VERSION}
Transfer To Device ${CURDIR}/apt_package_pinning /etc/apt/preferences.d/tedge
Execute Command cmd=sed -i 's/%%VERSION%%/${VERSION}/g' /etc/apt/preferences.d/tedge

Unpin thin-edge.io APT Packages
Execute Command cmd=rm -f /etc/apt/preferences.d/tedge
# Remove thin-edge.io public repositories to avoid affecting the selected version
Execute Command cmd=rm -f /etc/apt/sources.list.d/thinedge-*.list

0 comments on commit 8ed469e

Please sign in to comment.