1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3
4 #include "webserver_cli.hpp"
5
6 #include "boost_formatters.hpp"
7 #include "logging.hpp"
8 #include "webserver_run.hpp"
9
10 #include <CLI/CLI.hpp>
11 #include <boost/asio/io_context.hpp>
12 #include <sdbusplus/asio/connection.hpp>
13
14 #include <algorithm>
15 #include <array>
16 #include <cctype>
17 #include <memory>
18 #include <string>
19
20 // Override default log option:
cliLogLevel(const std::string & logLevel)21 static void cliLogLevel(const std::string& logLevel)
22 {
23 crow::getBmcwebCurrentLoggingLevel() = crow::getLogLevelFromName(logLevel);
24 }
25
26 static constexpr std::array<std::string, 7> levels{
27 "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"};
28
29 // Check if debug level is valid
validateLogLevel(std::string & input)30 static std::string validateLogLevel(std::string& input)
31 {
32 std::ranges::transform(input, input.begin(), ::toupper);
33 const std::string* iter = std::ranges::find(levels, input);
34 if (iter == levels.end())
35 {
36 return {"Invalid log level"};
37 }
38 return {};
39 }
40
helpMsg()41 static std::string helpMsg()
42 {
43 std::string help = "\nLog levels to choose from:\n";
44 for (const std::string& prompt : levels)
45 {
46 std::string level = prompt;
47 std::ranges::transform(level, level.begin(), ::tolower);
48 help.append(level + "\n");
49 }
50 return help;
51 }
52
setLogLevel(std::string & loglevel)53 static int setLogLevel(std::string& loglevel)
54 {
55 // Define sdbus interfaces:
56 std::string service = "xyz.openbmc_project.bmcweb";
57 std::string path = "/xyz/openbmc_project/bmcweb";
58 std::string iface = "xyz.openbmc_project.bmcweb";
59 std::string method = "SetLogLevel";
60
61 std::ranges::transform(loglevel, loglevel.begin(), ::toupper);
62 // Set up dbus connection:
63 boost::asio::io_context io;
64 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
65
66 // Attempt to async_call to set logging level
67 conn->async_method_call(
68 [&io, loglevel](boost::system::error_code& ec) mutable {
69 if (ec)
70 {
71 BMCWEB_LOG_ERROR("SetLogLevel returned error with {}", ec);
72 }
73 else
74 {
75 BMCWEB_LOG_INFO("logging level changed to: {}", loglevel);
76 }
77 io.stop();
78 },
79 service, path, iface, method, loglevel);
80
81 io.run();
82
83 return 0;
84 }
85
runCLI(int argc,char ** argv)86 int runCLI(int argc, char** argv) noexcept(false)
87 {
88 CLI::App app("BMCWeb CLI");
89
90 const CLI::Validator levelValidator =
91 CLI::Validator(validateLogLevel, "valid level");
92
93 CLI::App* loglevelsub =
94 app.add_subcommand("loglevel", "Set bmcweb log level");
95
96 std::string loglevel;
97 loglevelsub->add_option("level", loglevel, helpMsg())
98 ->required()
99 ->check(levelValidator);
100
101 CLI::App* daemon = app.add_subcommand("daemon", "Run webserver");
102
103 CLI11_PARSE(app, argc, argv)
104
105 if (loglevelsub->parsed())
106 {
107 cliLogLevel("INFO");
108 return setLogLevel(loglevel);
109 }
110 if (daemon->parsed())
111 {
112 return runWebserver();
113 }
114 runWebserver();
115
116 return 0;
117 }
118