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

mendersoftware / mender / 1012473002

21 Sep 2023 02:17PM UTC coverage: 78.107% (-0.3%) from 78.44%
1012473002

push

gitlab-ci

lluiscampos
chore: log stdout output on errors when parsing UM yes/no commands

Signed-off-by: Lluis Campos <lluis.campos@northern.tech>

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

6468 of 8281 relevant lines covered (78.11%)

11106.28 hits per line

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

98.93
/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);
158✔
57
        update_module_workdir_ = path::Join(
158✔
58
                ctx.GetConfig().paths.GetModulesWorkPath(), "modules", "v3", "payloads", "0000", "tree");
316✔
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()));
2✔
72
        }
73
        auto &processStdOut = exp_output.value();
94✔
74
        if (processStdOut == "Yes") {
94✔
75
                return true;
3✔
76
        } else if (processStdOut == "No" || processStdOut == "") {
91✔
77
                return false;
90✔
78
        }
79
        return expected::unexpected(error::Error(
1✔
80
                make_error_condition(errc::protocol_error),
1✔
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) {
48✔
92
                        handler(HandleProvidePayloadFileSizesOutput(exp_output));
48✔
93
                });
96✔
94
}
95

96
error::Error UpdateModule::Download(artifact::Payload &payload) {
51✔
97
        events::EventLoop event_loop;
102✔
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
        });
102✔
103
        event_loop.Run();
51✔
104
        return err;
102✔
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);
98✔
112

113
        download_->download_finished_handler_ = [this, handler](error::Error err) {
98✔
114
                handler(err);
98✔
115
                download_.reset();
98✔
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;
4✔
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
        });
4✔
128
        event_loop.Run();
2✔
129
        return err;
4✔
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);
3✔
137
        download_->downloading_with_sizes_ = true;
3✔
138

139
        download_->download_finished_handler_ = [this, handler](error::Error err) {
3✔
140
                handler(err);
3✔
141
                download_.reset();
3✔
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);
42✔
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()));
6✔
159
        }
160
        auto &processStdOut = exp_output.value();
106✔
161
        if (processStdOut == "Yes") {
106✔
162
                return RebootAction::Yes;
63✔
163
        } else if (processStdOut == "No" || processStdOut == "") {
43✔
164
                return RebootAction::No;
39✔
165
        } else if (processStdOut == "Automatic") {
4✔
166
                return RebootAction::Automatic;
3✔
167
        }
168
        return expected::unexpected(error::Error(
1✔
169
                make_error_condition(errc::protocol_error),
1✔
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) {
72✔
181
                        handler(HandleNeedsRebootOutput(exp_output));
72✔
182
                });
144✔
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);
27✔
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);
18✔
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()));
4✔
207
        }
208
        auto &processStdOut = exp_output.value();
92✔
209
        if (processStdOut == "Yes") {
92✔
210
                return true;
54✔
211
        } else if (processStdOut == "No" || processStdOut == "") {
38✔
212
                return false;
37✔
213
        }
214
        return expected::unexpected(error::Error(
1✔
215
                make_error_condition(errc::protocol_error),
1✔
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) {
44✔
227
                        handler(HandleSupportsRollbackOutput(exp_output));
44✔
228
                });
88✔
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);
40✔
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);
29✔
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);
56✔
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);
59✔
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);
54✔
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);
79✔
283
}
284

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

289
string UpdateModule::GetModulesWorkPath() const {
831✔
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()));
298✔
303

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

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

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

330
        loop.Run();
134✔
331

332
        state_runner_.reset();
134✔
333

334
        return ret;
134✔
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()));
533✔
340

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

355
error::Error UpdateModule::CallStateNoCapture(State state) {
129✔
356
        events::EventLoop loop;
258✔
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
        });
258✔
362

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

367
        loop.Run();
128✔
368

369
        state_runner_.reset();
128✔
370

371
        return err;
128✔
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