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

mendersoftware / mender / 1033353997

11 Oct 2023 01:43PM UTC coverage: 79.99% (-0.2%) from 80.166%
1033353997

push

gitlab-ci

oleorhagen
style: Run clang-format on the whole repository

Signed-off-by: Ole Petter <ole.orhagen@northern.tech>

1 of 1 new or added line in 1 file covered. (100.0%)

6492 of 8116 relevant lines covered (79.99%)

9901.24 hits per line

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

88.62
/mender-update/daemon/context.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/context.hpp>
16

17
#include <common/common.hpp>
18
#include <common/conf.hpp>
19
#include <common/log.hpp>
20
#include <mender-update/http_resumer.hpp>
21

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

26
namespace common = mender::common;
27
namespace conf = mender::common::conf;
28
namespace log = mender::common::log;
29
namespace http_resumer = mender::update::http_resumer;
30

31
namespace main_context = mender::update::context;
32

33
const int kStateDataVersion = 2;
34

35
// The maximum times we are allowed to move through update states. If this is exceeded then the
36
// update will be forcefully aborted. This can happen if we are in a reboot loop, for example.
37
const int kMaxStateDataStoreCount = 28;
38

39
ExpectedStateData ApiResponseJsonToStateData(const json::Json &json) {
55✔
40
        StateData data;
110✔
41

42
        expected::ExpectedString str = json.Get("id").and_then(json::ToString);
110✔
43
        if (!str) {
55✔
44
                return expected::unexpected(str.error().WithContext("Could not get deployment ID"));
×
45
        }
46
        data.update_info.id = str.value();
55✔
47

48
        str = json.Get("artifact")
110✔
49
                          .and_then([](const json::Json &json) { return json.Get("source"); })
110✔
50
                          .and_then([](const json::Json &json) { return json.Get("uri"); })
110✔
51
                          .and_then(json::ToString);
55✔
52
        if (!str) {
55✔
53
                return expected::unexpected(
×
54
                        str.error().WithContext("Could not get artifact URI for deployment"));
×
55
        }
56
        data.update_info.artifact.source.uri = str.value();
55✔
57
        log::Debug("Artifact Download URL: " + data.update_info.artifact.source.uri);
55✔
58

59
        str = json.Get("artifact")
110✔
60
                          .and_then([](const json::Json &json) { return json.Get("source"); })
110✔
61
                          .and_then([](const json::Json &json) { return json.Get("expire"); })
110✔
62
                          .and_then(json::ToString);
55✔
63
        if (str) {
55✔
64
                data.update_info.artifact.source.expire = str.value();
55✔
65
                // If it's not available, we don't care.
66
        }
67

68
        // For later: Update Control Maps should be handled here.
69

70
        // Note: There is more information available in the response than we collect here, but we
71
        // prefer to get the information from the artifact instead, since it is the authoritative
72
        // source. And it's also signed, unlike the response.
73

74
        return data;
55✔
75
}
76

77
// Database keys
78
const string Context::kRollbackNotSupported = "rollback-not-supported";
79
const string Context::kRollbackSupported = "rollback-supported";
80

81
string SupportsRollbackToDbString(bool support) {
44✔
82
        return support ? Context::kRollbackSupported : Context::kRollbackNotSupported;
50✔
83
}
84

85
expected::ExpectedBool DbStringToSupportsRollback(const string &str) {
14✔
86
        if (str == Context::kRollbackSupported) {
14✔
87
                return true;
88
        } else if (str == Context::kRollbackNotSupported) {
2✔
89
                return false;
90
        } else {
91
                return expected::unexpected(main_context::MakeError(
×
92
                        main_context::DatabaseValueError,
93
                        "\"" + str + "\" is not a valid value for SupportsRollback"));
×
94
        }
95
}
96

97
// Database keys
98
const string Context::kRebootTypeNone = "";
99
const string Context::kRebootTypeCustom = "reboot-type-custom";
100
const string Context::kRebootTypeAutomatic = "reboot-type-automatic";
101

