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 <dkodihal@in.ibm.com>
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 <sdbusplus/bus.hpp>
+
+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 <fstream>
+
+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 <sdbusplus/bus.hpp>
+#include <sdbusplus/server/object.hpp>
+#include <string>
+#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<NetworkClient>;
+
+/** @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 <sdbusplus/bus.hpp>
+
+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