Skip to content

Commit

Permalink
fix: Add a UpdateDownloadCancel state to the mender-update's state ma…
Browse files Browse the repository at this point in the history
…chine

To make sure we always cancel the update download in case of an
error. We need to be able to handle HTTPS/network/... errors as
well as artifact parsing errors (incl. checksum
mismatches,...). Instead of adding `download_client->Cancel()`
calls to many places and risking missing some more, we introduce
a new state the UpdateDownload state transitions into on failure
and then things continue to the `download_error` state that
handles the related state scripts, etc.

Ticket: MEN-7810
Changelog: Fix download failure to always do a proper
cancellation and cleanup of internal HTTP stuctures to avoid
breaking future HTTP requests. Fixes `bad_version` error.

Signed-off-by: Vratislav Podzimek <[email protected]>
  • Loading branch information
vpodzime committed Dec 11, 2024
1 parent 7a8c7a0 commit 9ef1299
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/mender-update/daemon/state_machine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class StateMachine {
PollForDeploymentState poll_for_deployment_state_;
SendStatusUpdateState send_download_status_state_;
UpdateDownloadState update_download_state_;
UpdateDownloadCancelState update_download_cancel_state_;
SendStatusUpdateState send_install_status_state_;
UpdateInstallState update_install_state_;

Expand Down
5 changes: 4 additions & 1 deletion src/mender-update/daemon/state_machine/state_machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,12 @@ StateMachine::StateMachine(Context &ctx, events::EventLoop &event_loop) :

main_states_.AddTransition(update_download_state_, se::Success, ss.download_leave_, tf::Immediate);
main_states_.AddTransition(update_download_state_, se::StateLoopDetected, state_loop_state_, tf::Immediate);
main_states_.AddTransition(update_download_state_, se::Failure, ss.download_error_, tf::Immediate);
main_states_.AddTransition(update_download_state_, se::Failure, update_download_cancel_state_, tf::Immediate);
main_states_.AddTransition(update_download_state_, se::NothingToDo, ss.download_leave_save_provides, tf::Immediate);

// Cannot fail because download cancellation is a void function as there's nothing to do if it fails, anyway.
main_states_.AddTransition(update_download_cancel_state_, se::Success, ss.download_error_, tf::Immediate);

main_states_.AddTransition(ss.download_leave_, se::Success, send_install_status_state_, tf::Immediate);
main_states_.AddTransition(ss.download_leave_, se::Failure, ss.download_error_, tf::Immediate);

Expand Down
8 changes: 6 additions & 2 deletions src/mender-update/daemon/states.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,13 @@ void UpdateDownloadState::OnEnter(Context &ctx, sm::EventPoster<StateEvent> &pos
if (resp->GetStatusCode() != http::StatusOK) {
log::Error(
"Unexpected status code while fetching artifact: " + resp->GetStatusMessage());
ctx.download_client->Cancel();
poster.PostEvent(StateEvent::Failure);
return;
}

auto http_reader = resp->MakeBodyAsyncReader();
if (!http_reader) {
log::Error(http_reader.error().String());
ctx.download_client->Cancel();
poster.PostEvent(StateEvent::Failure);
return;
}
Expand Down Expand Up @@ -455,6 +453,12 @@ void UpdateDownloadState::DoDownload(Context &ctx, sm::EventPoster<StateEvent> &
}
}

void UpdateDownloadCancelState::OnEnter(Context &ctx, sm::EventPoster<StateEvent> &poster) {
log::Debug("Entering DownloadCancel state");
ctx.download_client->Cancel();
poster.PostEvent(StateEvent::Success);
}

SendStatusUpdateState::SendStatusUpdateState(optional<deployments::DeploymentStatus> status) :
status_(status),
mode_(FailureMode::Ignore) {
Expand Down
5 changes: 5 additions & 0 deletions src/mender-update/daemon/states.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ class UpdateDownloadState : virtual public StateType {
static void DoDownload(Context &ctx, sm::EventPoster<StateEvent> &poster);
};

class UpdateDownloadCancelState : virtual public StateType {
public:
void OnEnter(Context &ctx, sm::EventPoster<StateEvent> &poster) override;
};

class SendStatusUpdateState : virtual public StateType {
public:
// Ignore-failure version.
Expand Down

0 comments on commit 9ef1299

Please sign in to comment.