102
string NeedsRebootToDbString(update_module::RebootAction action) {
71✔
103
        switch (action) {
71✔
104
        case update_module::RebootAction::No:
8✔
105
                return Context::kRebootTypeNone;
8✔
106
        case update_module::RebootAction::Automatic:
×
107
                return Context::kRebootTypeAutomatic;
×
108
        case update_module::RebootAction::Yes:
63✔
109
                return Context::kRebootTypeCustom;
63✔
110
        default:
×
111
                // Should not happen.
112
                assert(false);
113
                return Context::kRebootTypeNone;
×
114
        }
115
}
116

117
update_module::ExpectedRebootAction DbStringToNeedsReboot(const string &str) {
50✔
118
        if (str == Context::kRebootTypeNone) {
50✔
119
                return update_module::RebootAction::No;
120
        } else if (str == Context::kRebootTypeAutomatic) {
50✔
121
                return update_module::RebootAction::Automatic;
122
        } else if (str == Context::kRebootTypeCustom) {
50✔
123
                return update_module::RebootAction::Yes;
124
        } else {
125
                return expected::unexpected(main_context::MakeError(
×
126
                        main_context::DatabaseValueError,
127
                        "\"" + str + "\" is not a valid value for RebootRequested"));
×
128
        }
129
}
130

131
void StateData::FillUpdateDataFromArtifact(artifact::PayloadHeaderView &view) {
49✔
132
        auto &artifact = update_info.artifact;
133
        auto &header = view.header;
134
        artifact.compatible_devices = header.header_info.depends.device_type;
49✔
135
        artifact.payload_types = {header.payload_type};
147✔
136
        artifact.artifact_name = header.artifact_name;
49✔
137
        artifact.artifact_group = header.artifact_group;
49✔
138
        if (header.type_info.artifact_provides) {
49✔
139
                artifact.type_info_provides = header.type_info.artifact_provides.value();
48✔
140
        } else {
141
                artifact.type_info_provides.clear();
142
        }
143
        if (header.type_info.clears_artifact_provides) {
49✔
144
                artifact.clears_artifact_provides = header.type_info.clears_artifact_provides.value();
48✔
145
        } else {
146
                artifact.clears_artifact_provides.clear();
1✔
147
        }
148
}
49✔
149

150
Context::Context(main_context::MenderContext &mender_context, events::EventLoop &event_loop) :
93✔
151
        Context(
152
                mender_context,
153
                event_loop,
154
                http::ClientConfig {
186✔
155
                        .server_cert_path = mender_context.GetConfig().server_certificate,
93✔
156
                        .client_cert_path = mender_context.GetConfig().https_client.certificate,
93✔
157
                        .client_cert_key_path = mender_context.GetConfig().https_client.key,
93✔
158
                        .skip_verify = mender_context.GetConfig().skip_verify,
93✔
159
                }) {
93✔
160
}
93✔
161

162
Context::Context(
93✔
163
        mender::update::context::MenderContext &mender_context,
164
        events::EventLoop &event_loop,
165
        const http::ClientConfig &http_config) :
93✔
166
        mender_context(mender_context),
167
        event_loop(event_loop),
168
        authenticator(
169
                event_loop,
170
                http_config,
171
                mender_context.GetConfig().server_url,
93✔
172
                mender_context.GetConfig().paths.GetKeyFile(),
93✔
173
                mender_context.GetConfig().paths.GetIdentityScript(),
93✔
174
                mender_context.GetConfig().tenant_token),
93✔
175
        http_client(http_config, event_loop, authenticator),
176
        download_client(make_shared<http_resumer::DownloadResumerClient>(http_config, event_loop)),
93✔
177
        deployment_client(make_shared<deployments::DeploymentClient>()),
93✔
178
        inventory_client(make_shared<inventory::InventoryClient>()) {
558✔
179
}
93✔
180

