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

mendersoftware / mender / 1022567176

02 Oct 2023 07:50AM UTC coverage: 80.127% (+2.5%) from 77.645%
1022567176

push

gitlab-ci

kacf
chore: Centralize selection of `std::filesystem` library.

Signed-off-by: Kristian Amlie <kristian.amlie@northern.tech>

6447 of 8046 relevant lines covered (80.13%)

9912.21 hits per line

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

95.76
/mender-update/update_module/v3/update_module.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/update_module/v3/update_module.hpp>
16

17
#include <common/events.hpp>
18
#include <common/error.hpp>
19
#include <common/expected.hpp>
20
#include <common/path.hpp>
21

22
namespace mender {
23
namespace update {
24
namespace update_module {
25
namespace v3 {
26

27
namespace error = mender::common::error;
28
namespace expected = mender::common::expected;
29
namespace path = mender::common::path;
30

31
static std::string StateString[] = {
32
        "ProvidePayloadFileSizes",
33
        "Download",
34
        "DownloadWithFileSizes",
35
        "ArtifactInstall",
36
        "NeedsArtifactReboot",
37
        "ArtifactReboot",
38
        "ArtifactCommit",
39
        "SupportsRollback",
40
        "ArtifactRollback",
41
        "ArtifactVerifyReboot",
42
        "ArtifactRollbackReboot",
43
        "ArtifactVerifyRollbackReboot",
44
        "ArtifactFailure",
45
        "Cleanup"};
46

47
std::string StateToString(State state) {
2,495✔
48
        static_assert(
49
                sizeof(StateString) / sizeof(*StateString) == static_cast<int>(State::LastState),
50
                "Make sure to keep State and StateString in sync!");
51
        return StateString[static_cast<int>(state)];
2,495✔
52
}
53

54
UpdateModule::UpdateModule(MenderContext &ctx, const string &payload_type) :
158✔
55
        ctx_ {ctx} {
158✔
56
        update_module_path_ = path::Join(ctx.GetConfig().paths.GetModulesPath(), payload_type);
316✔
57
        update_module_workdir_ = path::Join(
158✔
58
                ctx.GetConfig().paths.GetModulesWorkPath(), "modules", "v3", "payloads", "0000", "tree");
158✔
59
}
158✔
60

61
UpdateModule::DownloadData::DownloadData(
101✔
62
        events::EventLoop &event_loop, artifact::Payload &payload) :
101✔
63
        payload_ {payload},
64
        event_loop_ {event_loop} {
101✔
65
        buffer_.resize(MENDER_BUFSIZE);
101✔
66
}
101✔
67

68
static expected::ExpectedBool HandleProvidePayloadFileSizesOutput(
95✔
69
        const expected::ExpectedString &exp_output) {
70
        if (!exp_output) {
95✔
71
                return expected::unexpected(error::Error(exp_output.error()));
3✔
72
        }
73
        auto &processStdOut = exp_output.value();
94✔
74
        if (processStdOut == "Yes") {
94✔
75
                return true;
76
        } else if (processStdOut == "No" || processStdOut == "") {
91✔
77
                return false;
78
        }
79
        return expected::unexpected(error::Error(
1✔
80
                make_error_condition(errc::protocol_error),
2✔
81
                "Unexpected output from the process for ProvidePayloadFileSizes state: " + processStdOut));
3✔
82
}
83

84
expected::ExpectedBool UpdateModule::ProvidePayloadFileSizes() {
47✔
85
        return HandleProvidePayloadFileSizesOutput(CallStateCapture(State::ProvidePayloadFileSizes));
94✔
86
}
87

88
error::Error UpdateModule::AsyncProvidePayloadFileSizes(
48✔
89
        events::EventLoop &event_loop, ProvidePayloadFileSizesFinishedHandler handler) {
90
        return AsyncCallStateCapture(
91
                event_loop, State::ProvidePayloadFileSizes, [handler](expected::ExpectedString exp_output) {
864✔
92
                        handler(HandleProvidePayloadFileSizesOutput(exp_output));
48✔
93
                });
144✔
94
}
95

96
error::Error UpdateModule::Download(artifact::Payload &payload) {
51✔
97
        events::EventLoop event_loop;
98
        error::Error err;
51✔
99
        AsyncDownload(event_loop, payload, [&event_loop, &err](error::Error inner_err) {
51✔
100
                err = inner_err;
51✔
101
                event_loop.Stop();
51✔
102
        });
×
103
        event_loop.Run();
51✔
104
        return err;
51✔
105
}
106

107
void UpdateModule::AsyncDownload(
98✔
108
        events::EventLoop &event_loop,
109
        artifact::Payload &payload,
110
        UpdateModule::StateFinishedHandler handler) {
111
        download_ = make_unique<DownloadData>(event_loop, payload);
196✔
112

113
        download_->download_finished_handler_ = [this, handler](error::Error err) {
196✔
114
                handler(err);
196✔
115
                download_.reset();
116
        };
294✔
117

118
        download_->event_loop_.Post([this]() { StartDownloadProcess(); });
196✔
119
}
98✔
120

121
error::Error UpdateModule::DownloadWithFileSizes(artifact::Payload &payload) {
2✔
122
        events::EventLoop event_loop;
123
        error::Error err;
2✔
124
        AsyncDownloadWithFileSizes(event_loop, payload, [&event_loop, &err](error::Error inner_err) {
2✔
125
                err = inner_err;
2✔
126
                event_loop.Stop();
2✔
127
        });
×
128
        event_loop.Run();
2✔
129
        return err;
2✔
130
}
131

132
void UpdateModule::AsyncDownloadWithFileSizes(
3✔
133
        events::EventLoop &event_loop,
134
        artifact::Payload &payload,
135
        UpdateModule::StateFinishedHandler handler) {
136
        download_ = make_unique<DownloadData>(event_loop, payload);
6✔
137
        download_->downloading_with_sizes_ = true;
3✔
138

139
        download_->download_finished_handler_ = [this, handler](error::Error err) {
6✔
140
                handler(err);
6✔
141
                download_.reset();
142
        };
9✔
143

144
        download_->event_loop_.Post([this]() { StartDownloadProcess(); });
6✔
145
}
3✔
146

147
error::Error UpdateModule::ArtifactInstall() {
38✔
148
        return CallStateNoCapture(State::ArtifactInstall);
38✔
149
}
150

151
error::Error UpdateModule::AsyncArtifactInstall(
42✔
152
        events::EventLoop &event_loop, StateFinishedHandler handler) {
153
        return AsyncCallStateNoCapture(event_loop, State::ArtifactInstall, handler);
84✔
154
}
155

156
static ExpectedRebootAction HandleNeedsRebootOutput(const expected::ExpectedString &exp_output) {
109✔
157
        if (!exp_output) {
109✔
158
                return expected::unexpected(error::Error(exp_output.error()));
9✔
159
        }
160
        auto &processStdOut = exp_output.value();
106✔
161
        if (processStdOut == "Yes") {
106✔
162
                return RebootAction::Yes;
163
        } else if (processStdOut == "No" || processStdOut == "") {
43✔
164
                return RebootAction::No;
165
        } else if (processStdOut == "Automatic") {
4✔
166
                return RebootAction::Automatic;
167
        }
168
        return expected::unexpected(error::Error(
1✔
169
                make_error_condition(errc::protocol_error),
2✔
170
                "Unexpected output from the process for NeedsReboot state: " + processStdOut));
3✔
171
}
172

173
ExpectedRebootAction UpdateModule::NeedsReboot() {
37✔
174
        return HandleNeedsRebootOutput(CallStateCapture(State::NeedsReboot));
74✔
175
}
176

177
error::Error UpdateModule::AsyncNeedsReboot(
72✔
178
        events::EventLoop &event_loop, NeedsRebootFinishedHandler handler) {
179
        return AsyncCallStateCapture(
180
                event_loop, State::NeedsReboot, [handler](expected::ExpectedString exp_output) {
1,296✔
181
                        handler(HandleNeedsRebootOutput(exp_output));
72✔
182
                });
216✔
183
}
184

185
error::Error UpdateModule::ArtifactReboot() {
1✔
186
        return CallStateNoCapture(State::ArtifactReboot);
1✔
187
}
188

189
error::Error UpdateModule::AsyncArtifactReboot(
27✔
190
        events::EventLoop &event_loop, StateFinishedHandler handler) {
191
        return AsyncCallStateNoCapture(event_loop, State::ArtifactReboot, handler);
54✔
192
}
193

194
error::Error UpdateModule::ArtifactCommit() {
28✔
195
        return CallStateNoCapture(State::ArtifactCommit);
28✔
196
}
197

198
error::Error UpdateModule::AsyncArtifactCommit(
18✔
199
        events::EventLoop &event_loop, StateFinishedHandler handler) {
200
        return AsyncCallStateNoCapture(event_loop, State::ArtifactCommit, handler);
36✔
201
}
202

203
static expected::ExpectedBool HandleSupportsRollbackOutput(
94✔
204
        const expected::ExpectedString &exp_output) {
205
        if (!exp_output) {
94✔
206
                return expected::unexpected(error::Error(exp_output.error()));
6✔
207
        }
208
        auto &processStdOut = exp_output.value();
92✔
209
        if (processStdOut == "Yes") {
92✔
210
                return true;
211
        } else if (processStdOut == "No" || processStdOut == "") {
38✔
212
                return false;
213
        }
214
        return expected::unexpected(error::Error(
1✔
215
                make_error_condition(errc::protocol_error),
2✔
216
                "Unexpected output from the process for SupportsRollback state: " + processStdOut));
3✔
217
}
218

219
expected::ExpectedBool UpdateModule::SupportsRollback() {
50✔
220
        return HandleSupportsRollbackOutput(CallStateCapture(State::SupportsRollback));
100✔
221
}
222

223
error::Error UpdateModule::AsyncSupportsRollback(
44✔
224
        events::EventLoop &event_loop, SupportsRollbackFinishedHandler handler) {
225
        return AsyncCallStateCapture(
226
                event_loop, State::SupportsRollback, [handler](expected::ExpectedString exp_output) {
792✔
227
                        handler(HandleSupportsRollbackOutput(exp_output));
44✔
228
                });
132✔
229
}
230

231
error::Error UpdateModule::ArtifactRollback() {
8✔
232
        return CallStateNoCapture(State::ArtifactRollback);
8✔
233
}
234

235
error::Error UpdateModule::AsyncArtifactRollback(
40✔
236
        events::EventLoop &event_loop, StateFinishedHandler handler) {
237
        return AsyncCallStateNoCapture(event_loop, State::ArtifactRollback, handler);
80✔
238
}
239

240
error::Error UpdateModule::ArtifactVerifyReboot() {
1✔
241
        return CallStateNoCapture(State::ArtifactVerifyReboot);
1✔
242
}
243

244
error::Error UpdateModule::AsyncArtifactVerifyReboot(
29✔
245
        events::EventLoop &event_loop, StateFinishedHandler handler) {
246
        return AsyncCallStateNoCapture(event_loop, State::ArtifactVerifyReboot, handler);
58✔
247
}
248

249
error::Error UpdateModule::ArtifactRollbackReboot() {
1✔
250
        return CallStateNoCapture(State::ArtifactRollbackReboot);
1✔
251
}
252

253
error::Error UpdateModule::AsyncArtifactRollbackReboot(
56✔
254
        events::EventLoop &event_loop, StateFinishedHandler handler) {
255
        return AsyncCallStateNoCapture(event_loop, State::ArtifactRollbackReboot, handler);
112✔
256
}
257

258
error::Error UpdateModule::ArtifactVerifyRollbackReboot() {
1✔
259
        return CallStateNoCapture(State::ArtifactVerifyRollbackReboot);
1✔
260
}
261

262
error::Error UpdateModule::AsyncArtifactVerifyRollbackReboot(
59✔
263
        events::EventLoop &event_loop, StateFinishedHandler handler) {
264
        return AsyncCallStateNoCapture(event_loop, State::ArtifactVerifyRollbackReboot, handler);
118✔
265
}
266

267
error::Error UpdateModule::ArtifactFailure() {
10✔
268
        return CallStateNoCapture(State::ArtifactFailure);
10✔
269
}
270

271
error::Error UpdateModule::AsyncArtifactFailure(
54✔
272
        events::EventLoop &event_loop, StateFinishedHandler handler) {
273
        return AsyncCallStateNoCapture(event_loop, State::ArtifactFailure, handler);
108✔
274
}
275

276
error::Error UpdateModule::Cleanup() {
41✔
277
        return CallStateNoCapture(State::Cleanup);
41✔
278
}
279

280
error::Error UpdateModule::AsyncCleanup(
79✔
281
        events::EventLoop &event_loop, StateFinishedHandler handler) {
282
        return AsyncCallStateNoCapture(event_loop, State::Cleanup, handler);
158✔
283
}
284

285
string UpdateModule::GetModulePath() const {
×
286
        return update_module_path_;
×
287
}
288

289
string UpdateModule::GetModulesWorkPath() const {
×
290
        return update_module_workdir_;
831✔
291
}
292

293
error::Error UpdateModule::GetProcessError(const error::Error &err) {
4✔
294
        if (err.code == make_error_condition(errc::no_such_file_or_directory)) {
4✔
295
                return context::MakeError(context::NoSuchUpdateModuleError, err.message);
×
296
        }
297
        return err;
4✔
298
}
299

300
error::Error UpdateModule::AsyncCallStateCapture(
298✔
301
        events::EventLoop &loop, State state, function<void(expected::ExpectedString)> handler) {
302
        state_runner_.reset(new StateRunner(loop, state, GetModulePath(), GetModulesWorkPath()));
596✔
303

304
        return state_runner_->AsyncCallState(
305
                state,
306
                true,
307
                chrono::seconds(ctx_.GetConfig().module_timeout_seconds),
298✔
308
                [handler](expected::expected<optional<string>, error::Error> exp_output) {
5,066✔
309
                        if (!exp_output) {
298✔
310
                                handler(expected::unexpected(exp_output.error()));
12✔
311
                        } else {
312
                                assert(exp_output.value());
313
                                handler(exp_output.value().value());
584✔
314
                        }
315
                });
596✔
316
}
317

318
expected::ExpectedString UpdateModule::CallStateCapture(State state) {
134✔
319
        events::EventLoop loop;
320
        expected::ExpectedString ret;
321
        auto err = AsyncCallStateCapture(loop, state, [&ret, &loop](expected::ExpectedString str) {
134✔
322
                ret = str;
323
                loop.Stop();
134✔
324
        });
134✔
325

326
        if (err != error::NoError) {
134✔
327
                return expected::unexpected(err);
×
328
        }
329

330
        loop.Run();
134✔
331

332
        state_runner_.reset();
333

334
        return ret;
335
}
336

337
error::Error UpdateModule::AsyncCallStateNoCapture(
533✔
338
        events::EventLoop &loop, State state, function<void(error::Error)> handler) {
339
        state_runner_.reset(new StateRunner(loop, state, GetModulePath(), GetModulesWorkPath()));
1,066✔
340

341
        return state_runner_->AsyncCallState(
342
                state,
343
                false,
344
                chrono::seconds(ctx_.GetConfig().module_timeout_seconds),
533✔
345
                [handler](expected::expected<optional<string>, error::Error> exp_output) {
9,044✔
346
                        if (!exp_output) {
532✔
347
                                handler(exp_output.error());
114✔
348
                        } else {
349
                                assert(!exp_output.value());
350
                                handler(error::NoError);
950✔
351
                        }
352
                });
1,065✔
353
}
354

355
error::Error UpdateModule::CallStateNoCapture(State state) {
129✔
356
        events::EventLoop loop;
357
        error::Error err;
129✔
358
        err = AsyncCallStateNoCapture(loop, state, [&err, &loop](error::Error inner_err) {
129✔
359
                err = inner_err;
128✔
360
                loop.Stop();
128✔
361
        });
129✔
362

363
        if (err != error::NoError) {
129✔
364
                return err;
365
        }
366

367
        loop.Run();
128✔
368

369
        state_runner_.reset();
370

371
        return err;
372
}
373

374
} // namespace v3
375
} // namespace update_module
376
} // namespace update
377
} // 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