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

mendersoftware / mender / 1035858476

13 Oct 2023 11:49AM UTC coverage: 79.922% (+0.001%) from 79.921%
1035858476

push

gitlab-ci

lluiscampos
refac: Refactor the whole `common::cli` inside `common::conf`

The first had some problems, like the interdependency between
`common::cli` and `common:conf` and the horrible code duplication
between `mender::upate::cli` and `mender::auth::cli`.

From a different point of view, the parsing of the (common) CLI options
is done in `common::conf` for both tools, which suggest that there is
reason to have everything in `common::conf` in the first place.

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

24 of 24 new or added lines in 4 files covered. (100.0%)

6592 of 8248 relevant lines covered (79.92%)

9745.91 hits per line

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

53.03
/mender-auth/cli/cli.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-auth/cli/cli.hpp>
16

17
#include <string>
18

19
#include <common/conf.hpp>
20
#include <common/expected.hpp>
21
#include <common/io.hpp>
22
#include <common/setup.hpp>
23

24
#include <mender-auth/cli/actions.hpp>
25
#include <mender-auth/context.hpp>
26
#include <mender-auth/ipc/server.hpp>
27

28
namespace mender {
29
namespace auth {
30
namespace cli {
31

32
using namespace std;
33

34
namespace conf = mender::common::conf;
35
namespace expected = mender::common::expected;
36
namespace io = mender::common::io;
37
namespace setup = mender::common::setup;
38

39
namespace context = mender::auth::context;
40
namespace ipc = mender::auth::ipc;
41

42
const vector<conf::CliOption> opts_bootstrap_daemon {
43
        conf::CliOption {
44
                .long_option = "forcebootstrap",
45
                .short_option = "F",
46
                .description = "Force bootstrap",
47
        },
48
        conf::CliOption {
49
                .long_option = "passphrase-file",
50
                .description =
51
                        "Passphrase file for decrypting an encrypted private key. '-' loads passphrase from stdin",
52
                .default_value = "''",
53
        },
54
};
55

56
const conf::CliCommand cmd_bootstrap {
57
        .name = "bootstrap",
58
        .description = "Perform bootstrap and exit",
59
        .options = opts_bootstrap_daemon,
60
};
61

62
const conf::CliCommand cmd_daemon {
63
        .name = "daemon",
64
        .description = "Start the client as a background service",
65
        .options = opts_bootstrap_daemon,
66
};
67

68
const conf::CliApp cli_mender_auth = {
69
        .name = "mender-auth",
70
        .short_description = "manage and start Mender Auth",
71
        .long_description =
72
                R"(mender-auth integrates both the mender-auth daemon and commands for manually
73
   performing tasks performed by the daemon (see list of COMMANDS below).)",
74
        .commands =
75
                {
76
                        cmd_bootstrap,
77
                        cmd_daemon,
78
                },
79
};
80

81
static expected::ExpectedString GetPassphraseFromFile(const string &filepath) {
×
82
        string passphrase = "";
×
83
        if (filepath == "") {
×
84
                return passphrase;
×
85
        }
86

87
        auto ex_ifs = io::OpenIfstream(filepath == "-" ? io::paths::Stdin : filepath);
×
88
        if (!ex_ifs) {
×
89
                return expected::unexpected(ex_ifs.error());
×
90
        }
91
        auto &ifs = ex_ifs.value();
×
92

93
        errno = 0;
×
94
        getline(ifs, passphrase);
×
95
        if (ifs.bad()) {
×
96
                int io_errno = errno;
×
97
                error::Error err {
98
                        generic_category().default_error_condition(io_errno),
×
99
                        "Failed to read passphrase from '" + filepath + "'"};
×
100
                return expected::unexpected(err);
×
101
        }
102

103
        return passphrase;
×
104
}
105

106
static ExpectedActionPtr ParseAuthArguments(
6✔
107
        const conf::MenderConfig &config,
108
        vector<string>::const_iterator start,
109
        vector<string>::const_iterator end) {
110
        if (start == end) {
6✔
111
                return expected::unexpected(conf::MakeError(conf::InvalidOptionsError, "Need an action"));
3✔
112
        }
113

114
        conf::CmdlineOptionsIterator opts_iter(
115
                start + 1,
116
                end,
117
                {},
118
                {
119
                        "--help",
120
                        "-h",
121
                });
35✔
122
        auto ex_opt_val = opts_iter.Next();
5✔
123

124
        bool help_arg = false;
125
        while (ex_opt_val && ((ex_opt_val.value().option != "") || (ex_opt_val.value().value != ""))) {
5✔
126
                auto opt_val = ex_opt_val.value();
×
127
                if ((opt_val.option == "--help") || (opt_val.option == "-h")) {
×
128
                        help_arg = true;
129
                        break;
×
130
                }
131
                ex_opt_val = opts_iter.Next();
×
132
        }
133

134
        if (help_arg) {
135
                conf::PrintCliCommandHelp(cli_mender_auth, start[0]);
×
136
                return expected::unexpected(error::MakeError(error::ExitWithSuccessError, ""));
×
137
        }
138

139
        string passphrase = "";
5✔
140
        bool forcebootstrap = false;
141
        if (start[0] == "bootstrap" || start[0] == "daemon") {
5✔
142
                conf::CmdlineOptionsIterator opts_iter(
143
                        start + 1, end, {"--passphrase-file"}, {"--forcebootstrap", "-F"});
40✔
144
                auto ex_opt_val = opts_iter.Next();
4✔
145

146
                while (ex_opt_val
147
                           && ((ex_opt_val.value().option != "") || (ex_opt_val.value().value != ""))) {
5✔
148
                        auto opt_val = ex_opt_val.value();
1✔
149
                        if ((opt_val.option == "--passphrase-file")) {
1✔
150
                                auto ex_passphrase = GetPassphraseFromFile(opt_val.value);
×
151
                                if (!ex_passphrase) {
×
152
                                        return expected::unexpected(ex_passphrase.error());
×
153
                                }
154
                                passphrase = ex_passphrase.value();
×
155
                        } else if ((opt_val.option == "--forcebootstrap" || opt_val.option == "-F")) {
1✔
156
                                forcebootstrap = true;
157
                        }
158
                        ex_opt_val = opts_iter.Next();
2✔
159
                }
160
                if (!ex_opt_val) {
4✔
161
                        return expected::unexpected(ex_opt_val.error());
×
162
                }
163
        }
164

165
        if (start[0] == "bootstrap") {
5✔
166
                return BootstrapAction::Create(config, passphrase, forcebootstrap);
4✔
167
        } else if (start[0] == "daemon") {
1✔
168
                return DaemonAction::Create(config, passphrase, forcebootstrap);
×
169
        } else {
170
                return expected::unexpected(
1✔
171
                        conf::MakeError(conf::InvalidOptionsError, "No such action: " + start[0]));
3✔
172
        }
173
}
174

175
error::Error DoMain(
6✔
176
        const vector<string> &args, function<void(context::MenderContext &ctx)> test_hook) {
177
        setup::GlobalSetup();
6✔
178

179
        conf::MenderConfig config;
12✔
180
        auto arg_pos = config.ProcessCmdlineArgs(args.begin(), args.end(), cli_mender_auth);
6✔
181
        if (!arg_pos) {
6✔
182
                if (arg_pos.error().code != error::MakeError(error::ExitWithSuccessError, "").code) {
×
183
                        conf::PrintCliHelp(cli_mender_auth);
×
184
                }
185
                return arg_pos.error();
×
186
        }
187

188
        auto action = ParseAuthArguments(config, args.begin() + arg_pos.value(), args.end());
6✔
189
        if (!action) {
6✔
190
                if (action.error().code != error::MakeError(error::ExitWithSuccessError, "").code) {
2✔
191
                        if (args.size() > 0) {
2✔
192
                                conf::PrintCliCommandHelp(cli_mender_auth, args[0]);
1✔
193
                        } else {
194
                                conf::PrintCliHelp(cli_mender_auth);
1✔
195
                        }
196
                }
197
                return action.error();
2✔
198
        }
199

200
        context::MenderContext context(config);
201

202
        test_hook(context);
4✔
203

204
        return action.value()->Execute(context);
4✔
205
}
206

207
} // namespace cli
208
} // namespace auth
209
} // 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