181
///////////////////////////////////////////////////////////////////////////////////////////////////
182
// Values for various states in the database.
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

185
// In use by current client. Some of the variable names have been updated from the Golang version,
186
// but the database strings are the same. Some naming is inconsistent, this is for historical
187
// reasons, and it's better to look at the names for the variables.
188
const string Context::kUpdateStateDownload = "update-store";
189
const string Context::kUpdateStateArtifactInstall = "update-install";
190
const string Context::kUpdateStateArtifactReboot = "reboot";
191
const string Context::kUpdateStateArtifactVerifyReboot = "after-reboot";
192
const string Context::kUpdateStateArtifactCommit = "update-commit";
193
const string Context::kUpdateStateAfterArtifactCommit = "update-after-commit";
194
const string Context::kUpdateStateArtifactRollback = "rollback";
195
const string Context::kUpdateStateArtifactRollbackReboot = "rollback-reboot";
196
const string Context::kUpdateStateArtifactVerifyRollbackReboot = "after-rollback-reboot";
197
const string Context::kUpdateStateArtifactFailure = "update-error";
198
const string Context::kUpdateStateCleanup = "cleanup";
199
const string Context::kUpdateStateStatusReportRetry = "update-retry-report";
200

201
///////////////////////////////////////////////////////////////////////////////////////////////////
202
// Not in use by current client, but were in use by Golang client, and still important to handle
203
// correctly in recovery scenarios.
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

206
// This client doesn't use it, but it's essentially equivalent to "update-after-commit".
207
const string Context::kUpdateStateUpdateAfterFirstCommit = "update-after-first-commit";
208
// This client doesn't use it, but it's essentially equivalent to "after-rollback-reboot".
209
const string Context::kUpdateStateVerifyRollbackReboot = "verify-rollback-reboot";
210
// No longer used. Since this used to be at the very end of an update, if we encounter it in the
211
// database during startup, we just go back to Idle.
212
const string UpdateStateReportStatusError = "status-report-error";
213

214
///////////////////////////////////////////////////////////////////////////////////////////////////
215
// Not in use. All of these, as well as unknown values, will cause a rollback.
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

218
// Disable, but distinguish from comments.
219
#if false
220
// These were never actually saved due to not being update states.
221
const string Context::kUpdateStateInit = "init";
222
const string Context::kUpdateStateIdle = "idle";
223
const string Context::kUpdateStateAuthorize = "authorize";
224
const string Context::kUpdateStateAuthorizeWait = "authorize-wait";
225
const string Context::kUpdateStateInventoryUpdate = "inventory-update";
226
const string Context::kUpdateStateInventoryUpdateRetryWait = "inventory-update-retry-wait";
227

228
const string Context::kUpdateStateCheckWait = "check-wait";
229
const string Context::kUpdateStateUpdateCheck = "update-check";
230
const string Context::kUpdateStateUpdateFetch = "update-fetch";
231
const string Context::kUpdateStateUpdateAfterStore = "update-after-store";
232
const string Context::kUpdateStateFetchStoreRetryWait = "fetch-install-retry-wait";
233
const string Context::kUpdateStateUpdateVerify = "update-verify";
234
const string Context::kUpdateStateUpdatePreCommitStatusReportRetry = "update-pre-commit-status-report-retry";
235
const string Context::kUpdateStateUpdateStatusReport = "update-status-report";
236
// Would have been used, but a copy/paste error in the Golang client means that it was never
237
// saved. "after-reboot" is stored twice instead.
238
const string Context::kUpdateStateVerifyReboot = "verify-reboot";
239
const string Context::kUpdateStateError = "error";
240
const string Context::kUpdateStateDone = "finished";
241
const string Context::kUpdateStateUpdateControl = "mender-update-control";
242
const string Context::kUpdateStateUpdateControlPause = "mender-update-control-pause";
243
const string Context::kUpdateStateFetchUpdateControl = "mender-update-control-refresh-maps";
244
const string Context::kUpdateStateFetchRetryUpdateControl = "mender-update-control-retry-refresh-maps";
245
#endif
246

