• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1644050704

28 Jan 2025 07:35AM UTC coverage: 79.704% (-0.002%) from 79.706%
1644050704

push

gitlab-ci

web-flow
Merge pull request #1727 from jo-lund/4.0.x

4.0.x: fix: Clear the inventory data hash on re-authentication

3 of 10 new or added lines in 3 files covered. (30.0%)

1 existing line in 1 file now uncovered.

7214 of 9051 relevant lines covered (79.7%)

12088.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.63
/src/mender-update/daemon/state_machine/state_machine.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <mender-update/daemon/state_machine.hpp>
16

17
#include <common/conf.hpp>
18
#include <common/key_value_database.hpp>
19
#include <common/log.hpp>
20

21
#include <mender-update/daemon/states.hpp>
22

23
namespace mender {
24
namespace update {
25
namespace daemon {
26

27
namespace conf = mender::common::conf;
28
namespace kvdb = mender::common::key_value_database;
29
namespace log = mender::common::log;
30

31
StateMachine::StateMachine(Context &ctx, events::EventLoop &event_loop) :
94✔
32
        ctx_(ctx),
33
        event_loop_(event_loop),
34
        check_update_handler_(event_loop),
35
        inventory_update_handler_(event_loop),
36
        termination_handler_(event_loop),
37
        submit_inventory_state_(event_loop),
38
        poll_for_deployment_state_(event_loop),
39
        send_download_status_state_(deployments::DeploymentStatus::Downloading),
40
        send_install_status_state_(deployments::DeploymentStatus::Installing),
41
        send_reboot_status_state_(deployments::DeploymentStatus::Rebooting),
42
        send_commit_status_state_(
43
                deployments::DeploymentStatus::Installing,
44
                event_loop,
45
                ctx.mender_context.GetConfig().retry_poll_interval_seconds,
46
                ctx.mender_context.GetConfig().retry_poll_count),
94✔
47
        // nullopt means: Fetch success/failure status from deployment context
48
        send_final_status_state_(
49
                nullopt,
50
                event_loop,
51
                ctx.mender_context.GetConfig().retry_poll_interval_seconds,
52
                ctx.mender_context.GetConfig().retry_poll_count),
94✔
53
        exit_state_(event_loop),
54
        main_states_(init_state_),
55
        state_scripts_(
56
                event_loop,
57
                chrono::seconds {ctx.mender_context.GetConfig().state_script_timeout_seconds},
58
                chrono::seconds {ctx.mender_context.GetConfig().state_script_retry_interval_seconds},
59
                chrono::seconds {ctx.mender_context.GetConfig().state_script_retry_timeout_seconds},
94✔
60
                ctx_.mender_context.GetConfig().paths.GetArtScriptsPath(),
188✔
61
                ctx_.mender_context.GetConfig().paths.GetRootfsScriptsPath()),
188✔
62
        runner_(ctx) {
282✔
63
        runner_.AddStateMachine(deployment_tracking_.states_);
94✔
64
        runner_.AddStateMachine(main_states_);
94✔
65
        runner_.AttachToEventLoop(event_loop_);
94✔
NEW
66
        ctx.authenticator.RegisterTokenReceivedCallback([&ctx]() {
×
NEW
67
                if (ctx.inventory_client->has_submitted_inventory) {
×
NEW
68
                        log::Debug("Client has re-authenticated - clear inventory data cache");
×
NEW
69
                        ctx.inventory_client->ClearDataCache();
×
NEW
70
                        ctx.inventory_client->has_submitted_inventory = false;
×
71
                }
NEW
72
        });
×
73

74
        using se = StateEvent;
75
        using tf = sm::TransitionFlag;
76

77
        auto &ss = state_scripts_;
78

79
        // When updating the table below, make sure that the initial states are in sync as well, in
80
        // LoadStateFromDb().
81

82
        // clang-format off
83
        main_states_.AddTransition(init_state_,                             se::Started,                     ss.idle_enter_,                          tf::Immediate);
94✔
84

85
        main_states_.AddTransition(ss.idle_enter_,                          se::Success,                     idle_state_,                             tf::Immediate);
94✔
86
        main_states_.AddTransition(ss.idle_enter_,                          se::Failure,                     idle_state_,                             tf::Immediate);
94✔
87

88
        main_states_.AddTransition(idle_state_,                             se::DeploymentPollingTriggered,  ss.idle_leave_deploy_,                   tf::Deferred);
94✔
89
        main_states_.AddTransition(idle_state_,                             se::InventoryPollingTriggered,   ss.idle_leave_inv_,                      tf::Deferred);
94✔
90

91
        main_states_.AddTransition(ss.idle_leave_deploy_,                   se::Success,                     ss.sync_enter_deployment_,               tf::Immediate);
94✔
92
        main_states_.AddTransition(ss.idle_leave_deploy_,                   se::Failure,                     ss.sync_enter_deployment_,               tf::Immediate);
94✔
93

94
        main_states_.AddTransition(ss.sync_enter_deployment_,               se::Success,                     poll_for_deployment_state_,              tf::Immediate);
94✔
95
        main_states_.AddTransition(ss.sync_enter_deployment_,               se::Failure,                     ss.sync_error_,                          tf::Immediate);
94✔
96

97
        main_states_.AddTransition(ss.sync_error_,                          se::Success,                     ss.idle_enter_,                          tf::Immediate);
94✔
98
        main_states_.AddTransition(ss.sync_error_,                          se::Failure,                     ss.idle_enter_,                          tf::Immediate);
94✔
99

100
        main_states_.AddTransition(ss.idle_leave_inv_,                      se::Success,                     ss.sync_enter_inventory_,                tf::Immediate);
94✔
101
        main_states_.AddTransition(ss.idle_leave_inv_,                      se::Failure,                     ss.sync_enter_inventory_,                tf::Immediate);
94✔
102

103
        main_states_.AddTransition(ss.sync_enter_inventory_,                se::Success,                     submit_inventory_state_,                 tf::Immediate);
94✔
104
        main_states_.AddTransition(ss.sync_enter_inventory_,                se::Failure,                     ss.sync_error_,                          tf::Immediate);
94✔
105

106
        main_states_.AddTransition(submit_inventory_state_,                 se::Success,                     ss.sync_leave_,                          tf::Immediate);
94✔
107
        main_states_.AddTransition(submit_inventory_state_,                 se::Failure,                     ss.sync_error_,                          tf::Immediate);
94✔
108

109
        main_states_.AddTransition(poll_for_deployment_state_,              se::Success,                     ss.sync_leave_download_,                 tf::Immediate);
94✔
110
        main_states_.AddTransition(poll_for_deployment_state_,              se::NothingToDo,                 ss.sync_leave_,                          tf::Immediate);
94✔
111
        main_states_.AddTransition(poll_for_deployment_state_,              se::Failure,                     ss.sync_error_,                          tf::Immediate);
94✔
112

113
        main_states_.AddTransition(ss.sync_leave_,                          se::Success,                     ss.idle_enter_,                          tf::Immediate);
94✔
114
        main_states_.AddTransition(ss.sync_leave_,                          se::Failure,                     ss.sync_error_,                          tf::Immediate);
94✔
115

116
        main_states_.AddTransition(ss.sync_leave_download_,                 se::Success,                     send_download_status_state_,             tf::Immediate);
94✔
117
        main_states_.AddTransition(ss.sync_leave_download_,                 se::Failure,                     ss.sync_error_download_,                 tf::Immediate);
94✔
118

119
        main_states_.AddTransition(ss.sync_error_download_,                 se::Success,                     end_of_deployment_state_,                tf::Immediate);
94✔
120
        main_states_.AddTransition(ss.sync_error_download_,                 se::Failure,                     end_of_deployment_state_,                tf::Immediate);
94✔
121

122
        // Cannot fail due to FailureMode::Ignore.
123
        main_states_.AddTransition(send_download_status_state_,             se::Success,                     ss.download_enter_,                      tf::Immediate);
94✔
124

125
        main_states_.AddTransition(ss.download_enter_,                      se::Success,                     update_download_state_,                  tf::Immediate);
94✔
126
        main_states_.AddTransition(ss.download_enter_,                      se::Failure,                     ss.download_error_,                      tf::Immediate);
94✔
127
        main_states_.AddTransition(ss.download_enter_,                      se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
128
        main_states_.AddTransition(ss.download_error_,                      se::Success,                     update_rollback_not_needed_state_,       tf::Immediate);
94✔
129
        main_states_.AddTransition(ss.download_error_,                      se::Failure,                     update_rollback_not_needed_state_,       tf::Immediate);
94✔
130

131
        main_states_.AddTransition(update_download_state_,                  se::Success,                     ss.download_leave_,                      tf::Immediate);
94✔
132
        main_states_.AddTransition(update_download_state_,                  se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
133
        main_states_.AddTransition(update_download_state_,                  se::Failure,                     update_download_cancel_state_,           tf::Immediate);
94✔
134
        main_states_.AddTransition(update_download_state_,                  se::NothingToDo,                 ss.download_leave_save_provides,         tf::Immediate);
94✔
135

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

139
        main_states_.AddTransition(ss.download_leave_,                      se::Success,                     send_install_status_state_,              tf::Immediate);
94✔
140
        main_states_.AddTransition(ss.download_leave_,                      se::Failure,                     ss.download_error_,                      tf::Immediate);
94✔
141

142
        main_states_.AddTransition(ss.download_leave_save_provides,         se::Success,                     update_save_provides_state_,             tf::Immediate);
94✔
143
        main_states_.AddTransition(ss.download_leave_save_provides,         se::Failure,                     ss.download_error_,                      tf::Immediate);
94✔
144

145
        main_states_.AddTransition(ss.install_enter_,                       se::Success,                     update_install_state_,                   tf::Immediate);
94✔
146
        main_states_.AddTransition(ss.install_enter_,                       se::Failure,                     ss.install_error_rollback_,              tf::Immediate);
94✔
147

148
        // Cannot fail due to FailureMode::Ignore.
149
        main_states_.AddTransition(send_install_status_state_,              se::Success,                     ss.install_enter_,                       tf::Immediate);
94✔
150

151
        main_states_.AddTransition(update_install_state_,                   se::Success,                     ss.install_leave_,                       tf::Immediate);
94✔
152
        main_states_.AddTransition(update_install_state_,                   se::Failure,                     ss.install_error_rollback_,              tf::Immediate);
94✔
153
        main_states_.AddTransition(update_install_state_,                   se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
154

155
        main_states_.AddTransition(ss.install_leave_,                       se::Success,                     update_check_reboot_state_,              tf::Immediate);
94✔
156
        main_states_.AddTransition(ss.install_leave_,                       se::Failure,                     ss.install_error_rollback_,              tf::Immediate);
94✔
157
        main_states_.AddTransition(ss.install_error_rollback_,              se::Success,                     update_check_rollback_state_,            tf::Immediate);
94✔
158
        main_states_.AddTransition(ss.install_error_rollback_,              se::Failure,                     update_check_rollback_state_,            tf::Immediate);
94✔
159

160
        main_states_.AddTransition(ss.failure_enter_,                       se::Success,                     update_failure_state_,                   tf::Immediate);
94✔
161
        main_states_.AddTransition(ss.failure_enter_,                       se::Failure,                     update_failure_state_,                   tf::Immediate);
94✔
162
        main_states_.AddTransition(ss.failure_enter_,                       se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
163

164

165
        main_states_.AddTransition(update_check_reboot_state_,              se::Success,                     send_reboot_status_state_,               tf::Immediate);
94✔
166
        main_states_.AddTransition(update_check_reboot_state_,              se::NothingToDo,                 update_before_commit_state_,             tf::Immediate);
94✔
167
        main_states_.AddTransition(update_check_reboot_state_,              se::Failure,                     update_check_rollback_state_,            tf::Immediate);
94✔
168
        main_states_.AddTransition(update_check_reboot_state_,              se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
169

170
        // Cannot fail due to FailureMode::Ignore.
171
        main_states_.AddTransition(send_reboot_status_state_,               se::Success,                     ss.reboot_enter_,                        tf::Immediate);
94✔
172

173
        main_states_.AddTransition(ss.reboot_enter_,                        se::Success,                     update_reboot_state_,                    tf::Immediate);
94✔
174
        main_states_.AddTransition(ss.reboot_enter_,                        se::Failure,                     ss.reboot_error_,                        tf::Immediate);
94✔
175

176
        main_states_.AddTransition(update_reboot_state_,                    se::Success,                     update_verify_reboot_state_,             tf::Immediate);
94✔
177
        main_states_.AddTransition(update_reboot_state_,                    se::Failure,                     ss.reboot_error_,                        tf::Immediate);
94✔
178
        main_states_.AddTransition(update_reboot_state_,                    se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
179

180
        main_states_.AddTransition(ss.reboot_error_,                        se::Success,                     update_check_rollback_state_,            tf::Immediate);
94✔
181
        main_states_.AddTransition(ss.reboot_error_,                        se::Failure,                     update_check_rollback_state_,            tf::Immediate);
94✔
182

183
        main_states_.AddTransition(update_verify_reboot_state_,             se::Success,                     ss.reboot_leave_,                        tf::Immediate);
94✔
184
        main_states_.AddTransition(update_verify_reboot_state_,             se::Failure,                     ss.reboot_error_,                        tf::Immediate);
94✔
185
        main_states_.AddTransition(update_verify_reboot_state_,             se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
186

187
        main_states_.AddTransition(ss.reboot_leave_,                        se::Success,                     update_before_commit_state_,             tf::Immediate);
94✔
188
        main_states_.AddTransition(ss.reboot_leave_,                        se::Failure,                     ss.reboot_error_,                        tf::Immediate);
94✔
189

190
        // Cannot fail.
191
        main_states_.AddTransition(update_before_commit_state_,             se::Success,                     send_commit_status_state_,               tf::Immediate);
94✔
192

193
        main_states_.AddTransition(send_commit_status_state_,               se::Success,                     ss.commit_enter_,                        tf::Immediate);
94✔
194
        main_states_.AddTransition(send_commit_status_state_,               se::Failure,                     update_check_rollback_state_,            tf::Immediate);
94✔
195

196
        main_states_.AddTransition(ss.commit_enter_,                        se::Success,                     update_commit_state_,                    tf::Immediate);
94✔
197
        main_states_.AddTransition(ss.commit_enter_,                        se::Failure,                     ss.commit_error_,                        tf::Immediate);
94✔
198

199
        main_states_.AddTransition(ss.commit_error_,                        se::Success,                     update_check_rollback_state_,            tf::Immediate);
94✔
200
        main_states_.AddTransition(ss.commit_error_,                        se::Failure,                     update_check_rollback_state_,            tf::Immediate);
94✔
201

202
        main_states_.AddTransition(update_commit_state_,                    se::Success,                     update_after_commit_state_,              tf::Immediate);
94✔
203
        main_states_.AddTransition(update_commit_state_,                    se::Failure,                     ss.commit_error_,                        tf::Immediate);
94✔
204
        main_states_.AddTransition(update_commit_state_,                    se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
205

206
        main_states_.AddTransition(update_after_commit_state_,              se::Success,                     ss.commit_leave_,                        tf::Immediate);
94✔
207
        main_states_.AddTransition(update_after_commit_state_,              se::Failure,                     ss.commit_error_save_provides_,          tf::Immediate);
94✔
208
        main_states_.AddTransition(update_after_commit_state_,              se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
209

210
        main_states_.AddTransition(ss.commit_leave_,                        se::Success,                     update_save_provides_state_,             tf::Immediate);
94✔
211
        main_states_.AddTransition(ss.commit_leave_,                        se::Failure,                     ss.commit_error_save_provides_,          tf::Immediate);
94✔
212

213
        main_states_.AddTransition(ss.commit_error_save_provides_,          se::Success,                     update_save_provides_state_,             tf::Immediate);
94✔
214
        main_states_.AddTransition(ss.commit_error_save_provides_,          se::Failure,                     update_save_provides_state_,             tf::Immediate);
94✔
215

216
        main_states_.AddTransition(update_check_rollback_state_,            se::Success,                     ss.rollback_enter_,                      tf::Immediate);
94✔
217
        main_states_.AddTransition(update_check_rollback_state_,            se::NothingToDo,                 ss.failure_enter_,                       tf::Immediate);
94✔
218
        main_states_.AddTransition(update_check_rollback_state_,            se::Failure,                     ss.failure_enter_,                       tf::Immediate);
94✔
219
        main_states_.AddTransition(update_check_rollback_state_,            se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
220

221
        main_states_.AddTransition(ss.rollback_enter_,                      se::Success,                     update_rollback_state_,                  tf::Immediate);
94✔
222
        main_states_.AddTransition(ss.rollback_enter_,                      se::Failure,                     update_rollback_state_,                  tf::Immediate);
94✔
223

224
        main_states_.AddTransition(update_rollback_state_,                  se::Success,                     ss.rollback_leave_,                      tf::Immediate);
94✔
225
        main_states_.AddTransition(update_rollback_state_,                  se::Failure,                     ss.rollback_leave_error_,                tf::Immediate);
94✔
226
        main_states_.AddTransition(update_rollback_state_,                  se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
227

228
        main_states_.AddTransition(ss.rollback_leave_,                      se::Success,                     update_check_rollback_reboot_state_,     tf::Immediate);
94✔
229
        main_states_.AddTransition(ss.rollback_leave_,                      se::Failure,                     update_check_rollback_reboot_state_,     tf::Immediate);
94✔
230

231
        main_states_.AddTransition(ss.rollback_leave_error_,                se::Success,                     ss.failure_enter_,                       tf::Immediate);
94✔
232
        main_states_.AddTransition(ss.rollback_leave_error_,                se::Failure,                     ss.failure_enter_,                       tf::Immediate);
94✔
233

234
        main_states_.AddTransition(update_check_rollback_reboot_state_,     se::Success,                     ss.rollback_reboot_enter_,               tf::Immediate);
94✔
235
        main_states_.AddTransition(update_check_rollback_reboot_state_,     se::NothingToDo,                 update_rollback_successful_state_,       tf::Immediate);
94✔
236
        main_states_.AddTransition(update_check_rollback_reboot_state_,     se::Failure,                     ss.failure_enter_,                       tf::Immediate);
94✔
237
        main_states_.AddTransition(update_check_rollback_reboot_state_,     se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
238

239
        main_states_.AddTransition(ss.rollback_reboot_enter_,               se::Success,                     update_rollback_reboot_state_,           tf::Immediate);
94✔
240
        main_states_.AddTransition(ss.rollback_reboot_enter_,               se::Failure,                     update_rollback_reboot_state_,           tf::Immediate);
94✔
241

242
        main_states_.AddTransition(ss.rollback_reboot_error_,               se::Success,                     ss.failure_enter_,                       tf::Immediate);
94✔
243
        main_states_.AddTransition(ss.rollback_reboot_error_,               se::Failure,                     ss.failure_enter_,                       tf::Immediate);
94✔
244

245
        // No Failure transition for this state see comments in handler.
246
        main_states_.AddTransition(update_rollback_reboot_state_,           se::Success,                     update_verify_rollback_reboot_state_,    tf::Immediate);
94✔
247
        main_states_.AddTransition(update_rollback_reboot_state_,           se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
248

249
        main_states_.AddTransition(update_verify_rollback_reboot_state_,    se::Success,                     ss.rollback_reboot_leave_,               tf::Immediate);
94✔
250
        main_states_.AddTransition(update_verify_rollback_reboot_state_,    se::Retry,                       update_rollback_reboot_state_,           tf::Immediate);
94✔
251
        main_states_.AddTransition(update_verify_rollback_reboot_state_,    se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
252

253
        main_states_.AddTransition(ss.rollback_reboot_leave_,               se::Success,                     update_rollback_successful_state_,       tf::Immediate);
94✔
254
        main_states_.AddTransition(ss.rollback_reboot_leave_,               se::Failure,                     ss.rollback_reboot_error_,               tf::Immediate);
94✔
255

256
        main_states_.AddTransition(update_rollback_successful_state_,       se::Success,                     ss.failure_enter_,                       tf::Immediate);
94✔
257

258
        main_states_.AddTransition(update_failure_state_,                   se::Success,                     ss.failure_leave_update_save_provides_,  tf::Immediate);
94✔
259
        main_states_.AddTransition(update_failure_state_,                   se::Failure,                     ss.failure_leave_update_save_provides_,  tf::Immediate);
94✔
260
        main_states_.AddTransition(update_failure_state_,                   se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
261

262
        main_states_.AddTransition(ss.failure_leave_update_save_provides_,  se::Success,                     update_save_provides_state_,             tf::Immediate);
94✔
263
        main_states_.AddTransition(ss.failure_leave_update_save_provides_,  se::Failure,                     update_save_provides_state_,             tf::Immediate);
94✔
264

265
        // Even if this fails there is nothing we can do at this point.
266
        main_states_.AddTransition(update_save_provides_state_,             se::Success,                     update_cleanup_state_,                   tf::Immediate);
94✔
267
        main_states_.AddTransition(update_save_provides_state_,             se::Failure,                     update_cleanup_state_,                   tf::Immediate);
94✔
268
        main_states_.AddTransition(update_save_provides_state_,             se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
269

270
        main_states_.AddTransition(update_rollback_not_needed_state_,       se::Success,                     update_cleanup_state_,                   tf::Immediate);
94✔
271

272
        main_states_.AddTransition(update_cleanup_state_,                   se::Success,                     send_final_status_state_,                tf::Immediate);
94✔
273
        main_states_.AddTransition(update_cleanup_state_,                   se::Failure,                     send_final_status_state_,                tf::Immediate);
94✔
274
        main_states_.AddTransition(update_cleanup_state_,                   se::StateLoopDetected,           state_loop_state_,                       tf::Immediate);
94✔
275

276
        main_states_.AddTransition(state_loop_state_,                       se::Success,                     send_final_status_state_,                tf::Immediate);
94✔
277
        main_states_.AddTransition(state_loop_state_,                       se::Failure,                     send_final_status_state_,                tf::Immediate);
94✔
278

279
        main_states_.AddTransition(send_final_status_state_,                se::Success,                     clear_artifact_data_state_,              tf::Immediate);
94✔
280
        main_states_.AddTransition(send_final_status_state_,                se::Failure,                     clear_artifact_data_state_,              tf::Immediate);
94✔
281

282
        main_states_.AddTransition(clear_artifact_data_state_,              se::Success,                     end_of_deployment_state_,                tf::Immediate);
94✔
283
        main_states_.AddTransition(clear_artifact_data_state_,              se::Failure,                     end_of_deployment_state_,                tf::Immediate);
94✔
284

285
        main_states_.AddTransition(end_of_deployment_state_,                se::Success,                     ss.idle_enter_,                          tf::Immediate);
94✔
286

287
        auto &dt = deployment_tracking_;
288

289
        dt.states_.AddTransition(dt.idle_state_,                            se::DeploymentStarted,           dt.no_failures_state_,                   tf::Immediate);
94✔
290

291
        dt.states_.AddTransition(dt.no_failures_state_,                     se::Failure,                     dt.failure_state_,                       tf::Immediate);
94✔
292
        dt.states_.AddTransition(dt.no_failures_state_,                     se::DeploymentEnded,             dt.idle_state_,                          tf::Immediate);
94✔
293

294
        dt.states_.AddTransition(dt.failure_state_,                         se::RollbackStarted,             dt.rollback_attempted_state_,            tf::Immediate);
94✔
295
        dt.states_.AddTransition(dt.failure_state_,                         se::DeploymentEnded,             dt.idle_state_,                          tf::Immediate);
94✔
296

297
        dt.states_.AddTransition(dt.rollback_attempted_state_,              se::Failure,                     dt.rollback_failed_state_,               tf::Immediate);
94✔
298
        dt.states_.AddTransition(dt.rollback_attempted_state_,              se::DeploymentEnded,             dt.idle_state_,                          tf::Immediate);
94✔
299

300
        dt.states_.AddTransition(dt.rollback_failed_state_,                 se::DeploymentEnded,             dt.idle_state_,                          tf::Immediate);
94✔
301
        // clang-format on
302
}
94✔
303

304
StateMachine::StateMachine(
89✔
305
        Context &ctx, events::EventLoop &event_loop, chrono::milliseconds minimum_wait_time) :
89✔
306
        StateMachine(ctx, event_loop) {
89✔
307
        send_commit_status_state_.SetSmallestWaitInterval(minimum_wait_time);
89✔
308
        send_final_status_state_.SetSmallestWaitInterval(minimum_wait_time);
89✔
309
}
89✔
310

311
StateMachine::DeploymentTracking::DeploymentTracking() :
94✔
312
        states_(idle_state_) {
94✔
313
}
94✔
314

315
void StateMachine::LoadStateFromDb() {
90✔
316
        unique_ptr<StateData> state_data(new StateData);
124✔
317
        auto exp_loaded = ctx_.LoadDeploymentStateData(*state_data);
90✔
318
        if (!exp_loaded) {
90✔
319
                if (exp_loaded.error().code
2✔
320
                        == context::MakeError(context::StateDataStoreCountExceededError, "").code) {
2✔
321
                        log::Error("State loop detected. Forcefully aborting update.");
2✔
322

323
                        // This particular error code also fills in state_data.
324
                        ctx_.deployment.state_data = std::move(state_data);
1✔
325

326
                        ctx_.BeginDeploymentLogging();
1✔
327

328
                        main_states_.SetState(state_loop_state_);
1✔
329
                        deployment_tracking_.states_.SetState(deployment_tracking_.rollback_failed_state_);
1✔
330
                } else {
331
                        log::Error(
1✔
332
                                "Unable to load deployment data from database: " + exp_loaded.error().String());
2✔
333
                        log::Error("Starting from initial state");
2✔
334
                }
335
                return;
2✔
336
        }
337

338
        auto &store = ctx_.mender_context.GetMenderStoreDB();
88✔
339

340
        if (!exp_loaded.value()) {
88✔
341
                log::Debug("No existing deployment data, starting from initial state");
106✔
342

343
                auto err = store.Remove(ctx_.mender_context.update_control_maps);
53✔
344
                if (err != error::NoError) {
53✔
345
                        log::Error(
×
346
                                "Error removing " + ctx_.mender_context.update_control_maps
×
347
                                + " key from database: " + err.String());
×
348
                        // Nothing we can do about it.
349
                }
350

351
                return;
352
        }
353

354
        // We have state data, move it to the context.
355
        ctx_.deployment.state_data = std::move(state_data);
35✔
356

357
        ctx_.BeginDeploymentLogging();
35✔
358

359
        bool update_control_enabled = false;
360
        auto exp_update_control_data = store.Read(ctx_.mender_context.update_control_maps);
35✔
361
        if (exp_update_control_data) {
35✔
362
                auto update_control_data = common::StringFromByteVector(exp_update_control_data.value());
2✔
363
                if (update_control_data != "" && update_control_data != "{}") {
2✔
364
                        update_control_enabled = true;
365
                }
366
        } else if (exp_update_control_data.error().code != kvdb::MakeError(kvdb::KeyError, "").code) {
33✔
367
                log::Error("Error while loading update control data from database");
×
368
                // Since we don't actually need it, continue anyway.
369
        }
370

371
        auto &state = ctx_.deployment.state_data->state;
35✔
372

373
        if (state == ctx_.kUpdateStateDownload) {
35✔
374
                main_states_.SetState(update_cleanup_state_);
3✔
375
                // "rollback_attempted_state" because Download in its nature makes no system
376
                // changes, so a rollback is a no-op.
377
                deployment_tracking_.states_.SetState(deployment_tracking_.rollback_attempted_state_);
3✔
378

379
        } else if (state == ctx_.kUpdateStateArtifactReboot) {
32✔
380
                // Normal update path with a reboot.
381
                if (update_control_enabled) {
5✔
382
                        log::Error(
1✔
383
                                "This deployment was done using Update Control, but this client does not support Update Control. Failing / rolling back deployment.");
2✔
384
                        main_states_.SetState(state_scripts_.reboot_error_);
1✔
385
                        deployment_tracking_.states_.SetState(deployment_tracking_.failure_state_);
1✔
386
                } else {
387
                        main_states_.SetState(update_verify_reboot_state_);
4✔
388
                        deployment_tracking_.states_.SetState(deployment_tracking_.no_failures_state_);
4✔
389
                }
390

391
        } else if (state == ctx_.kUpdateStateArtifactRollback) {
27✔
392
                // Installation failed, but rollback could still succeed.
393
                main_states_.SetState(state_scripts_.rollback_enter_);
3✔
394
                deployment_tracking_.states_.SetState(deployment_tracking_.rollback_attempted_state_);
3✔
395

396
        } else if (
397
                state == ctx_.kUpdateStateArtifactRollbackReboot
24✔
398
                || state == ctx_.kUpdateStateArtifactVerifyRollbackReboot
22✔
399
                || state == ctx_.kUpdateStateVerifyRollbackReboot) {
44✔
400
                // Normal flow for a rebooting rollback.
401
                main_states_.SetState(update_verify_rollback_reboot_state_);
4✔
402
                deployment_tracking_.states_.SetState(deployment_tracking_.rollback_attempted_state_);
4✔
403

404
        } else if (
405
                state == ctx_.kUpdateStateAfterArtifactCommit
20✔
406
                || state == ctx_.kUpdateStateUpdateAfterFirstCommit) {
20✔
407
                // Re-run commit Leave scripts if spontaneously rebooted after commit.
408
                main_states_.SetState(update_after_commit_state_);
2✔
409
                deployment_tracking_.states_.SetState(deployment_tracking_.no_failures_state_);
2✔
410

411
        } else if (state == ctx_.kUpdateStateArtifactFailure) {
18✔
412
                // Re-run ArtifactFailure if spontaneously rebooted before finishing.
413
                main_states_.SetState(state_scripts_.failure_enter_);
4✔
414
                if (ctx_.deployment.state_data->update_info.all_rollbacks_successful) {
4✔
415
                        deployment_tracking_.states_.SetState(deployment_tracking_.rollback_attempted_state_);
3✔
416
                } else {
417
                        deployment_tracking_.states_.SetState(deployment_tracking_.failure_state_);
1✔
418
                }
419

420
        } else if (state == ctx_.kUpdateStateCleanup) {
14✔
421
                // Re-run Cleanup if spontaneously rebooted before finishing.
422
                main_states_.SetState(update_cleanup_state_);
2✔
423
                if (ctx_.deployment.state_data->update_info.all_rollbacks_successful) {
2✔
424
                        deployment_tracking_.states_.SetState(deployment_tracking_.rollback_attempted_state_);
1✔
425
                } else {
426
                        deployment_tracking_.states_.SetState(deployment_tracking_.failure_state_);
1✔
427
                }
428

429
        } else {
430
                // All other states trigger a rollback.
431
                main_states_.SetState(update_check_rollback_state_);
12✔
432
                deployment_tracking_.states_.SetState(deployment_tracking_.failure_state_);
12✔
433
        }
434

435
        auto &payload_types = ctx_.deployment.state_data->update_info.artifact.payload_types;
35✔
436
        if (payload_types.size() == 0) {
35✔
437
                ctx_.deployment.update_module.reset();
438
                return;
439
        }
440
        assert(payload_types.size() == 1);
441
        ctx_.deployment.update_module.reset(
442
                new update_module::UpdateModule(ctx_.mender_context, payload_types[0]));
34✔
443
}
444

445
error::Error StateMachine::Run() {
93✔
446
        // Client is supposed to do one handling of each on startup.
447
        runner_.PostEvent(StateEvent::InventoryPollingTriggered);
93✔
448
        runner_.PostEvent(StateEvent::DeploymentPollingTriggered);
93✔
449

450
        auto err = RegisterSignalHandlers();
93✔
451
        if (err != error::NoError) {
93✔
452
                return err;
×
453
        }
454

455
        log::Info("Running Mender client " + conf::kMenderVersion);
93✔
456

457
        event_loop_.Run();
93✔
458
        return exit_state_.exit_error;
93✔
459
}
460

461
void StateMachine::StopAfterDeployment() {
91✔
462
        main_states_.AddTransition(
91✔
463
                end_of_deployment_state_,
464
                StateEvent::DeploymentEnded,
465
                exit_state_,
466
                sm::TransitionFlag::Immediate);
467
}
91✔
468

469
#ifndef NDEBUG
470
void StateMachine::StopAfterDeployments(int number) {
471
        exit_state_.ExitAfter(number);
472
        main_states_.AddTransition(
473
                end_of_deployment_state_, StateEvent::Success, exit_state_, sm::TransitionFlag::Immediate);
474
        main_states_.AddTransition(
475
                exit_state_,
476
                StateEvent::Success,
477
                state_scripts_.idle_enter_,
478
                sm::TransitionFlag::Immediate);
479
}
480
#endif
481

482
} // namespace daemon
483
} // namespace update
484
} // namespace mender
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc