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

mendersoftware / mender / 974575668

21 Aug 2023 12:04PM UTC coverage: 78.829% (-0.05%) from 78.877%
974575668

push

gitlab-ci

kacf
chore: Implement pushing of logs to the server.

Ticket: MEN-6581

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

18 of 18 new or added lines in 2 files covered. (100.0%)

5492 of 6967 relevant lines covered (78.83%)

238.75 hits per line

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

92.31
/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
        "Download",
33
        "ArtifactInstall",
34
        "NeedsArtifactReboot",
35
        "ArtifactReboot",
36
        "ArtifactCommit",
37
        "SupportsRollback",
38
        "ArtifactRollback",
39
        "ArtifactVerifyReboot",
40
        "ArtifactRollbackReboot",
41
        "ArtifactVerifyRollbackReboot",
42
        "ArtifactFailure",
43
        "Cleanup"};
44

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

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

59
void UpdateModule::Cancel() {
×
60
        download_.reset();
×
61
        state_runner_.reset();
×
62
}
×
63

64
UpdateModule::DownloadData::DownloadData(
65✔
65
        events::EventLoop &event_loop, artifact::Payload &payload) :
65✔
66
        payload_ {payload},
67
        event_loop_ {event_loop} {
65✔
68
        buffer_.resize(MENDER_BUFSIZE);
65✔
69
}
65✔
70

71
error::Error UpdateModule::Download(artifact::Payload &payload) {
41✔
72
        events::EventLoop event_loop;
82✔
73
        error::Error err;
41✔
74
        AsyncDownload(event_loop, payload, [&event_loop, &err](error::Error inner_err) {
41✔
75
                err = inner_err;
41✔
76
                event_loop.Stop();
41✔
77
        });
82✔
78
        event_loop.Run();
41✔
79
        return err;
82✔
80
}
81

82
void UpdateModule::AsyncDownload(
65✔
83
        events::EventLoop &event_loop,
84
        artifact::Payload &payload,
85
        UpdateModule::StateFinishedHandler handler) {
86
        download_ = make_unique<DownloadData>(event_loop, payload);
65✔
87

88
        download_->download_finished_handler_ = [this, handler](error::Error err) {
65✔
89
                handler(err);
65✔
90
                download_.reset();
65✔
91
        };
195✔
92

93
        download_->event_loop_.Post([this]() { StartDownloadProcess(); });
130✔
94
}
65✔
95

96
error::Error UpdateModule::ArtifactInstall() {
29✔
97
        return CallStateNoCapture(State::ArtifactInstall);
29✔
98
}
99

100
error::Error UpdateModule::AsyncArtifactInstall(
21✔
101
        events::EventLoop &event_loop, StateFinishedHandler handler) {
102
        return AsyncCallStateNoCapture(event_loop, State::ArtifactInstall, handler);
21✔
103
}
104

105
static ExpectedRebootAction HandleNeedsRebootOutput(const expected::ExpectedString &exp_output) {
65✔
106
        if (!exp_output) {
65✔
107
                return expected::unexpected(error::Error(exp_output.error()));
6✔
108
        }
109
        auto &processStdOut = exp_output.value();
62✔
110
        if (processStdOut == "Yes") {
62✔
111
                return RebootAction::Yes;
31✔
112
        } else if (processStdOut == "No" || processStdOut == "") {
31✔
113
                return RebootAction::No;
27✔
114
        } else if (processStdOut == "Automatic") {
4✔
115
                return RebootAction::Automatic;
3✔
116
        }
117
        return expected::unexpected(error::Error(
1✔
118
                make_error_condition(errc::protocol_error),
1✔
119
                "Unexpected output from the process for NeedsReboot state"));
3✔
120
}
121

122
ExpectedRebootAction UpdateModule::NeedsReboot() {
29✔
123
        return HandleNeedsRebootOutput(CallStateCapture(State::NeedsReboot));
58✔
124
}
125

126
error::Error UpdateModule::AsyncNeedsReboot(
36✔
127
        events::EventLoop &event_loop, NeedsRebootFinishedHandler handler) {
128
        return AsyncCallStateCapture(
129
                event_loop, State::NeedsReboot, [handler](expected::ExpectedString exp_output) {
36✔
130
                        handler(HandleNeedsRebootOutput(exp_output));
36✔
131
                });
72✔
132
}
133