247
///////////////////////////////////////////////////////////////////////////////////////////////////
248
// End of database values.
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

251
static string GenerateStateDataJson(const StateData &state_data) {
645✔
252
        stringstream content;
1,290✔
253

254
        auto append_vector = [&content](const vector<string> &data) {
2,580✔
255
                for (auto entry = data.begin(); entry != data.end(); entry++) {
4,757✔
256
                        if (entry != data.begin()) {
2,177✔
257
                                content << ",";
×
258
                        }
259
                        content << R"(")" << json::EscapeString(*entry) << R"(")";
4,354✔
260
                }
261
        };
2,580✔
262

263
        auto append_map = [&content](const unordered_map<string, string> &data) {
645✔
264
                for (auto entry = data.begin(); entry != data.end(); entry++) {
1,226✔
265
                        if (entry != data.begin()) {
581✔
266
                                content << ",";
×
267
                        }
268
                        content << R"(")" << json::EscapeString(entry->first) << R"(":")"
1,162✔
269
                                        << json::EscapeString(entry->second) << R"(")";
1,743✔
270
                }
271
        };
645✔
272

273
        content << "{";
645✔
274
        {
275
                content << R"("Version":)" << to_string(state_data.version) << ",";
645✔
276
                content << R"("Name":")" << json::EscapeString(state_data.state) << R"(",)";
645✔
277
                content << R"("UpdateInfo":{)";
645✔
278
                {
279
                        auto &update_info = state_data.update_info;
280
                        content << R"("Artifact":{)";
645✔
281
                        {
282
                                auto &artifact = update_info.artifact;
283
                                content << R"("Source":{)";
645✔
284
                                {
285
                                        content << R"("URI":")" << json::EscapeString(artifact.source.uri) << R"(",)";
645✔
286
                                        content << R"("Expire":")" << json::EscapeString(artifact.source.expire)
645✔
287
                                                        << R"(")";
1,290✔
288
                                }
289
                                content << "},";
645✔
290

291
                                content << R"("CompatibleDevices":[)";
645✔
292
                                append_vector(artifact.compatible_devices);
645✔
293
                                content << "],";
645✔
294

295
                                content << R"("PayloadTypes":[)";
645✔
296
                                append_vector(artifact.payload_types);
645✔
297
                                content << "],";
645✔
298

299
                                content << R"("ArtifactName":")" << json::EscapeString(artifact.artifact_name)
645✔
300
                                                << R"(",)";
1,290✔
301
                                content << R"("ArtifactGroup":")" << json::EscapeString(artifact.artifact_group)
645✔
302
                                                << R"(",)";
1,290✔
303

304
                                content << R"("TypeInfoProvides":{)";
645✔
305
                                append_map(artifact.type_info_provides);
645✔
306
                                content << "},";
645✔
307

308
                                content << R"("ClearsArtifactProvides":[)";
645✔
309
                                append_vector(artifact.clears_artifact_provides);
645✔
310
                                content << "]";
645✔
311
                        }
312
                        content << "},";
645✔
313

314
                        content << R"("ID":")" << json::EscapeString(update_info.id) << R"(",)";
645✔
315

316
                        content << R"("RebootRequested":[)";
645✔
317
                        append_vector(update_info.reboot_requested);
645✔
318
                        content << R"(],)";
645✔
319

320
                        content << R"("SupportsRollback":")"
321
                                        << json::EscapeString(update_info.supports_rollback) << R"(",)";
645✔
322
                        content << R"("StateDataStoreCount":)" << to_string(update_info.state_data_store_count)
645✔
323
                                        << R"(,)";
1,290✔
324
                        content << R"("HasDBSchemaUpdate":)"
325
                                        << string(update_info.has_db_schema_update ? "true," : "false,");
1,931✔
326
                        content << R"("AllRollbacksSuccessful":)"
327
                                        << string(update_info.all_rollbacks_successful ? "true" : "false");
