From c49661925b0c59a4355aca6813a85d749c21e764 Mon Sep 17 00:00:00 2001 From: Deepak Kodihalli Date: Thu, 23 Aug 2018 02:19:58 -0500 Subject: Add application to configure rsyslog The application implements the xyz.openbmc_project.Network.Client D-Bus interface to set a remote rsyslog server's address and port in the rsyslog config file. This lets us configure rsyslog to be able to stream out logs. TODO: Exception handling and validation will be handled in subsequent commits. Change-Id: I8917daab3f0de1806d2f1aafe99cb3a872f19184 Signed-off-by: Deepak Kodihalli --- Makefile.am | 2 +- README.md | 53 +++++++++++++++++++++++ configure.ac | 30 ++++++++++++- log_manager.cpp | 4 -- phosphor-rsyslog-config/Makefile.am | 20 +++++++++ phosphor-rsyslog-config/main.cpp | 23 ++++++++++ phosphor-rsyslog-config/server-conf.cpp | 42 ++++++++++++++++++ phosphor-rsyslog-config/server-conf.hpp | 76 +++++++++++++++++++++++++++++++++ phosphor-rsyslog-config/utils.hpp | 26 +++++++++++ 9 files changed, 270 insertions(+), 6 deletions(-) create mode 100644 phosphor-rsyslog-config/Makefile.am create mode 100644 phosphor-rsyslog-config/main.cpp create mode 100644 phosphor-rsyslog-config/server-conf.cpp create mode 100644 phosphor-rsyslog-config/server-conf.hpp create mode 100644 phosphor-rsyslog-config/utils.hpp diff --git a/Makefile.am b/Makefile.am index 4035edc..1b13af7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -108,7 +108,7 @@ callouts-gen.hpp: $(REQ_FILES_TO_GEN) pkgconfiglibdir = ${libdir}/pkgconfig pkgconfiglib_DATA = phosphor-logging.pc -SUBDIRS = test +SUBDIRS = test phosphor-rsyslog-config endif # Export elog-gen parser and mako script elogdir = ${datadir}/phosphor-logging/elog diff --git a/README.md b/README.md index 1d5fe13..e0ea54a 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,59 @@ To build this package, do the following steps: To clean the repository run `./bootstrap.sh clean`. ``` +## Remote Logging via Rsyslog +The BMC has the ability to stream out local logs (that go to the systemd journal) +via rsyslog (https://www.rsyslog.com/). + +The BMC will send everything. Any kind of filtering and appropriate storage +will have to be managed on the rsyslog server. Various examples are available +on the internet. Here are few pointers : +https://www.rsyslog.com/storing-and-forwarding-remote-messages/ +https://www.rsyslog.com/doc/rsyslog%255Fconf%255Ffilter.html +https://www.thegeekdiary.com/understanding-rsyslog-filter-options/ + +#### Configuring rsyslog server for remote logging +The BMC is an rsyslog client. To stream out logs, it needs to talk to an rsyslog +server, to which there's connectivity over a network. REST API can be used to +set the remote server's IP address and port number. + +The following presumes a user has logged on to the BMC (see +https://github.com/openbmc/docs/blob/master/rest-api.md). + +Set the IP: +``` +curl -b cjar -k -H "Content-Type: application/json" -X PUT \ + -d '{"data": }' \ + https:///xyz/openbmc_project/logging/config/remote/attr/Address +``` + +Set the port: +``` +curl -b cjar -k -H "Content-Type: application/json" -X PUT \ + -d '{"data": }' \ + https:///xyz/openbmc_project/logging/config/remote/attr/Port +``` + +#### Querying the current configuration +``` +curl -b cjar -k \ + https:///xyz/openbmc_project/logging/config/remote +``` + +#### Setting the hostname +Rsyslog can store logs separately for each host. For this reason, it's useful to +provide a unique hostname to each managed BMC. Here's how that can be done via a +REST API : +``` +curl -b cjar -k -H "Content-Type: application/json" -X PUT \ + -d '{"data": "myHostName"}' \ + https:////xyz/openbmc_project/network/config/attr/HostName +``` + +#### Changing the rsyslog server +When switching to a new server from an existing one (i.e the address, or port, +or both change), it is recommended to disable the existing configuration first. + ## Adding application specific error YAML * This document captures steps for adding application specific error YAML files and generating local elog-errors.hpp header file for application use. diff --git a/configure.ac b/configure.ac index 3ae2407..ce9b8bb 100644 --- a/configure.ac +++ b/configure.ac @@ -118,7 +118,35 @@ AC_ARG_VAR(CLASS_VERSION, [Class version to register with Cereal]) AS_IF([test "x$CLASS_VERSION" == "x"], [CLASS_VERSION=2]) AC_DEFINE_UNQUOTED([CLASS_VERSION], [$CLASS_VERSION], [Class version to register with Cereal]) +AC_ARG_VAR(RSYSLOG_SERVER_CONFIG_FILE, \ + [Path of config file containing server address]) +AS_IF([test "x$RSYSLOG_SERVER_CONFIG_FILE" == "x"], \ + [RSYSLOG_SERVER_CONFIG_FILE="/etc/rsyslog.d/server.conf"]) +AC_DEFINE_UNQUOTED([RSYSLOG_SERVER_CONFIG_FILE], \ + ["$RSYSLOG_SERVER_CONFIG_FILE"], \ + [Path of config file containing server address]) + +AC_ARG_VAR(BUSNAME_SYSLOG_CONFIG, \ + [D-Bus busname of syslog config service]) +AS_IF([test "x$BUSNAME_SYSLOG_CONFIG" == "x"], \ + [BUSNAME_SYSLOG_CONFIG="xyz.openbmc_project.Syslog.Config"]) +AC_DEFINE_UNQUOTED([BUSNAME_SYSLOG_CONFIG], \ + ["$BUSNAME_SYSLOG_CONFIG"], \ + [D-Bus busname of syslog config service]) + +AC_ARG_VAR(BUSPATH_REMOTE_LOGGING_CONFIG, \ + [D-Bus path of remote logging config object]) +AS_IF([test "x$BUSPATH_REMOTE_LOGGING_CONFIG" == "x"], \ + [BUSPATH_REMOTE_LOGGING_CONFIG="/xyz/openbmc_project/logging/config/remote"]) +AC_DEFINE_UNQUOTED([BUSPATH_REMOTE_LOGGING_CONFIG], \ + ["$BUSPATH_REMOTE_LOGGING_CONFIG"], \ + [D-Bus path of remote logging config object]) + +AC_DEFINE(SYSTEMD_BUSNAME, "org.freedesktop.systemd1", [systemd busname.]) +AC_DEFINE(SYSTEMD_PATH, "/org/freedesktop/systemd1", [systemd path.]) +AC_DEFINE(SYSTEMD_INTERFACE, "org.freedesktop.systemd1.Manager", [systemd interface.]) + AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_FILES([Makefile test/Makefile]) +AC_CONFIG_FILES([Makefile test/Makefile phosphor-rsyslog-config/Makefile]) AC_CONFIG_FILES([phosphor-logging.pc]) AC_OUTPUT diff --git a/log_manager.cpp b/log_manager.cpp index cbbf9a8..ad1c5d1 100644 --- a/log_manager.cpp +++ b/log_manager.cpp @@ -371,10 +371,6 @@ void Manager::journalSync() { syncRequested = true; - constexpr auto SYSTEMD_BUSNAME = "org.freedesktop.systemd1"; - constexpr auto SYSTEMD_PATH = "/org/freedesktop/systemd1"; - constexpr auto SYSTEMD_INTERFACE = - "org.freedesktop.systemd1.Manager"; constexpr auto JOURNAL_UNIT = "systemd-journald.service"; auto signal = SIGRTMIN + 1; diff --git a/phosphor-rsyslog-config/Makefile.am b/phosphor-rsyslog-config/Makefile.am new file mode 100644 index 0000000..f695946 --- /dev/null +++ b/phosphor-rsyslog-config/Makefile.am @@ -0,0 +1,20 @@ +noinst_HEADERS = \ + utils.hpp \ + server-conf.hpp + +sbin_PROGRAMS = phosphor-rsyslog-conf + +phosphor_rsyslog_conf_SOURCES = \ + main.cpp \ + server-conf.cpp + +phosphor_rsyslog_conf_LDFLAGS = \ + $(SDBUSPLUS_LIBS) \ + $(PHOSPHOR_LOGGING_LIBS) \ + $(PHOSPHOR_DBUS_INTERFACES_LIBS) + +phosphor_rsyslog_conf_CXXFLAGS = \ + $(SDBUSPLUS_CFLAGS) \ + $(PHOSPHOR_LOGGING_CFLAGS) \ + $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ + -flto diff --git a/phosphor-rsyslog-config/main.cpp b/phosphor-rsyslog-config/main.cpp new file mode 100644 index 0000000..3e4d928 --- /dev/null +++ b/phosphor-rsyslog-config/main.cpp @@ -0,0 +1,23 @@ +#include "config.h" +#include "server-conf.hpp" +#include + +int main(int argc, char *argv[]) +{ + auto bus = sdbusplus::bus::new_default(); + + phosphor::rsyslog_config::Server + serverConf(bus, + BUSPATH_REMOTE_LOGGING_CONFIG, + RSYSLOG_SERVER_CONFIG_FILE); + + bus.request_name(BUSNAME_SYSLOG_CONFIG); + + while(true) + { + bus.process_discard(); + bus.wait(); + } + + return 0; +} diff --git a/phosphor-rsyslog-config/server-conf.cpp b/phosphor-rsyslog-config/server-conf.cpp new file mode 100644 index 0000000..16c792d --- /dev/null +++ b/phosphor-rsyslog-config/server-conf.cpp @@ -0,0 +1,42 @@ +#include "server-conf.hpp" +#include "utils.hpp" +#include + +namespace phosphor +{ +namespace rsyslog_config +{ + +namespace utils = phosphor::rsyslog_utils; + +std::string Server::address(std::string value) +{ + writeConfig(value, port(), configFilePath.c_str()); + auto result = NetworkClient::address(value); + return result; +} + +uint16_t Server::port(uint16_t value) +{ + writeConfig(address(), value, configFilePath.c_str()); + auto result = NetworkClient::port(value); + return result; +} + +void Server::writeConfig( + const std::string& serverAddress, + uint16_t serverPort, + const char* filePath) +{ + if (serverPort && !serverAddress.empty()) + { + std::fstream stream(filePath, std::fstream::out); + // write '*.* @@remote-host:port' + stream << "*.* @@" << serverAddress << ":" << serverPort; + + utils::restart(); + } +} + +} // namespace rsyslog_config +} // namespace phosphor diff --git a/phosphor-rsyslog-config/server-conf.hpp b/phosphor-rsyslog-config/server-conf.hpp new file mode 100644 index 0000000..cb8882b --- /dev/null +++ b/phosphor-rsyslog-config/server-conf.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include +#include "xyz/openbmc_project/Network/Client/server.hpp" + +namespace phosphor +{ +namespace rsyslog_config +{ + +using NetworkClient = sdbusplus::xyz::openbmc_project::Network::server::Client; +using Iface = sdbusplus::server::object::object; + +/** @class Server + * @brief Configuration for rsyslog server + * @details A concrete implementation of the + * xyz.openbmc_project.Network.Client API, in order to + * provide remote rsyslog server's address and port. + */ +class Server : public Iface +{ + public: + Server() = delete; + Server(const Server&) = delete; + Server& operator=(const Server&) = delete; + Server(Server&&) = delete; + Server& operator=(Server&&) = delete; + virtual ~Server() = default; + + /** @brief Constructor to put object onto bus at a dbus path. + * @param[in] bus - Bus to attach to. + * @param[in] path - Path to attach at. + * @param[in] filePath - rsyslog remote logging config file + */ + Server(sdbusplus::bus::bus& bus, + const std::string& path, + const char* filePath) : + Iface(bus, path.c_str()), + configFilePath(filePath) + { + } + + using NetworkClient::address; + using NetworkClient::port; + + /** @brief Override that updates rsyslog config file as well + * @param[in] value - remote server address + * @returns value of changed address + */ + virtual std::string address(std::string value) override; + + /** @brief Override that updates rsyslog config file as well + * @param[in] value - remote server port + * @returns value of changed port + */ + virtual uint16_t port(uint16_t value) override; + + private: + /** @brief Update remote server address and port in + * rsyslog config file. + * @param[in] serverAddress - remote server address + * @param[in] serverPort - remote server port + * @param[in] filePath - rsyslog config file path + */ + void writeConfig( + const std::string& serverAddress, + uint16_t serverPort, + const char* filePath); + + std::string configFilePath{}; +}; + +} // namespace rsyslog_config +} // namespace phosphor diff --git a/phosphor-rsyslog-config/utils.hpp b/phosphor-rsyslog-config/utils.hpp new file mode 100644 index 0000000..ea7984d --- /dev/null +++ b/phosphor-rsyslog-config/utils.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "config.h" +#include + +namespace phosphor +{ +namespace rsyslog_utils +{ + +/** @brief Restart rsyslog's systemd unit + */ +void restart() +{ + auto bus = sdbusplus::bus::new_default(); + auto method = bus.new_method_call( + SYSTEMD_BUSNAME, + SYSTEMD_PATH, + SYSTEMD_INTERFACE, + "RestartUnit"); + method.append("rsyslog.service", "replace"); + bus.call_noreply(method); +} + +} // namespace rsyslog_utils +} // namespace phosphor -- cgit v1.2.1