134
error::Error UpdateModule::ArtifactReboot() {
1✔
135
        return CallStateNoCapture(State::ArtifactReboot);
1✔
136
}
137

138
error::Error UpdateModule::AsyncArtifactReboot(
13✔
139
        events::EventLoop &event_loop, StateFinishedHandler handler) {
140
        return AsyncCallStateNoCapture(event_loop, State::ArtifactReboot, handler);
13✔
141
}
142

143
error::Error UpdateModule::ArtifactCommit() {
24✔
144
        return CallStateNoCapture(State::ArtifactCommit);
24✔
145
}
146

147
error::Error UpdateModule::AsyncArtifactCommit(
8✔
148
        events::EventLoop &event_loop, StateFinishedHandler handler) {
149
        return AsyncCallStateNoCapture(event_loop, State::ArtifactCommit, handler);
8✔
150
}
151

152
static expected::ExpectedBool HandleSupportsRollbackOutput(
59✔
153
        const expected::ExpectedString &exp_output) {
154
        if (!exp_output) {
59✔
155
                return expected::unexpected(error::Error(exp_output.error()));
4✔
156
        }
157
        auto &processStdOut = exp_output.value();
57✔
158
        if (processStdOut == "Yes") {
57✔
159
                return true;
35✔
160
        } else if (processStdOut == "No" || processStdOut == "") {
22✔
161
                return false;
21✔
162
        }
163
        return expected::unexpected(error::Error(
1✔
164
                make_error_condition(errc::protocol_error),
1✔
165
                "Unexpected output from the process for SupportsRollback state"));
3✔
166
}
167

168
expected::ExpectedBool UpdateModule::SupportsRollback() {
36✔
169
        return HandleSupportsRollbackOutput(CallStateCapture(State::SupportsRollback));
72✔
170
}
171

172
error::Error UpdateModule::AsyncSupportsRollback(
23✔
173
        events::EventLoop &event_loop, SupportsRollbackFinishedHandler handler) {
174
        return AsyncCallStateCapture(
175
                event_loop, State::SupportsRollback, [handler](expected::ExpectedString exp_output) {
23✔
176
                        handler(HandleSupportsRollbackOutput(exp_output));
23✔
177
                });
46✔
178
}
179

180
error::Error UpdateModule::ArtifactRollback() {
7✔
181
        return CallStateNoCapture(State::ArtifactRollback);
7✔
182
}
183

184
error::Error UpdateModule::AsyncArtifactRollback(
21✔
185
        events::EventLoop &event_loop, StateFinishedHandler handler) {
186
        return AsyncCallStateNoCapture(event_loop, State::ArtifactRollback, handler);
21✔
187
}
188

189
error::Error UpdateModule::ArtifactVerifyReboot() {
1✔
190
        return CallStateNoCapture(State::ArtifactVerifyReboot);
1✔
191
}
192

193
error::Error UpdateModule::AsyncArtifactVerifyReboot(
14✔
194
        events::EventLoop &event_loop, StateFinishedHandler handler) {
195
        return AsyncCallStateNoCapture(event_loop, State::ArtifactVerifyReboot, handler);
14✔
196
}
197

198
error::Error UpdateModule::ArtifactRollbackReboot() {
1✔
199
        return CallStateNoCapture(State::ArtifactRollbackReboot);
1✔
200
}
201

202
error::Error UpdateModule::AsyncArtifactRollbackReboot(
29✔
203
        events::EventLoop &event_loop, StateFinishedHandler handler) {
204
        return AsyncCallStateNoCapture(event_loop, State::ArtifactRollbackReboot, handler);
29✔
205
}
206

207
error::Error UpdateModule::ArtifactVerifyRollbackReboot() {
1✔
208
        return CallStateNoCapture(State::ArtifactVerifyRollbackReboot);
1✔
209
}
210

211
error::Error UpdateModule::AsyncArtifactVerifyRollbackReboot(
30✔
212
        events::EventLoop &event_loop, StateFinishedHandler handler) {
213
        return AsyncCallStateNoCapture(event_loop, State::ArtifactVerifyRollbackReboot, handler);
30✔
214
}
215

216
error::Error UpdateModule::ArtifactFailure() {
5✔
217
        return CallStateNoCapture(State::ArtifactFailure);
5✔
218
}
219