1,788✔
328
                }
329
                content << "}";
645✔
330
        }
331
        content << "}";
645✔
332

333
        return std::move(*content.rdbuf()).str();
1,290✔
334
}
335

336
error::Error Context::SaveDeploymentStateData(kv_db::Transaction &txn, StateData &state_data) {
647✔
337
        if (state_data.update_info.state_data_store_count++ >= kMaxStateDataStoreCount) {
647✔
338
                return main_context::MakeError(
339
                        main_context::StateDataStoreCountExceededError,
340
                        "State looping detected, breaking out of loop");
4✔
341
        }
342

343
        string content = GenerateStateDataJson(state_data);
645✔
344

345
        string store_key;
346
        if (state_data.update_info.has_db_schema_update) {
645✔
347
                store_key = mender_context.state_data_key_uncommitted;
348

349
                // Leave state_data_key alone.
350
        } else {
351
                store_key = mender_context.state_data_key;
352

353
                auto err = txn.Remove(mender_context.state_data_key_uncommitted);
641✔
354
                if (err != error::NoError) {
641✔
355
                        return err.WithContext("Could not remove uncommitted state data");
×
356
                }
357
        }
358

359
        auto err = txn.Write(store_key, common::ByteVectorFromString(content));
645✔
360
        if (err != error::NoError) {
645✔
361
                return err.WithContext("Could not write state data");
×
362
        }
363

364
        return error::NoError;
645✔
365
}
366

367
error::Error Context::SaveDeploymentStateData(StateData &state_data) {
584✔
368
        auto &db = mender_context.GetMenderStoreDB();
584✔
369
        return db.WriteTransaction([this, &state_data](kv_db::Transaction &txn) {
575✔
370
                return SaveDeploymentStateData(txn, state_data);
575✔
371
        });
1,168✔
372
}
373

