xref: /openbmc/bmcweb/src/webserver_cli.cpp (revision 55385c705c0efc58b88ff885b78ee65acb455b85)
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::transform(input.begin(), input.end(), 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::transform(level.begin(), level.end(), 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::transform(loglevel.begin(), loglevel.end(), loglevel.begin(),
62                    ::toupper);
63     // Set up dbus connection:
64     boost::asio::io_context io;
65     auto conn = std::make_shared<sdbusplus::asio::connection>(io);
66 
67     // Attempt to async_call to set logging level
68     conn->async_method_call(
69         [&io, loglevel](boost::system::error_code& ec) mutable {
70             if (ec)
71             {
72                 BMCWEB_LOG_ERROR("SetLogLevel returned error with {}", ec);
73             }
74             else
75             {
76                 BMCWEB_LOG_INFO("logging level changed to: {}", loglevel);
77             }
78             io.stop();
79         },
80         service, path, iface, method, loglevel);
81 
82     io.run();
83 
84     return 0;
85 }
86 
runCLI(int argc,char ** argv)87 int runCLI(int argc, char** argv) noexcept(false)
88 {
89     CLI::App app("BMCWeb CLI");
90 
91     cliLogLevel("INFO");
92 
93     const CLI::Validator levelValidator =
94         CLI::Validator(validateLogLevel, "valid level");
95 
96     CLI::App* loglevelsub =
97         app.add_subcommand("loglevel", "Set bmcweb log level");
98 
99     std::string loglevel;
100     loglevelsub->add_option("level", loglevel, helpMsg())
101         ->required()
102         ->check(levelValidator);
103 
104     CLI::App* daemon = app.add_subcommand("daemon", "Run webserver");
105 
106     CLI11_PARSE(app, argc, argv)
107 
108     if (loglevelsub->parsed())
109     {
110         return setLogLevel(loglevel);
111     }
112     if (daemon->parsed())
113     {
114         return runWebserver();
115     }
116     runWebserver();
117 
118     return 0;
119 }
120