220
error::Error UpdateModule::AsyncArtifactFailure(
27✔
221
        events::EventLoop &event_loop, StateFinishedHandler handler) {
222
        return AsyncCallStateNoCapture(event_loop, State::ArtifactFailure, handler);
27✔
223
}
224

225
error::Error UpdateModule::Cleanup() {
28✔
226
        return CallStateNoCapture(State::Cleanup);
28✔
227
}
228

229
error::Error UpdateModule::AsyncCleanup(
38✔
230
        events::EventLoop &event_loop, StateFinishedHandler handler) {
231
        return AsyncCallStateNoCapture(event_loop, State::Cleanup, handler);
38✔
232
}
233

234
string UpdateModule::GetModulePath() const {
422✔
235
        return update_module_path_;
422✔
236
}
237

238
string UpdateModule::GetModulesWorkPath() const {
422✔
239
        return update_module_workdir_;
422✔
240
}
241

242
error::Error UpdateModule::GetProcessError(const error::Error &err) {
4✔
243
        if (err.code == make_error_condition(errc::no_such_file_or_directory)) {
4✔
244
                return context::MakeError(context::NoSuchUpdateModuleError, err.message);
×
245
        }
246
        return err;
4✔
247
}
248

249
error::Error UpdateModule::AsyncCallStateCapture(
124✔
250
        events::EventLoop &loop, State state, function<void(expected::ExpectedString)> handler) {
251
        state_runner_.reset(new StateRunner(loop, state, GetModulePath(), GetModulesWorkPath()));
124✔
252

253
        return state_runner_->AsyncCallState(
254
                state,
255
                true,
256
                chrono::seconds(ctx_.GetConfig().module_timeout_seconds),
124✔
257
                [handler](expected::expected<optional::optional<string>, error::Error> exp_output) {
124✔
258
                        if (!exp_output) {
124✔
259
                                handler(expected::unexpected(exp_output.error()));
5✔
260
                        } else {
261
                                assert(exp_output.value());
119✔
262
                                handler(exp_output.value().value());
119✔
263
                        }
264
                });
372✔
265
}
266

267
expected::ExpectedString UpdateModule::CallStateCapture(State state) {
65✔
268
        events::EventLoop loop;
130✔
269
        expected::ExpectedString ret;
130✔
270
        auto err = AsyncCallStateCapture(loop, state, [&ret, &loop](expected::ExpectedString str) {
130✔
271
                ret = str;
65✔
272
                loop.Stop();
65✔
273
        });
130✔
274

275
        if (err != error::NoError) {
65✔
276
                return expected::unexpected(err);
×
277
        }
278

279
        loop.Run();
65✔
280

281
        state_runner_.reset();
65✔
282

283
        return ret;
65✔
284
}
285

286
error::Error UpdateModule::AsyncCallStateNoCapture(
298✔
287
        events::EventLoop &loop, State state, function<void(error::Error)> handler) {
288
        state_runner_.reset(new StateRunner(loop, state, GetModulePath(), GetModulesWorkPath()));
298✔
289

290
        return state_runner_->AsyncCallState(
291
                state,
292
                false,
293
                chrono::seconds(ctx_.GetConfig().module_timeout_seconds),
298✔
294
                [handler](expected::expected<optional::optional<string>, error::Error> exp_output) {
297✔
295
                        if (!exp_output) {
297✔
296
                                handler(exp_output.error());
41✔
297
                        } else {
298
                                assert(!exp_output.value());
256✔
299
                                handler(error::NoError);
256✔
300
                        }
301
                });
893✔
302
}
303

304
error::Error UpdateModule::CallStateNoCapture(State state) {
97✔
305
        events::EventLoop loop;
194✔
306
        error::Error err;
97✔
307
        err = AsyncCallStateNoCapture(loop, state, [&err, &loop](error::Error inner_err) {
97✔
308
                err = inner_err;
96✔
309
                loop.Stop();
96✔
310
        });
194✔
311

312
        if (err != error::NoError) {
97✔
313
                return err;
1✔
314
        }
315

316
        loop.Run();
96✔
317

318
        state_runner_.reset();
96✔
319

320
        return err;
96✔
321
}
322

323
} // namespace v3
324
} // namespace update_module
325
} // namespace update
326
} // 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