374
static error::Error UnmarshalJsonStateData(const json::Json &json, StateData &state_data) {
37✔
375
#define SetOrReturnIfError(dst, expr) \
376
        if (!expr) {                      \
377
                return expr.error();          \
378
        }                                 \
379
        dst = expr.value()
380

381
#define DefaultOrSetOrReturnIfError(dst, expr, def)                            \
382
        if (!expr) {                                                               \
383
                if (expr.error().code == kv_db::MakeError(kv_db::KeyError, "").code) { \
384
                        dst = def;                                                         \
385
                } else {                                                               \
386
                        return expr.error();                                               \
387
                }                                                                      \
388
        } else {                                                                   \
389
                dst = expr.value();                                                    \
390
        }
391

392
        auto exp_int = json.Get("Version").and_then(json::ToInt);
74✔
393
        SetOrReturnIfError(state_data.version, exp_int);
37✔
394

395
        if (state_data.version != kStateDataVersion) {
37✔
396
                return error::Error(
397
                        make_error_condition(errc::not_supported),
2✔
398
                        "State Data version not supported by this client");
2✔
399
        }
400

401
        auto exp_string = json.Get("Name").and_then(json::ToString);
72✔
402
        SetOrReturnIfError(state_data.state, exp_string);
36✔
403

404
        const auto &exp_json_update_info = json.Get("UpdateInfo");
36✔
405
        SetOrReturnIfError(const auto &json_update_info, exp_json_update_info);
36✔
406

407
        const auto &exp_json_artifact = json_update_info.Get("Artifact");
36✔
408
        SetOrReturnIfError(const auto &json_artifact, exp_json_artifact);
36✔
409

410
        const auto &exp_json_source = json_artifact.Get("Source");
36✔
411
        SetOrReturnIfError(const auto &json_source, exp_json_source);
36✔
412

413
        auto &update_info = state_data.update_info;
414
        auto &artifact = update_info.artifact;
415
        auto &source = artifact.source;
416

417
        exp_string = json_source.Get("URI").and_then(json::ToString);
72✔
418
        SetOrReturnIfError(source.uri, exp_string);
36✔
419

420
        exp_string = json_source.Get("Expire").and_then(json::ToString);
72✔
421
        SetOrReturnIfError(source.expire, exp_string);
36✔
422

423
        auto exp_string_vector = json_artifact.Get("CompatibleDevices").and_then(json::ToStringVector);
72✔
424
        SetOrReturnIfError(artifact.compatible_devices, exp_string_vector);
36✔
425

426
        exp_string = json_artifact.Get("ArtifactName").and_then(json::ToString);
72✔
427
        SetOrReturnIfError(artifact.artifact_name, exp_string);
36✔
428

429
        exp_string_vector = json_artifact.Get("PayloadTypes").and_then(json::ToStringVector);
72✔
430
        SetOrReturnIfError(artifact.payload_types, exp_string_vector);
36✔
431
        // It's possible for there not to be an initialized update,
432
        // if the deployment failed before we could successfully parse the artifact.
433
        if (artifact.payload_types.size() == 0 and artifact.artifact_name == "") {
36✔
434
                return error::NoError;
1✔
435
        }
436
        if (artifact.payload_types.size() != 1) {
35✔
437
                return error::Error(
438
                        make_error_condition(errc::not_supported),
×
439
                        "Only exactly one payload type is supported. Got: "
440
                                + to_string(artifact.payload_types.size()));
×
441
        }
442

443
        exp_string = json_artifact.Get("ArtifactGroup").and_then(json::ToString);
70✔
444
        SetOrReturnIfError(artifact.artifact_group, exp_string);
35✔
445

446
        auto exp_string_map = json_artifact.Get("TypeInfoProvides").and_then(json::ToKeyValuesMap);
70✔
447
        DefaultOrSetOrReturnIfError(artifact.type_info_provides, exp_string_map, {});
35✔
448

449
        exp_string_vector = json_artifact.Get("ClearsArtifactProvides").and_then(json::ToStringVector);
70✔
450
        DefaultOrSetOrReturnIfError(artifact.clears_artifact_provides, exp_string_vector, {});
35✔
451

452
        exp_string = json_update_info.Get("ID").and_then(json::ToString);
70✔
453
        SetOrReturnIfError(update_info.id, exp_string);
35✔
454

455
        exp_string_vector = json_update_info.Get("RebootRequested").and_then(json::ToStringVector);
70✔
456
        SetOrReturnIfError(update_info.reboot_requested, exp_string_vector);
35✔
457
        // Check that it's valid strings.
458
        for (const auto &reboot_requested : update_info.reboot_requested) {
61✔
459
                if (reboot_requested != "") {
26✔
460
                        auto exp_needs_reboot = DbStringToNeedsReboot(reboot_requested);
23✔
461
                        if (!exp_needs_reboot) {
23✔
462
                                return exp_needs_reboot.error();
×
463
                        }
464
                }
465
        }
466

467
        exp_string = json_update_info.Get("SupportsRollback").and_then(json::ToString);
70✔
468
        SetOrReturnIfError(update_info.supports_rollback, exp_string);
35✔
469
        // Check that it's a valid string.
470
        if (update_info.supports_rollback != "") {
35✔
471
                auto exp_supports_rollback = DbStringToSupportsRollback(update_info.supports_rollback);
14✔
472
                if (!exp_supports_rollback) {
14✔
473
                        return exp_supports_rollback.error();
×
474
                }
475
        }
476

477
        exp_int = json_update_info.Get("StateDataStoreCount").and_then(json::ToInt);
70✔
478
        SetOrReturnIfError(update_info.state_data_store_count, exp_int);
35✔
479

480
        auto exp_bool = json_update_info.Get("HasDBSchemaUpdate").and_then(json::ToBool);
70✔
481
        SetOrReturnIfError(update_info.has_db_schema_update, exp_bool);
35✔
482

483
        exp_bool = json_update_info.Get("AllRollbacksSuccessful").and_then(json::ToBool);
70✔
484
        DefaultOrSetOrReturnIfError(update_info.all_rollbacks_successful, exp_bool, false);
35✔
485

486
#undef SetOrReturnIfError
487
#undef EmptyOrSetOrReturnIfError
488

489
        return error::NoError;
35✔
490
}
491

