From af4089dac348da982acc773b4715f930c1956864 Mon Sep 17 00:00:00 2001 From: Henri DF Date: Thu, 7 Apr 2016 16:30:06 -0700 Subject: [PATCH 1/4] Build and link yaml-cpp lib --- CMakeLists.txt | 12 ++++++++++++ digwatch.yaml | 6 ++++++ userspace/digwatch/CMakeLists.txt | 5 ++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 digwatch.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index d4f3d143..04ce9426 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,18 @@ ExternalProject_Add(b64 BUILD_IN_SOURCE 1 INSTALL_COMMAND "") + +set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp") +message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'") +set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a") +# Once the next version of yaml-cpp is released (first version not requiring +# boost), we can switch to that and no longer pull from github. +ExternalProject_Add(yamlcpp + GIT_REPOSITORY "https://github.com/jbeder/yaml-cpp.git" + GIT_TAG "7d2873ce9f2202ea21b6a8c5ecbc9fe38032c229" + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "") + set(OPENSSL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl") set(OPENSSL_INSTALL_DIR "${OPENSSL_BUNDLE_DIR}/target") set(OPENSSL_LIBRARY_SSL "${OPENSSL_INSTALL_DIR}/lib/libssl.a") diff --git a/digwatch.yaml b/digwatch.yaml new file mode 100644 index 00000000..2150fc69 --- /dev/null +++ b/digwatch.yaml @@ -0,0 +1,6 @@ +rules_file: /etc/digwatch.conf +priority_level: warning +outputs: + - file + - syslog + diff --git a/userspace/digwatch/CMakeLists.txt b/userspace/digwatch/CMakeLists.txt index fd71d282..eb849a73 100644 --- a/userspace/digwatch/CMakeLists.txt +++ b/userspace/digwatch/CMakeLists.txt @@ -6,11 +6,14 @@ include_directories(${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp) include_directories("${PROJECT_BINARY_DIR}/userspace/digwatch") include_directories("${CURL_INCLUDE_DIR}") include_directories("${LPEG_SRC}") +include_directories(${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include) add_executable(digwatch formats.cpp fields.cpp rules.cpp syslog.cpp digwatch.cpp) target_link_libraries(digwatch sinsp) -target_link_libraries(digwatch "${LPEG_SRC}/lpeg.a") +target_link_libraries(digwatch + "${LPEG_SRC}/lpeg.a" + "${YAMLCPP_LIB}") set(DIGWATCH_LUA_MAIN "rule_loader.lua") From dc099bfb91f3f0620d115818f12472a0bd558072 Mon Sep 17 00:00:00 2001 From: Henri DF Date: Tue, 12 Apr 2016 12:40:56 -0700 Subject: [PATCH 2/4] Add configuration object and Yaml parser These aren't wired up yet. --- CMakeLists.txt | 1 + digwatch.yaml | 18 ++++- userspace/digwatch/CMakeLists.txt | 3 +- userspace/digwatch/config_digwatch.h.in | 2 + userspace/digwatch/configuration.cpp | 47 +++++++++++ userspace/digwatch/configuration.h | 102 ++++++++++++++++++++++++ userspace/digwatch/digwatch.cpp | 12 ++- 7 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 userspace/digwatch/configuration.cpp create mode 100644 userspace/digwatch/configuration.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 04ce9426..7a435945 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,7 @@ ExternalProject_Add(b64 set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp") message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'") set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a") +set(YAMLCPP_INCLUDE_DIR "${YAMLCPP_SRC}/include") # Once the next version of yaml-cpp is released (first version not requiring # boost), we can switch to that and no longer pull from github. ExternalProject_Add(yamlcpp diff --git a/digwatch.yaml b/digwatch.yaml index 2150fc69..0c452e78 100644 --- a/digwatch.yaml +++ b/digwatch.yaml @@ -1,6 +1,16 @@ rules_file: /etc/digwatch.conf -priority_level: warning -outputs: - - file - - syslog + +# Priority level +# Any rule with priority lower than this level will be discarded +priority_level: warning + +syslog_output: + enabled: true + +file_output: + enabled: true + filename: "bla.bla" + +stdout_output: + enabled: false diff --git a/userspace/digwatch/CMakeLists.txt b/userspace/digwatch/CMakeLists.txt index eb849a73..eb6dfc8a 100644 --- a/userspace/digwatch/CMakeLists.txt +++ b/userspace/digwatch/CMakeLists.txt @@ -5,10 +5,11 @@ include_directories(${PROJECT_SOURCE_DIR}/../sysdig/userspace/libscap) include_directories(${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp) include_directories("${PROJECT_BINARY_DIR}/userspace/digwatch") include_directories("${CURL_INCLUDE_DIR}") +include_directories("${YAMLCPP_INCLUDE_DIR}") include_directories("${LPEG_SRC}") include_directories(${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include) -add_executable(digwatch formats.cpp fields.cpp rules.cpp syslog.cpp digwatch.cpp) +add_executable(digwatch configuration.cpp formats.cpp fields.cpp rules.cpp syslog.cpp digwatch.cpp) target_link_libraries(digwatch sinsp) target_link_libraries(digwatch diff --git a/userspace/digwatch/config_digwatch.h.in b/userspace/digwatch/config_digwatch.h.in index ad40da3a..2a1fd477 100644 --- a/userspace/digwatch/config_digwatch.h.in +++ b/userspace/digwatch/config_digwatch.h.in @@ -3,6 +3,8 @@ #define DIGWATCH_VERSION "${DIGWATCH_VERSION}" #define DIGWATCH_LUA_DIR "/usr/share/digwatch/lua/" +#define DIGWATCH_SOURCE_DIR "${PROJECT_SOURCE_DIR}" +#define DIGWATCH_CONF_FILE "${PROJECT_SOURCE_DIR}/digwatch.yaml" #define DIGWATCH_SOURCE_LUA_DIR "${PROJECT_SOURCE_DIR}/userspace/digwatch/lua/" diff --git a/userspace/digwatch/configuration.cpp b/userspace/digwatch/configuration.cpp new file mode 100644 index 00000000..1835116f --- /dev/null +++ b/userspace/digwatch/configuration.cpp @@ -0,0 +1,47 @@ +#include "configuration.h" +#include "config_digwatch.h" +#include "sinsp.h" + +using namespace std; + +void digwatch_configuration::init() +{ + string m_config_file = DIGWATCH_CONF_FILE; + m_config = new yaml_configuration(m_config_file); + + m_rules_file = m_config->get_scalar("rules_file", "/etc/digwatch.conf"); + m_priority_level = m_config->get_scalar("priority_level", "warning"); + + output_config file_output; + file_output.name = "file"; + if (m_config->get_scalar("file_output", "enabled", false)) + { + string filename; + filename = m_config->get_scalar("file_output", "filename", ""); + if (filename == string("")) + { + throw sinsp_exception("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block"); + } + file_output.options["filename"] = filename; + m_outputs.push_back(file_output); + } + + output_config stdout_output; + stdout_output.name = "stdout"; + if (m_config->get_scalar("stdout_output", "enabled", false)) + { + m_outputs.push_back(stdout_output); + } + + output_config syslog_output; + syslog_output.name = "syslog"; + if (m_config->get_scalar("syslog_output", "enabled", false)) + { + m_outputs.push_back(syslog_output); + } + + if (m_outputs.size() == 0) + { + throw sinsp_exception("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block"); + } +} diff --git a/userspace/digwatch/configuration.h b/userspace/digwatch/configuration.h new file mode 100644 index 00000000..d709ffa5 --- /dev/null +++ b/userspace/digwatch/configuration.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include + +struct output_config +{ + std::string name; + std::map options; +}; + +class yaml_configuration +{ +public: + std::string m_path; + yaml_configuration(const std::string& path) + { + m_path = path; + YAML::Node config; + std::vector outputs; + try + { + m_root = YAML::LoadFile(path); + } + catch (const YAML::BadFile& ex) + { + std::cerr << "Error reading config file (" + path + "): " + ex.what() + "\n"; + throw; + } + catch (const YAML::ParserException& ex) + { + std::cerr << "Cannot read config file (" + path + "): " + ex.what() + "\n"; + throw; + } + } + + /** + * Get a scalar value defined at the top level of the config + */ + template + const T get_scalar(const std::string& key, const T& default_value) + { + try + { + auto node = m_root[key]; + if (node.IsDefined()) + { + return node.as(); + } + } catch (const YAML::BadConversion& ex) + { + std::cerr << "Cannot read config file (" + m_path + "): wrong type at key " + key + "\n"; + throw; + } + + return default_value; + } + + /** + * Get a scalar value defined inside a 2 level nested structure like: + * file_output: + * enabled: true + * filename: output_file.txt + * + * get_scalar("file_output", "enabled", false) + */ + template + const T get_scalar(const std::string& key, const std::string& subkey, const T& default_value) + { + try + { + auto node = m_root[key][subkey]; + if (node.IsDefined()) + { + return node.as(); + } + } + catch (const YAML::BadConversion& ex) + { + std::cerr << "Cannot read config file (" + m_path + "): wrong type at key " + key + "\n"; + throw; + } + + return default_value; + } + +private: + YAML::Node m_root; +}; + + +class digwatch_configuration +{ + public: + void init(); + std::string m_rules_file; + std::string m_priority_level; + std::vector m_outputs; + private: + yaml_configuration* m_config; +}; + diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index 6ad529fe..137f6868 100644 --- a/userspace/digwatch/digwatch.cpp +++ b/userspace/digwatch/digwatch.cpp @@ -18,12 +18,14 @@ extern "C" { } #include -#include +#include "config_digwatch.h" +#include "configuration.h" #include "rules.h" #include "formats.h" #include "fields.h" #include "syslog.h" #include "utils.h" +#include static bool g_terminate = false; @@ -155,6 +157,8 @@ void add_lua_path(lua_State *ls, string path) lua_pop(ls, 1); } + + // // ARGUMENT PARSING AND PROGRAM SETUP // @@ -246,6 +250,9 @@ int digwatch_init(int argc, char **argv) } + digwatch_configuration config; + config.init(); + if(signal(SIGINT, signal_callback) == SIG_ERR) { fprintf(stderr, "An error occurred while setting SIGINT signal handler.\n"); @@ -275,7 +282,6 @@ int digwatch_init(int argc, char **argv) } } - // Initialize Lua interpreter ls = lua_open(); luaL_openlibs(ls); @@ -327,7 +333,7 @@ int digwatch_init(int argc, char **argv) } catch(...) { - printf("Exception\n"); + printf("Error, exiting.\n"); result = EXIT_FAILURE; } From 73ec593931165f23f4cf3c912f7bc321123e13b9 Mon Sep 17 00:00:00 2001 From: Henri DF Date: Tue, 12 Apr 2016 16:00:56 -0700 Subject: [PATCH 3/4] Add a configuration::init() that just sets up defaults (For when no config file is being used) --- userspace/digwatch/configuration.cpp | 11 ++++++++++- userspace/digwatch/configuration.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/userspace/digwatch/configuration.cpp b/userspace/digwatch/configuration.cpp index 1835116f..401d6328 100644 --- a/userspace/digwatch/configuration.cpp +++ b/userspace/digwatch/configuration.cpp @@ -4,9 +4,18 @@ using namespace std; + +// If we don't have a configuration file, we just use stdout output and all other defaults void digwatch_configuration::init() { - string m_config_file = DIGWATCH_CONF_FILE; + output_config stdout_output; + stdout_output.name = "stdout"; + m_outputs.push_back(stdout_output); +} + +void digwatch_configuration::init(string conf_filename) +{ + string m_config_file = conf_filename; m_config = new yaml_configuration(m_config_file); m_rules_file = m_config->get_scalar("rules_file", "/etc/digwatch.conf"); diff --git a/userspace/digwatch/configuration.h b/userspace/digwatch/configuration.h index d709ffa5..9d3644ab 100644 --- a/userspace/digwatch/configuration.h +++ b/userspace/digwatch/configuration.h @@ -92,6 +92,7 @@ private: class digwatch_configuration { public: + void init(std::string conf_filename); void init(); std::string m_rules_file; std::string m_priority_level; From 42de0507fa9d01dd93e3c37fbeee4706a886fff8 Mon Sep 17 00:00:00 2001 From: Henri DF Date: Tue, 12 Apr 2016 16:01:52 -0700 Subject: [PATCH 4/4] search for yaml config file In order: 1) cmdline opt 2) in-tree path 3) /etc/digwatch.yaml --- userspace/digwatch/config_digwatch.h.in | 3 +- userspace/digwatch/digwatch.cpp | 49 ++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/userspace/digwatch/config_digwatch.h.in b/userspace/digwatch/config_digwatch.h.in index 2a1fd477..252493cb 100644 --- a/userspace/digwatch/config_digwatch.h.in +++ b/userspace/digwatch/config_digwatch.h.in @@ -4,7 +4,8 @@ #define DIGWATCH_LUA_DIR "/usr/share/digwatch/lua/" #define DIGWATCH_SOURCE_DIR "${PROJECT_SOURCE_DIR}" -#define DIGWATCH_CONF_FILE "${PROJECT_SOURCE_DIR}/digwatch.yaml" +#define DIGWATCH_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/digwatch.yaml" +#define DIGWATCH_INSTALL_CONF_FILE "/etc/digwatch.yaml" #define DIGWATCH_SOURCE_LUA_DIR "${PROJECT_SOURCE_DIR}/userspace/digwatch/lua/" diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index 137f6868..43de8178 100644 --- a/userspace/digwatch/digwatch.cpp +++ b/userspace/digwatch/digwatch.cpp @@ -173,6 +173,7 @@ int digwatch_init(int argc, char **argv) string lua_main_filename; string output_name = "stdout"; string infile; + string conf_filename; string lua_dir = DIGWATCH_LUA_DIR; lua_State* ls = NULL; @@ -192,7 +193,7 @@ int digwatch_init(int argc, char **argv) // Parse the args // while((op = getopt_long(argc, argv, - "ho:r:", + "c:ho:R:", long_options, &long_index)) != -1) { switch(op) @@ -200,6 +201,9 @@ int digwatch_init(int argc, char **argv) case 'h': usage(); goto exit; + case 'c': + conf_filename = optarg; + break; case 'o': valid = std::find(valid_output_names.begin(), valid_output_names.end(), optarg) != valid_output_names.end(); if (!valid) @@ -250,8 +254,49 @@ int digwatch_init(int argc, char **argv) } + ifstream* conf_stream; + if (conf_filename.size()) + { + conf_stream = new ifstream(conf_filename); + if (!conf_stream->good()) + { + fprintf(stderr, "Could not find configuration file at %s \n", conf_filename.c_str()); + result = EXIT_FAILURE; + goto exit; + } + } + else + { + conf_stream = new ifstream(DIGWATCH_SOURCE_CONF_FILE); + if (conf_stream->good()) + { + conf_filename = DIGWATCH_SOURCE_CONF_FILE; + } + else + { + conf_stream = new ifstream(DIGWATCH_INSTALL_CONF_FILE); + if (conf_stream->good()) + { + conf_filename = DIGWATCH_INSTALL_CONF_FILE; + } + else + { + conf_filename = ""; + } + } + } + digwatch_configuration config; - config.init(); + if (conf_filename.size()) + { + cout << "Using configuration file " + conf_filename + "\n"; + config.init(conf_filename); + } + else + { + cout << "No configuration file found, proceeding with defaults\n"; + config.init(); + } if(signal(SIGINT, signal_callback) == SIG_ERR) {