492
expected::ExpectedBool Context::LoadDeploymentStateData(StateData &state_data) {
90✔
493
        auto &db = mender_context.GetMenderStoreDB();
90✔
494
        auto err = db.WriteTransaction([this, &state_data](kv_db::Transaction &txn) {
163✔
495
                auto exp_content = txn.Read(mender_context.state_data_key);
89✔
496
                if (!exp_content) {
89✔
497
                        return exp_content.error().WithContext("Could not load state data");
106✔
498
                }
499
                auto &content = exp_content.value();
36✔
500

501
                auto exp_json = json::Load(common::StringFromByteVector(content));
72✔
502
                if (!exp_json) {
36✔
503
                        return exp_json.error().WithContext("Could not load state data");
×
504
                }
505

506
                auto err = UnmarshalJsonStateData(exp_json.value(), state_data);
36✔
507
                if (err != error::NoError) {
36✔
508
                        if (err.code != make_error_condition(errc::not_supported)) {
1✔
509
                                return err.WithContext("Could not load state data");
×
510
                        }
511

512
                        // Try again with the state_data_key_uncommitted.
513
                        exp_content = txn.Read(mender_context.state_data_key_uncommitted);
2✔
514
                        if (!exp_content) {
1✔
515
                                return err.WithContext("Could not load state data").FollowedBy(exp_content.error());
×
516
                        }
517
                        auto &content = exp_content.value();
1✔
518

519
                        exp_json = json::Load(common::StringFromByteVector(content));
2✔
520
                        if (!exp_json) {
1✔
521
                                return err.WithContext("Could not load state data").FollowedBy(exp_json.error());
×
522
                        }
523

524
                        auto inner_err = UnmarshalJsonStateData(exp_json.value(), state_data);
1✔
525
                        if (inner_err != error::NoError) {
1✔
526
                                return err.WithContext("Could not load state data").FollowedBy(inner_err);
×
527
                        }
528

529
                        // Since we loaded from the uncommitted key, set this.
530
                        state_data.update_info.has_db_schema_update = true;
1✔
531
                }
532

533
                // Every load also saves, which increments the state_data_store_count.
534
                return SaveDeploymentStateData(txn, state_data);
36✔
535
        });
90✔
536

537
        if (err == error::NoError) {
90✔
538
                return true;
539
        } else if (err.code == kv_db::MakeError(kv_db::KeyError, "").code) {
55✔
540
                return false;
541
        } else {
542
                return expected::unexpected(err);
4✔
543
        }
544
}
545

546
void Context::BeginDeploymentLogging() {
91✔
547
        deployment.logger.reset(new deployments::DeploymentLog(
548
                mender_context.GetConfig().paths.GetUpdateLogPath(),
182✔
549
                deployment.state_data->update_info.id));
91✔
550
        auto err = deployment.logger->BeginLogging();
91✔
551
        if (err != error::NoError) {
91✔
552
                log::Error(
×
553
                        "Was not able to set up deployment log for deployment ID "
554
                        + deployment.state_data->update_info.id + ": " + err.String());
×
555
                // It's not a fatal error, so continue.
556
        }
557
}
91✔
558

559
void Context::FinishDeploymentLogging() {
91✔
560
        auto err = deployment.logger->FinishLogging();
91✔
561
        if (err != error::NoError) {
91✔
562
                log::Error(
×
563
                        "Was not able to stop deployment log for deployment ID "
564
                        + deployment.state_data->update_info.id + ": " + err.String());
×
565
                // We need to continue regardless
566
        }
567
}
91✔
568

569
} // namespace daemon
570
} // namespace update
571
} // 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

© 2025 Coveralls, Inc