From c2a513f65cfe49ccc4f026ff7cdfaf57e76403f8 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Mon, 19 Apr 2021 18:01:09 -0400 Subject: [PATCH 01/10] set up yaml configuration support --- cmd/pktvisord/main.cpp | 25 +++++++++++++++++++++++++ conanfile.txt | 1 + src/CMakeLists.txt | 1 + src/CoreServer.cpp | 4 ++++ src/CoreServer.h | 3 +++ 5 files changed, 34 insertions(+) diff --git a/cmd/pktvisord/main.cpp b/cmd/pktvisord/main.cpp index f8c53680c..f04900c76 100644 --- a/cmd/pktvisord/main.cpp +++ b/cmd/pktvisord/main.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "GeoDB.h" #include "handlers/dns/DnsStreamHandler.h" @@ -47,6 +48,8 @@ static const char USAGE[] = --version Show version --geo-city FILE GeoLite2 City database to use for IP to Geo mapping --geo-asn FILE GeoLite2 ASN database to use for IP to ASN mapping + Configuration: + --config FILE Use specified YAML configuration to configure options, Taps, and Collection Policies Logging Options: --log-file FILE Log to the given output file name --syslog Log to syslog @@ -194,6 +197,28 @@ int main(int argc, char *argv[]) } }); + if (args["--config"]) { + logger->info("using config file: {}", args["--config"].asString()); + YAML::Node config_file; + // look for local options + try { + config_file = YAML::LoadFile(args["--config"].asString()); + if (!config_file.IsMap() || !config_file["visor"]) { + throw std::runtime_error("invalid schema"); + } + } catch (std::runtime_error &e) { + logger->error("configuration error: {}", e.what()); + exit(EXIT_FAILURE); + } + + if (config_file.IsMap() && config_file["visor"] && config_file["visor"]["config"]) { + std::cerr << config_file << std::endl; + } + + // then pass to CoreServer + svr.configure_from_file(args["--config"].asString()); + } + shutdown_handler = [&]([[maybe_unused]] int signal) { logger->info("Shutting down"); svr.stop(); diff --git a/conanfile.txt b/conanfile.txt index dc69654b9..9a0b180d5 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -7,6 +7,7 @@ cpp-httplib/0.8.0 corrade/2020.06 pcapplusplus/ns1-dev json-schema-validator/2.1.0 +yaml-cpp/0.6.3 [build_requires] benchmark/1.5.2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b5fce816d..5038bdc97 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,6 +30,7 @@ target_link_libraries(visor-core ${CONAN_LIBS_CORRADE} ${CONAN_LIBS_SPDLOG} ${CONAN_LIBS_FMT} + ${CONAN_LIBS_YAML-CPP} ${VISOR_STATIC_PLUGINS} ) diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index 8490ff101..986d87c49 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -184,3 +184,7 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) }); } } +void visor::CoreServer::configure_from_file(const std::string &filename) +{ + YAML::Node config = YAML::LoadFile(filename); +} diff --git a/src/CoreServer.h b/src/CoreServer.h index 66c34ce20..20887ef70 100644 --- a/src/CoreServer.h +++ b/src/CoreServer.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace visor { @@ -53,6 +54,8 @@ class CoreServer void start(const std::string &host, int port); void stop(); + void configure_from_file(const std::string &filename); + void set_http_logger(httplib::Logger logger) { _svr.set_logger(logger); From f773920bc9da0fc3719cdc68d62f619e5a06d810 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Tue, 20 Apr 2021 11:05:05 -0400 Subject: [PATCH 02/10] yaml configuration --- .gitignore | 3 ++- cmd/pktvisord/main.cpp | 23 +++++++++++++++++------ src/CoreServer.cpp | 11 ++++++++++- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 82dd8837c..e38087f8f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ docs/html-documentation-generated* integration_tests/external golang/pkg/client/version.go docs/internals/html -appimage/*.AppImage \ No newline at end of file +appimage/*.AppImage +/test-config*.yaml diff --git a/cmd/pktvisord/main.cpp b/cmd/pktvisord/main.cpp index f04900c76..53a2efe37 100644 --- a/cmd/pktvisord/main.cpp +++ b/cmd/pktvisord/main.cpp @@ -197,26 +197,37 @@ int main(int argc, char *argv[]) } }); + // local config file if (args["--config"]) { logger->info("using config file: {}", args["--config"].asString()); YAML::Node config_file; // look for local options try { config_file = YAML::LoadFile(args["--config"].asString()); + if (!config_file.IsMap() || !config_file["visor"]) { throw std::runtime_error("invalid schema"); } + if (!config_file["version"] || !config_file["version"].IsScalar() || config_file["version"].as() != "1.0") { + throw std::runtime_error("missing or unsupported version"); + } + + if (config_file["visor"]["config"] && config_file["visor"]["config"].IsMap()) { + // todo more config items + auto config = config_file["visor"]["config"]; + if (config["verbose"] && config["verbose"].as()) { + logger->set_level(spdlog::level::debug); + } + } + + // then pass to CoreServer + svr.configure_from_file(args["--config"].asString()); + } catch (std::runtime_error &e) { logger->error("configuration error: {}", e.what()); exit(EXIT_FAILURE); } - if (config_file.IsMap() && config_file["visor"] && config_file["visor"]["config"]) { - std::cerr << config_file << std::endl; - } - - // then pass to CoreServer - svr.configure_from_file(args["--config"].asString()); } shutdown_handler = [&]([[maybe_unused]] int signal) { diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index 986d87c49..5b0d7a8a3 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -186,5 +186,14 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) } void visor::CoreServer::configure_from_file(const std::string &filename) { - YAML::Node config = YAML::LoadFile(filename); + YAML::Node config_file = YAML::LoadFile(filename); + + if (!config_file.IsMap() || !config_file["visor"]) { + throw std::runtime_error("invalid schema"); + } + if (!config_file["version"] || !config_file["version"].IsScalar() || config_file["version"].as() != "1.0") { + throw std::runtime_error("missing or unsupported version"); + } + + // taps } From eadd424d09a59a75f9be63f28512c93d38aaaf97 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Tue, 20 Apr 2021 11:46:21 -0400 Subject: [PATCH 03/10] break out configurable. add taps. start checking names/labels with regex --- src/AbstractModule.h | 64 ++++------------------------------ src/CMakeLists.txt | 3 +- src/Configurable.h | 81 ++++++++++++++++++++++++++++++++++++++++++++ src/CoreServer.cpp | 3 ++ src/Metrics.h | 15 ++++++++ src/Taps.cpp | 14 ++++++++ src/Taps.h | 27 +++++++++++++++ 7 files changed, 148 insertions(+), 59 deletions(-) create mode 100644 src/Configurable.h create mode 100644 src/Taps.cpp create mode 100644 src/Taps.h diff --git a/src/AbstractModule.h b/src/AbstractModule.h index 6423f3483..c7430a167 100644 --- a/src/AbstractModule.h +++ b/src/AbstractModule.h @@ -4,9 +4,11 @@ #pragma once +#include "Configurable.h" #include #include #include +#include #include #include #include @@ -16,20 +18,8 @@ namespace visor { using json = nlohmann::json; -class ConfigException : public std::runtime_error +class AbstractModule : public Configurable { -public: - explicit ConfigException(const std::string &msg) - : std::runtime_error(msg) - { - } -}; - -class AbstractModule -{ -private: - std::unordered_map> _config; - mutable std::shared_mutex _config_mutex; protected: std::atomic_bool _running = false; @@ -50,6 +40,9 @@ class AbstractModule AbstractModule(const std::string &name) : _name(name) { + if (!std::regex_match(name, std::regex("[a-zA-Z_][a-zA-Z0-9_]*"))) { + throw std::runtime_error("invalid module name: " + name); + } } virtual ~AbstractModule(){}; @@ -74,51 +67,6 @@ class AbstractModule { return _running; } - - template - auto config_get(const std::string &key) - { - std::shared_lock lock(_config_mutex); - if (_config.count(key) == 0) { - throw ConfigException("missing key: " + key); - } - auto val = std::get_if(&_config[key]); - if (!val) { - throw ConfigException("wrong type for key: " + key); - } - return *val; - } - - template - void config_set(const std::string &key, const T &val) - { - std::unique_lock lock(_config_mutex); - _config[key] = val; - } - - // specialize to ensure a string literal is interpreted as a std::string - void config_set(const std::string &key, const char *val) - { - std::unique_lock lock(_config_mutex); - _config[key] = std::string(val); - } - - bool config_exists(const std::string &name) const - { - std::shared_lock lock(_config_mutex); - return _config.count(name) == 1; - } - - void config_json(json &j) const - { - std::shared_lock lock(_config_mutex); - for (const auto &[key, value] : _config) { - std::visit([&j, key = key](auto &&arg) { - j[key] = arg; - }, - value); - } - } }; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5038bdc97..733600b85 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,8 @@ add_library(visor-core HandlerModulePlugin.cpp GeoDB.cpp CoreServer.cpp - Metrics.cpp Metrics.h) + Metrics.cpp + Taps.cpp) add_library(Visor::Core ALIAS visor-core) target_include_directories(visor-core diff --git a/src/Configurable.h b/src/Configurable.h new file mode 100644 index 000000000..7c1575801 --- /dev/null +++ b/src/Configurable.h @@ -0,0 +1,81 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace visor { + +using json = nlohmann::json; + +class ConfigException : public std::runtime_error +{ +public: + explicit ConfigException(const std::string &msg) + : std::runtime_error(msg) + { + } +}; + +class Configurable +{ +private: + std::unordered_map> _config; + mutable std::shared_mutex _config_mutex; + +public: + template + auto config_get(const std::string &key) + { + std::shared_lock lock(_config_mutex); + if (_config.count(key) == 0) { + throw ConfigException("missing key: " + key); + } + auto val = std::get_if(&_config[key]); + if (!val) { + throw ConfigException("wrong type for key: " + key); + } + return *val; + } + + template + void config_set(const std::string &key, const T &val) + { + std::unique_lock lock(_config_mutex); + _config[key] = val; + } + + // specialize to ensure a string literal is interpreted as a std::string + void config_set(const std::string &key, const char *val) + { + std::unique_lock lock(_config_mutex); + _config[key] = std::string(val); + } + + bool config_exists(const std::string &name) const + { + std::shared_lock lock(_config_mutex); + return _config.count(name) == 1; + } + + void config_json(json &j) const + { + std::shared_lock lock(_config_mutex); + for (const auto &[key, value] : _config) { + std::visit([&j, key = key](auto &&arg) { + j[key] = arg; + }, + value); + } + } +}; + +} diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index 5b0d7a8a3..7f9bc652e 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -196,4 +196,7 @@ void visor::CoreServer::configure_from_file(const std::string &filename) } // taps + if (config_file["visor"]["taps"] && config_file["visor"]["taps"].IsMap()) { + auto taps = config_file["visor"]["taps"]; + } } diff --git a/src/Metrics.h b/src/Metrics.h index fd5bfa081..3d611a55f 100644 --- a/src/Metrics.h +++ b/src/Metrics.h @@ -16,6 +16,7 @@ #include #pragma GCC diagnostic pop #include +#include #include #include @@ -40,12 +41,25 @@ class Metric std::string _desc; std::string _schema_key; + void _check_names() + { + for (const auto &name : _name) { + if (!std::regex_match(name, std::regex("[a-zA-Z_][a-zA-Z0-9_]*"))) { + throw std::runtime_error("invalid metric name: " + name); + } + } + if (!std::regex_match(_schema_key, std::regex("[a-zA-Z_][a-zA-Z0-9_]*"))) { + throw std::runtime_error("invalid schema name: " + _schema_key); + } + } + public: Metric(std::string schema_key, std::initializer_list names, std::string desc) : _name(names) , _desc(std::move(desc)) , _schema_key(schema_key) { + _check_names(); } void set_info(std::string schema_key, std::initializer_list names, const std::string &desc) @@ -54,6 +68,7 @@ class Metric _name = names; _desc = desc; _schema_key = schema_key; + _check_names(); } static void add_base_label(const std::string &label, const std::string &value) diff --git a/src/Taps.cpp b/src/Taps.cpp new file mode 100644 index 000000000..8333667ae --- /dev/null +++ b/src/Taps.cpp @@ -0,0 +1,14 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "Taps.h" +#include + +visor::Tap::Tap(const std::string &name) + : _name(name) +{ + if (!std::regex_match(name, std::regex("[a-zA-Z_][a-zA-Z0-9_]*"))) { + throw std::runtime_error("invalid tap name: " + name); + } +} diff --git a/src/Taps.h b/src/Taps.h new file mode 100644 index 000000000..e3ac165c9 --- /dev/null +++ b/src/Taps.h @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "Configurable.h" + +namespace visor { + +class Tap : public Configurable +{ +protected: + /** + * the tap identifier: unique name associated with this Tap + */ + std::string _name; + +public: + Tap(const std::string &name); +}; + +class TapManager +{ +}; + +} \ No newline at end of file From 8005aae50f06083ad6d4d5af45350d3af981bbd6 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Tue, 20 Apr 2021 13:21:44 -0400 Subject: [PATCH 04/10] some more abstraction for taps. take module life cycle (start/stop) out of the manager --- cmd/pktvisor-pcap/main.cpp | 4 ++- cmd/pktvisord/main.cpp | 3 ++ src/AbstractManager.h | 13 ++++----- src/AbstractModule.h | 32 +++++++++++++++++---- src/CoreServer.cpp | 3 ++ src/CoreServer.h | 2 ++ src/InputStream.h | 4 +-- src/StreamHandler.h | 4 +-- src/Taps.cpp | 9 +----- src/Taps.h | 20 +++++++------ src/handlers/dns/DnsHandlerModulePlugin.cpp | 4 +++ src/handlers/net/NetHandlerModulePlugin.cpp | 4 +++ src/inputs/pcap/PcapInputModulePlugin.cpp | 2 +- 13 files changed, 69 insertions(+), 35 deletions(-) diff --git a/cmd/pktvisor-pcap/main.cpp b/cmd/pktvisor-pcap/main.cpp index 005cd2ae9..1b25bfd99 100644 --- a/cmd/pktvisor-pcap/main.cpp +++ b/cmd/pktvisor-pcap/main.cpp @@ -164,7 +164,7 @@ int main(int argc, char *argv[]) input_stream->info_json(j["info"]); logger->info("{}", j.dump(4)); - input_manager->module_add(std::move(input_stream), false); + input_manager->module_add(std::move(input_stream)); auto [input_stream_, stream_mgr_lock] = input_manager->module_get_locked("pcap"); stream_mgr_lock.unlock(); auto pcap_stream = dynamic_cast(input_stream_); @@ -173,6 +173,7 @@ int main(int argc, char *argv[]) { auto handler_module = std::make_unique("net", pcap_stream, periods, sample_rate); handler_module->config_set("recorded_stream", true); + handler_module->start(); handler_manager->module_add(std::move(handler_module)); auto [handler, handler_mgr_lock] = handler_manager->module_get_locked("net"); handler_mgr_lock.unlock(); @@ -182,6 +183,7 @@ int main(int argc, char *argv[]) { auto handler_module = std::make_unique("dns", pcap_stream, periods, sample_rate); handler_module->config_set("recorded_stream", true); + handler_module->start(); handler_manager->module_add(std::move(handler_module)); auto [handler, handler_mgr_lock] = handler_manager->module_get_locked("dns"); handler_mgr_lock.unlock(); diff --git a/cmd/pktvisord/main.cpp b/cmd/pktvisord/main.cpp index 53a2efe37..c48c0f365 100644 --- a/cmd/pktvisord/main.cpp +++ b/cmd/pktvisord/main.cpp @@ -300,6 +300,7 @@ int main(int argc, char *argv[]) auto input_manager = svr.input_manager(); auto handler_manager = svr.handler_manager(); + input_stream->start(); input_manager->module_add(std::move(input_stream)); auto [input_stream_, stream_mgr_lock] = input_manager->module_get_locked("pcap"); stream_mgr_lock.unlock(); @@ -307,10 +308,12 @@ int main(int argc, char *argv[]) { auto handler_module = std::make_unique("net", pcap_stream, periods, sample_rate); + handler_module->start(); handler_manager->module_add(std::move(handler_module)); } { auto handler_module = std::make_unique("dns", pcap_stream, periods, sample_rate); + handler_module->start(); handler_manager->module_add(std::move(handler_module)); } diff --git a/src/AbstractManager.h b/src/AbstractManager.h index e45f690b0..baee369db 100644 --- a/src/AbstractManager.h +++ b/src/AbstractManager.h @@ -32,6 +32,10 @@ class AbstractManager { } + virtual ~AbstractManager() + { + } + auto module_get_all_locked() { struct retVals { @@ -42,16 +46,12 @@ class AbstractManager return retVals{_map, std::move(lock)}; } - // atomically ensure module starts before arriving in registry, if requested - virtual void module_add(std::unique_ptr &&m, bool start = true) + virtual void module_add(std::unique_ptr &&m) { std::unique_lock lock(_map_mutex); if (_map.count(m->name())) { throw std::runtime_error("module name already exists"); } - if (start) { - m->start(); - } _map.emplace(m->name(), std::move(m)); } @@ -64,7 +64,7 @@ class AbstractManager throw std::runtime_error("module name does not exist"); } struct retVals { - ModuleType *map; + ModuleType *module; std::unique_lock lock; }; return retVals{_map[name].get(), std::move(lock)}; @@ -76,7 +76,6 @@ class AbstractManager if (_map.count(name) == 0) { throw std::runtime_error("module name does not exist"); } - _map[name]->stop(); _map.erase(name); } diff --git a/src/AbstractModule.h b/src/AbstractModule.h index c7430a167..8f644ac1f 100644 --- a/src/AbstractModule.h +++ b/src/AbstractModule.h @@ -22,7 +22,6 @@ class AbstractModule : public Configurable { protected: - std::atomic_bool _running = false; /** * the module instance identifier: unique name associated with this instance @@ -32,7 +31,6 @@ class AbstractModule : public Configurable void _common_info_json(json &j) const { j["module"]["name"] = _name; - j["module"]["running"] = _running.load(); config_json(j["module"]["config"]); } @@ -40,22 +38,44 @@ class AbstractModule : public Configurable AbstractModule(const std::string &name) : _name(name) { - if (!std::regex_match(name, std::regex("[a-zA-Z_][a-zA-Z0-9_]*"))) { + if (!std::regex_match(name, std::regex("[a-zA-Z_][a-zA-Z0-9_-]*"))) { throw std::runtime_error("invalid module name: " + name); } } virtual ~AbstractModule(){}; - virtual void start() = 0; - virtual void stop() = 0; - virtual void info_json(json &j) const = 0; const std::string &name() const { return _name; } +}; + +class AbstractRunnableModule : public AbstractModule +{ + +protected: + std::atomic_bool _running = false; + + void _common_info_json(json &j) const + { + j["module"]["name"] = _name; + j["module"]["running"] = _running.load(); + config_json(j["module"]["config"]); + } + +public: + AbstractRunnableModule(const std::string &name) + : AbstractModule(name) + { + } + + virtual ~AbstractRunnableModule(){}; + + virtual void start() = 0; + virtual void stop() = 0; /** * the module schema key: the same for all instances of this module diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index 7f9bc652e..96b1d171a 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -37,6 +37,9 @@ visor::CoreServer::CoreServer(bool read_only, std::shared_ptr lo _handler_plugins.emplace_back(std::move(mod)); } + // taps + _tap_manager = std::make_unique(); + _setup_routes(prom_config); if (!prom_config.instance.empty()) { Metric::add_base_label("instance", prom_config.instance); diff --git a/src/CoreServer.h b/src/CoreServer.h index 20887ef70..5ed8dde35 100644 --- a/src/CoreServer.h +++ b/src/CoreServer.h @@ -9,6 +9,7 @@ #include "HttpServer.h" #include "InputModulePlugin.h" #include "InputStreamManager.h" +#include "Taps.h" #include #include #include @@ -41,6 +42,7 @@ class CoreServer std::unique_ptr _input_manager; std::unique_ptr _handler_manager; + std::unique_ptr _tap_manager; std::shared_ptr _logger; std::chrono::system_clock::time_point _start_time; diff --git a/src/InputStream.h b/src/InputStream.h index 19d5a6852..7fe1c4a54 100644 --- a/src/InputStream.h +++ b/src/InputStream.h @@ -9,12 +9,12 @@ namespace visor { -class InputStream : public AbstractModule +class InputStream : public AbstractRunnableModule { public: InputStream(const std::string &name) - : AbstractModule(name) + : AbstractRunnableModule(name) { } diff --git a/src/StreamHandler.h b/src/StreamHandler.h index 159a00c05..0413862e1 100644 --- a/src/StreamHandler.h +++ b/src/StreamHandler.h @@ -13,12 +13,12 @@ namespace visor { using json = nlohmann::json; -class StreamHandler : public AbstractModule +class StreamHandler : public AbstractRunnableModule { public: StreamHandler(const std::string &name) - : AbstractModule(name) + : AbstractRunnableModule(name) { } diff --git a/src/Taps.cpp b/src/Taps.cpp index 8333667ae..bccca739a 100644 --- a/src/Taps.cpp +++ b/src/Taps.cpp @@ -3,12 +3,5 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "Taps.h" -#include -visor::Tap::Tap(const std::string &name) - : _name(name) -{ - if (!std::regex_match(name, std::regex("[a-zA-Z_][a-zA-Z0-9_]*"))) { - throw std::runtime_error("invalid tap name: " + name); - } -} + diff --git a/src/Taps.h b/src/Taps.h index e3ac165c9..54603178e 100644 --- a/src/Taps.h +++ b/src/Taps.h @@ -4,24 +4,28 @@ #pragma once +#include "AbstractManager.h" +#include "AbstractModule.h" #include "Configurable.h" namespace visor { -class Tap : public Configurable +class Tap : public AbstractModule { -protected: - /** - * the tap identifier: unique name associated with this Tap - */ - std::string _name; public: - Tap(const std::string &name); + Tap(const std::string &name) + : AbstractModule(name) + { + } }; -class TapManager +class TapManager : public AbstractManager { +public: + virtual ~TapManager() + { + } }; } \ No newline at end of file diff --git a/src/handlers/dns/DnsHandlerModulePlugin.cpp b/src/handlers/dns/DnsHandlerModulePlugin.cpp index 126ca040b..72e3abbd6 100644 --- a/src/handlers/dns/DnsHandlerModulePlugin.cpp +++ b/src/handlers/dns/DnsHandlerModulePlugin.cpp @@ -72,6 +72,7 @@ void DnsHandlerModulePlugin::_setup_routes(HttpServer &svr) deep_sample_rate = body["deep_sample_rate"]; } auto handler_module = std::make_unique(body["name"], pcap_stream, periods, deep_sample_rate); + handler_module->start(); _handler_manager->module_add(std::move(handler_module)); result["name"] = body["name"]; result["periods"] = periods; @@ -167,6 +168,9 @@ void DnsHandlerModulePlugin::_setup_routes(HttpServer &svr) res.set_content(result.dump(), "text/json"); return; } + auto [handler, handler_mgr_lock] = _handler_manager->module_get_locked(handler_name); + handler->stop(); + handler_mgr_lock.unlock(); _handler_manager->module_remove(handler_name); res.set_content(result.dump(), "text/json"); } catch (const std::exception &e) { diff --git a/src/handlers/net/NetHandlerModulePlugin.cpp b/src/handlers/net/NetHandlerModulePlugin.cpp index 66f93be53..62655fd83 100644 --- a/src/handlers/net/NetHandlerModulePlugin.cpp +++ b/src/handlers/net/NetHandlerModulePlugin.cpp @@ -72,6 +72,7 @@ void NetHandlerModulePlugin::_setup_routes(HttpServer &svr) deep_sample_rate = body["deep_sample_rate"]; } auto handler_module = std::make_unique(body["name"], pcap_stream, periods, deep_sample_rate); + handler_module->start(); _handler_manager->module_add(std::move(handler_module)); result["name"] = body["name"]; result["periods"] = periods; @@ -170,6 +171,9 @@ void NetHandlerModulePlugin::_setup_routes(HttpServer &svr) res.set_content(result.dump(), "text/json"); return; } + auto [handler, handler_mgr_lock] = _handler_manager->module_get_locked(handler_name); + handler->stop(); + handler_mgr_lock.unlock(); _handler_manager->module_remove(handler_name); res.set_content(result.dump(), "text/json"); } catch (const std::exception &e) { diff --git a/src/inputs/pcap/PcapInputModulePlugin.cpp b/src/inputs/pcap/PcapInputModulePlugin.cpp index b718f50f1..3f1a9bc16 100644 --- a/src/inputs/pcap/PcapInputModulePlugin.cpp +++ b/src/inputs/pcap/PcapInputModulePlugin.cpp @@ -60,8 +60,8 @@ void PcapInputModulePlugin::_create(const httplib::Request &req, httplib::Respon if (body.contains("pcap_source")) { input_stream->config_set("pcap_source", body["pcap_source"].get()); } + input_stream->start(); _input_manager->module_add(std::move(input_stream)); - // the module is now started and owned by the manager } auto [input_stream, stream_mgr_lock] = _input_manager->module_get_locked(body["name"]); From f72b86d5741fa32f9699dc3ff4007af8d88bb400 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Tue, 20 Apr 2021 14:52:05 -0400 Subject: [PATCH 05/10] naming of modules and plugins, tap config work --- src/CoreServer.cpp | 13 +++++------ src/CoreServer.h | 23 ++++++++++++++++++-- src/HandlerModulePlugin.h | 2 +- src/InputModulePlugin.h | 4 ++-- src/Taps.cpp | 24 ++++++++++++++++++++- src/Taps.h | 12 +++++++++++ src/handlers/dns/DnsHandlerModulePlugin.cpp | 2 +- src/handlers/dns/DnsHandlerModulePlugin.h | 2 +- src/handlers/net/NetHandlerModulePlugin.cpp | 2 +- src/handlers/net/NetHandlerModulePlugin.h | 2 +- src/inputs/pcap/PcapInputModulePlugin.cpp | 2 +- src/inputs/pcap/PcapInputModulePlugin.h | 2 +- 12 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index 96b1d171a..ec9f53be0 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -21,7 +21,7 @@ visor::CoreServer::CoreServer(bool read_only, std::shared_ptr lo // initialize input plugins for (auto &s : _input_registry.pluginList()) { InputPluginPtr mod = _input_registry.instantiate(s); - _logger->info("Load input plugin: {} {}", mod->name(), mod->pluginInterface()); + _logger->info("Load input stream plugin: {} {}", mod->name(), mod->pluginInterface()); mod->init_module(_input_manager.get(), _svr); _input_plugins.emplace_back(std::move(mod)); } @@ -32,15 +32,16 @@ visor::CoreServer::CoreServer(bool read_only, std::shared_ptr lo // initialize handler plugins for (auto &s : _handler_registry.pluginList()) { HandlerPluginPtr mod = _handler_registry.instantiate(s); - _logger->info("Load handler plugin: {} {}", mod->name(), mod->pluginInterface()); + _logger->info("Load stream handler plugin: {} {}", mod->name(), mod->pluginInterface()); mod->init_module(_input_manager.get(), _handler_manager.get(), _svr); _handler_plugins.emplace_back(std::move(mod)); } // taps - _tap_manager = std::make_unique(); + _tap_manager = std::make_unique(_input_manager.get()); _setup_routes(prom_config); + if (!prom_config.instance.empty()) { Metric::add_base_label("instance", prom_config.instance); } @@ -192,14 +193,14 @@ void visor::CoreServer::configure_from_file(const std::string &filename) YAML::Node config_file = YAML::LoadFile(filename); if (!config_file.IsMap() || !config_file["visor"]) { - throw std::runtime_error("invalid schema"); + throw ConfigException("invalid schema"); } if (!config_file["version"] || !config_file["version"].IsScalar() || config_file["version"].as() != "1.0") { - throw std::runtime_error("missing or unsupported version"); + throw ConfigException("missing or unsupported version"); } // taps if (config_file["visor"]["taps"] && config_file["visor"]["taps"].IsMap()) { - auto taps = config_file["visor"]["taps"]; + _tap_manager->load(config_file["visor"]["taps"]); } } diff --git a/src/CoreServer.h b/src/CoreServer.h index 5ed8dde35..0c0115cc9 100644 --- a/src/CoreServer.h +++ b/src/CoreServer.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -25,13 +26,12 @@ struct PrometheusConfig { class CoreServer { -public: -private: typedef Corrade::PluginManager::Manager InputPluginRegistry; typedef Corrade::PluginManager::Manager HandlerPluginRegistry; typedef Corrade::Containers::Pointer InputPluginPtr; typedef Corrade::Containers::Pointer HandlerPluginPtr; + // these hold plugin instances: these are the types of modules available for instantiation InputPluginRegistry _input_registry; std::vector _input_plugins; @@ -40,8 +40,10 @@ class CoreServer visor::HttpServer _svr; + // these hold instances of active modules std::unique_ptr _input_manager; std::unique_ptr _handler_manager; + std::unique_ptr _tap_manager; std::shared_ptr _logger; @@ -63,6 +65,19 @@ class CoreServer _svr.set_logger(logger); } + const InputStreamManager *input_manager() const + { + return _input_manager.get(); + } + const HandlerManager *handler_manager() const + { + return _handler_manager.get(); + } + const TapManager *tap_manager() const + { + return _tap_manager.get(); + } + InputStreamManager *input_manager() { return _input_manager.get(); @@ -71,6 +86,10 @@ class CoreServer { return _handler_manager.get(); } + TapManager *tap_manager() + { + return _tap_manager.get(); + } }; } \ No newline at end of file diff --git a/src/HandlerModulePlugin.h b/src/HandlerModulePlugin.h index b568ff16e..9c4ff2f4c 100644 --- a/src/HandlerModulePlugin.h +++ b/src/HandlerModulePlugin.h @@ -22,7 +22,7 @@ class HandlerModulePlugin : public AbstractPlugin public: static std::string pluginInterface() { - return "dev.visor.module.handler/1.0"; + return "visor.module.handler/1.0"; } static std::vector pluginSearchPaths() diff --git a/src/InputModulePlugin.h b/src/InputModulePlugin.h index 079395a87..1cec40c34 100644 --- a/src/InputModulePlugin.h +++ b/src/InputModulePlugin.h @@ -14,14 +14,14 @@ class InputModulePlugin : public AbstractPlugin { protected: - visor::InputStreamManager *_input_manager; + InputStreamManager *_input_manager; virtual void _setup_routes(HttpServer &svr) = 0; public: static std::string pluginInterface() { - return "dev.visor.module.input/1.0"; + return "visor.module.input/1.0"; } static std::vector pluginSearchPaths() diff --git a/src/Taps.cpp b/src/Taps.cpp index bccca739a..acfc91db8 100644 --- a/src/Taps.cpp +++ b/src/Taps.cpp @@ -3,5 +3,27 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "Taps.h" +#include - +void visor::TapManager::load(const YAML::Node &tap_yaml) +{ + assert(tap_yaml.IsMap()); + for (YAML::const_iterator it = tap_yaml.begin(); it != tap_yaml.end(); ++it) { + if (!it->first.IsScalar()) { + throw ConfigException("expecting tap identifier"); + } + auto tap_name = it->first.as(); + spdlog::get("pktvisor")->info("loading Tap: {}", tap_name); + if (!it->second.IsMap()) { + throw ConfigException("expecting tap configuration map"); + } + if (!it->second["type"] || !it->second["type"].IsScalar()) { + throw ConfigException("missing or invalid tap input stream 'type'"); + } + auto tap_type = it->second["type"].as(); + if (!_input_manager->module_exists(tap_type)) { + spdlog::get("pktvisor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, tap_type); + continue; + } + } +} diff --git a/src/Taps.h b/src/Taps.h index 54603178e..9f1236240 100644 --- a/src/Taps.h +++ b/src/Taps.h @@ -7,6 +7,8 @@ #include "AbstractManager.h" #include "AbstractModule.h" #include "Configurable.h" +#include "InputStreamManager.h" +#include namespace visor { @@ -22,10 +24,20 @@ class Tap : public AbstractModule class TapManager : public AbstractManager { + + const InputStreamManager *_input_manager; + public: + TapManager(const InputStreamManager *inputManager) + : _input_manager(inputManager) + { + } + virtual ~TapManager() { } + + void load(const YAML::Node &tap_yaml); }; } \ No newline at end of file diff --git a/src/handlers/dns/DnsHandlerModulePlugin.cpp b/src/handlers/dns/DnsHandlerModulePlugin.cpp index 72e3abbd6..183020262 100644 --- a/src/handlers/dns/DnsHandlerModulePlugin.cpp +++ b/src/handlers/dns/DnsHandlerModulePlugin.cpp @@ -9,7 +9,7 @@ #include CORRADE_PLUGIN_REGISTER(VisorHandlerDns, visor::handler::dns::DnsHandlerModulePlugin, - "dev.visor.module.handler/1.0") + "visor.module.handler/1.0") namespace visor::handler::dns { diff --git a/src/handlers/dns/DnsHandlerModulePlugin.h b/src/handlers/dns/DnsHandlerModulePlugin.h index 0f84102ee..d28d3d8f1 100644 --- a/src/handlers/dns/DnsHandlerModulePlugin.h +++ b/src/handlers/dns/DnsHandlerModulePlugin.h @@ -22,7 +22,7 @@ class DnsHandlerModulePlugin : public HandlerModulePlugin std::string name() const override { - return "DnsHandler"; + return "dns"; } }; } diff --git a/src/handlers/net/NetHandlerModulePlugin.cpp b/src/handlers/net/NetHandlerModulePlugin.cpp index 62655fd83..0a3f73aff 100644 --- a/src/handlers/net/NetHandlerModulePlugin.cpp +++ b/src/handlers/net/NetHandlerModulePlugin.cpp @@ -9,7 +9,7 @@ #include CORRADE_PLUGIN_REGISTER(VisorHandlerNet, visor::handler::net::NetHandlerModulePlugin, - "dev.visor.module.handler/1.0") + "visor.module.handler/1.0") namespace visor::handler::net { diff --git a/src/handlers/net/NetHandlerModulePlugin.h b/src/handlers/net/NetHandlerModulePlugin.h index 6344f5b9d..ada3b7e05 100644 --- a/src/handlers/net/NetHandlerModulePlugin.h +++ b/src/handlers/net/NetHandlerModulePlugin.h @@ -23,7 +23,7 @@ class NetHandlerModulePlugin : public HandlerModulePlugin std::string name() const override { - return "NetHandler"; + return "net"; } }; } diff --git a/src/inputs/pcap/PcapInputModulePlugin.cpp b/src/inputs/pcap/PcapInputModulePlugin.cpp index 3f1a9bc16..945c0c987 100644 --- a/src/inputs/pcap/PcapInputModulePlugin.cpp +++ b/src/inputs/pcap/PcapInputModulePlugin.cpp @@ -7,7 +7,7 @@ #include CORRADE_PLUGIN_REGISTER(VisorInputPcap, visor::input::pcap::PcapInputModulePlugin, - "dev.visor.module.input/1.0") + "visor.module.input/1.0") namespace visor::input::pcap { diff --git a/src/inputs/pcap/PcapInputModulePlugin.h b/src/inputs/pcap/PcapInputModulePlugin.h index 4334a0d63..4c44f14e4 100644 --- a/src/inputs/pcap/PcapInputModulePlugin.h +++ b/src/inputs/pcap/PcapInputModulePlugin.h @@ -28,7 +28,7 @@ class PcapInputModulePlugin : public visor::InputModulePlugin std::string name() const override { - return "PcapInputModulePlugin"; + return "pcap"; } }; From dbcc18550acf7134732f3d8c60ef0ba64c3368aa Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Tue, 20 Apr 2021 16:34:53 -0400 Subject: [PATCH 06/10] get to handle on corrade plug in names and aliases --- cmd/pktvisord/main.cpp | 2 +- src/AbstractPlugin.h | 1 - src/CoreServer.cpp | 42 ++++++++++++++++------- src/CoreServer.h | 12 +++---- src/HandlerModulePlugin.h | 8 +++-- src/InputModulePlugin.h | 8 +++-- src/Taps.cpp | 6 +++- src/Taps.h | 8 ++--- src/handlers/dns/DnsHandler.conf | 2 ++ src/handlers/dns/DnsHandlerModulePlugin.h | 5 --- src/handlers/net/NetHandler.conf | 2 ++ src/handlers/net/NetHandlerModulePlugin.h | 4 --- src/inputs/pcap/PcapInput.conf | 4 ++- src/inputs/pcap/PcapInputModulePlugin.h | 5 --- 14 files changed, 61 insertions(+), 48 deletions(-) diff --git a/cmd/pktvisord/main.cpp b/cmd/pktvisord/main.cpp index c48c0f365..0d12fde79 100644 --- a/cmd/pktvisord/main.cpp +++ b/cmd/pktvisord/main.cpp @@ -189,7 +189,7 @@ int main(int argc, char *argv[]) prom_config.instance = args["--prom-instance"].asString(); } } - CoreServer svr(!args["--admin-api"].asBool(), logger, prom_config); + CoreServer svr(!args["--admin-api"].asBool(), prom_config); svr.set_http_logger([&logger](const auto &req, const auto &res) { logger->info("REQUEST: {} {} {}", req.method, req.path, res.status); if (res.status == 500) { diff --git a/src/AbstractPlugin.h b/src/AbstractPlugin.h index a292b2f42..f99386c48 100644 --- a/src/AbstractPlugin.h +++ b/src/AbstractPlugin.h @@ -45,7 +45,6 @@ class AbstractPlugin : public Corrade::PluginManager::AbstractPlugin { } - virtual std::string name() const = 0; }; } diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index ec9f53be0..a4be80060 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -9,36 +9,52 @@ #include #include -visor::CoreServer::CoreServer(bool read_only, std::shared_ptr logger, const PrometheusConfig &prom_config) +visor::CoreServer::CoreServer(bool read_only, const PrometheusConfig &prom_config) : _svr(read_only) - , _logger(logger) , _start_time(std::chrono::system_clock::now()) { + _logger = spdlog::get("pktvisor"); + assert(_logger); + // inputs _input_manager = std::make_unique(); // initialize input plugins - for (auto &s : _input_registry.pluginList()) { - InputPluginPtr mod = _input_registry.instantiate(s); - _logger->info("Load input stream plugin: {} {}", mod->name(), mod->pluginInterface()); - mod->init_module(_input_manager.get(), _svr); - _input_plugins.emplace_back(std::move(mod)); + { + auto alias_list = _input_registry.aliasList(); + auto plugin_list = _input_registry.pluginList(); + std::vector by_alias; + std::set_difference(alias_list.begin(), alias_list.end(), + plugin_list.begin(), plugin_list.end(), std::inserter(by_alias, by_alias.begin())); + for (auto &s : by_alias) { + InputPluginPtr mod = _input_registry.instantiate(s); + _logger->info("Load input stream plugin: {} {}", s, mod->pluginInterface()); + mod->init_module(_input_manager.get(), _svr); + _input_plugins.emplace_back(std::move(mod)); + } } // handlers _handler_manager = std::make_unique(); // initialize handler plugins - for (auto &s : _handler_registry.pluginList()) { - HandlerPluginPtr mod = _handler_registry.instantiate(s); - _logger->info("Load stream handler plugin: {} {}", mod->name(), mod->pluginInterface()); - mod->init_module(_input_manager.get(), _handler_manager.get(), _svr); - _handler_plugins.emplace_back(std::move(mod)); + { + auto alias_list = _handler_registry.aliasList(); + auto plugin_list = _handler_registry.pluginList(); + std::vector by_alias; + std::set_difference(alias_list.begin(), alias_list.end(), + plugin_list.begin(), plugin_list.end(), std::inserter(by_alias, by_alias.begin())); + for (auto &s : by_alias) { + HandlerPluginPtr mod = _handler_registry.instantiate(s); + _logger->info("Load stream handler plugin: {} {}", s, mod->pluginInterface()); + mod->init_module(_input_manager.get(), _handler_manager.get(), _svr); + _handler_plugins.emplace_back(std::move(mod)); + } } // taps - _tap_manager = std::make_unique(_input_manager.get()); + _tap_manager = std::make_unique(&_input_registry); _setup_routes(prom_config); diff --git a/src/CoreServer.h b/src/CoreServer.h index 0c0115cc9..68d404023 100644 --- a/src/CoreServer.h +++ b/src/CoreServer.h @@ -10,8 +10,6 @@ #include "InputModulePlugin.h" #include "InputStreamManager.h" #include "Taps.h" -#include -#include #include #include #include @@ -26,10 +24,6 @@ struct PrometheusConfig { class CoreServer { - typedef Corrade::PluginManager::Manager InputPluginRegistry; - typedef Corrade::PluginManager::Manager HandlerPluginRegistry; - typedef Corrade::Containers::Pointer InputPluginPtr; - typedef Corrade::Containers::Pointer HandlerPluginPtr; // these hold plugin instances: these are the types of modules available for instantiation InputPluginRegistry _input_registry; @@ -52,7 +46,7 @@ class CoreServer void _setup_routes(const PrometheusConfig &prom_config); public: - CoreServer(bool read_only, std::shared_ptr logger, const PrometheusConfig &prom_config); + CoreServer(bool read_only, const PrometheusConfig &prom_config); ~CoreServer(); void start(const std::string &host, int port); @@ -77,6 +71,10 @@ class CoreServer { return _tap_manager.get(); } + const InputPluginRegistry *input_plugin_registry() const + { + return &_input_registry; + } InputStreamManager *input_manager() { diff --git a/src/HandlerModulePlugin.h b/src/HandlerModulePlugin.h index 9c4ff2f4c..a466037a4 100644 --- a/src/HandlerModulePlugin.h +++ b/src/HandlerModulePlugin.h @@ -7,6 +7,8 @@ #include "AbstractPlugin.h" #include "HandlerManager.h" #include "InputStreamManager.h" +#include +#include #include namespace visor { @@ -35,8 +37,6 @@ class HandlerModulePlugin : public AbstractPlugin { } - virtual std::string name() const = 0; - void init_module(InputStreamManager *im, HandlerManager *hm, HttpServer &svr); @@ -45,5 +45,7 @@ class HandlerModulePlugin : public AbstractPlugin HandlerManager *hm); }; -} +typedef Corrade::PluginManager::Manager HandlerPluginRegistry; +typedef Corrade::Containers::Pointer HandlerPluginPtr; +} diff --git a/src/InputModulePlugin.h b/src/InputModulePlugin.h index 1cec40c34..fbcbb43dc 100644 --- a/src/InputModulePlugin.h +++ b/src/InputModulePlugin.h @@ -6,6 +6,8 @@ #include "AbstractPlugin.h" #include "InputStreamManager.h" +#include +#include #include namespace visor { @@ -34,11 +36,11 @@ class InputModulePlugin : public AbstractPlugin { } - virtual std::string name() const = 0; - void init_module(InputStreamManager *im, HttpServer &svr); void init_module(InputStreamManager *im); }; -} +typedef Corrade::PluginManager::Manager InputPluginRegistry; +typedef Corrade::Containers::Pointer InputPluginPtr; +} diff --git a/src/Taps.cpp b/src/Taps.cpp index acfc91db8..994eb5d55 100644 --- a/src/Taps.cpp +++ b/src/Taps.cpp @@ -3,11 +3,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "Taps.h" +#include #include void visor::TapManager::load(const YAML::Node &tap_yaml) { assert(tap_yaml.IsMap()); + + auto input_plugins = _input_plugin_registry->aliasList(); + for (YAML::const_iterator it = tap_yaml.begin(); it != tap_yaml.end(); ++it) { if (!it->first.IsScalar()) { throw ConfigException("expecting tap identifier"); @@ -21,7 +25,7 @@ void visor::TapManager::load(const YAML::Node &tap_yaml) throw ConfigException("missing or invalid tap input stream 'type'"); } auto tap_type = it->second["type"].as(); - if (!_input_manager->module_exists(tap_type)) { + if (std::find(input_plugins.begin(), input_plugins.end(), tap_type) == input_plugins.end()) { spdlog::get("pktvisor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, tap_type); continue; } diff --git a/src/Taps.h b/src/Taps.h index 9f1236240..ac1d5a635 100644 --- a/src/Taps.h +++ b/src/Taps.h @@ -7,7 +7,7 @@ #include "AbstractManager.h" #include "AbstractModule.h" #include "Configurable.h" -#include "InputStreamManager.h" +#include "InputModulePlugin.h" #include namespace visor { @@ -25,11 +25,11 @@ class Tap : public AbstractModule class TapManager : public AbstractManager { - const InputStreamManager *_input_manager; + const InputPluginRegistry *_input_plugin_registry; public: - TapManager(const InputStreamManager *inputManager) - : _input_manager(inputManager) + TapManager(const InputPluginRegistry *inputManager) + : _input_plugin_registry(inputManager) { } diff --git a/src/handlers/dns/DnsHandler.conf b/src/handlers/dns/DnsHandler.conf index d2ce66614..39036eda5 100644 --- a/src/handlers/dns/DnsHandler.conf +++ b/src/handlers/dns/DnsHandler.conf @@ -1,2 +1,4 @@ +# Aliases +provides=dns [data] desc=DNS analyzer diff --git a/src/handlers/dns/DnsHandlerModulePlugin.h b/src/handlers/dns/DnsHandlerModulePlugin.h index d28d3d8f1..0fa4b743c 100644 --- a/src/handlers/dns/DnsHandlerModulePlugin.h +++ b/src/handlers/dns/DnsHandlerModulePlugin.h @@ -19,11 +19,6 @@ class DnsHandlerModulePlugin : public HandlerModulePlugin : visor::HandlerModulePlugin{manager, plugin} { } - - std::string name() const override - { - return "dns"; - } }; } diff --git a/src/handlers/net/NetHandler.conf b/src/handlers/net/NetHandler.conf index 0c7ecf850..ebfecf878 100644 --- a/src/handlers/net/NetHandler.conf +++ b/src/handlers/net/NetHandler.conf @@ -1,2 +1,4 @@ +# Aliases +provides=net [data] desc=Network (L3-L4) analyzer diff --git a/src/handlers/net/NetHandlerModulePlugin.h b/src/handlers/net/NetHandlerModulePlugin.h index ada3b7e05..e6577a6da 100644 --- a/src/handlers/net/NetHandlerModulePlugin.h +++ b/src/handlers/net/NetHandlerModulePlugin.h @@ -21,10 +21,6 @@ class NetHandlerModulePlugin : public HandlerModulePlugin { } - std::string name() const override - { - return "net"; - } }; } diff --git a/src/inputs/pcap/PcapInput.conf b/src/inputs/pcap/PcapInput.conf index b424b5568..8a3630f85 100644 --- a/src/inputs/pcap/PcapInput.conf +++ b/src/inputs/pcap/PcapInput.conf @@ -1,2 +1,4 @@ +# Aliases +provides=pcap [data] -desc=packet capture stream input (libpcap,DPDK,PF_RING) +desc=packet capture stream input diff --git a/src/inputs/pcap/PcapInputModulePlugin.h b/src/inputs/pcap/PcapInputModulePlugin.h index 4c44f14e4..cd7b4e7f9 100644 --- a/src/inputs/pcap/PcapInputModulePlugin.h +++ b/src/inputs/pcap/PcapInputModulePlugin.h @@ -25,11 +25,6 @@ class PcapInputModulePlugin : public visor::InputModulePlugin : visor::InputModulePlugin{manager, plugin} { } - - std::string name() const override - { - return "pcap"; - } }; } From 9cd66879fa4fc695bfb4d99bfdec417f1736cb7d Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Tue, 20 Apr 2021 16:47:45 -0400 Subject: [PATCH 07/10] explicitly include fmt. add strict taps --- conanfile.txt | 1 + src/CoreServer.cpp | 2 +- src/Taps.cpp | 11 ++++++++--- src/Taps.h | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/conanfile.txt b/conanfile.txt index 9a0b180d5..ed109fc10 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -8,6 +8,7 @@ corrade/2020.06 pcapplusplus/ns1-dev json-schema-validator/2.1.0 yaml-cpp/0.6.3 +fmt/7.1.3 [build_requires] benchmark/1.5.2 diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index a4be80060..4dadc4e06 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -217,6 +217,6 @@ void visor::CoreServer::configure_from_file(const std::string &filename) // taps if (config_file["visor"]["taps"] && config_file["visor"]["taps"].IsMap()) { - _tap_manager->load(config_file["visor"]["taps"]); + _tap_manager->load(config_file["visor"]["taps"], true); } } diff --git a/src/Taps.cpp b/src/Taps.cpp index 994eb5d55..27b4a07bf 100644 --- a/src/Taps.cpp +++ b/src/Taps.cpp @@ -4,9 +4,10 @@ #include "Taps.h" #include +#include #include -void visor::TapManager::load(const YAML::Node &tap_yaml) +void visor::TapManager::load(const YAML::Node &tap_yaml, bool strict) { assert(tap_yaml.IsMap()); @@ -26,8 +27,12 @@ void visor::TapManager::load(const YAML::Node &tap_yaml) } auto tap_type = it->second["type"].as(); if (std::find(input_plugins.begin(), input_plugins.end(), tap_type) == input_plugins.end()) { - spdlog::get("pktvisor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, tap_type); - continue; + if (strict) { + throw ConfigException(fmt::format("Tap '{}' requires input stream type '{}' which is not available", tap_name, tap_type)); + } else { + spdlog::get("pktvisor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, tap_type); + continue; + } } } } diff --git a/src/Taps.h b/src/Taps.h index ac1d5a635..1b201f71b 100644 --- a/src/Taps.h +++ b/src/Taps.h @@ -37,7 +37,7 @@ class TapManager : public AbstractManager { } - void load(const YAML::Node &tap_yaml); + void load(const YAML::Node &tap_yaml, bool strict); }; } \ No newline at end of file From 118257d0a0e3676d70af27305a9464a69e7e57d4 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Tue, 20 Apr 2021 17:44:00 -0400 Subject: [PATCH 08/10] Configurable from yaml --- cmd/pktvisord/main.cpp | 2 +- src/Configurable.h | 31 +++++++++++++++++++++++++++++-- src/Taps.cpp | 11 +++++++++++ src/Taps.h | 4 ++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/cmd/pktvisord/main.cpp b/cmd/pktvisord/main.cpp index 0d12fde79..f6439dc29 100644 --- a/cmd/pktvisord/main.cpp +++ b/cmd/pktvisord/main.cpp @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) // local config file if (args["--config"]) { - logger->info("using config file: {}", args["--config"].asString()); + logger->info("loading config file: {}", args["--config"].asString()); YAML::Node config_file; // look for local options try { diff --git a/src/Configurable.h b/src/Configurable.h index 7c1575801..1983af8eb 100644 --- a/src/Configurable.h +++ b/src/Configurable.h @@ -6,11 +6,14 @@ #include #include +#include #include +#include #include #include #include #include +#include namespace visor { @@ -37,11 +40,11 @@ class Configurable { std::shared_lock lock(_config_mutex); if (_config.count(key) == 0) { - throw ConfigException("missing key: " + key); + throw ConfigException(fmt::format("missing key: {}", key)); } auto val = std::get_if(&_config[key]); if (!val) { - throw ConfigException("wrong type for key: " + key); + throw ConfigException(fmt::format("wrong type for key: {}", key)); } return *val; } @@ -76,6 +79,30 @@ class Configurable value); } } + + void config_set_yaml(const YAML::Node &config_yaml) + { + std::unique_lock lock(_config_mutex); + assert(config_yaml.IsMap()); + for (YAML::const_iterator it = config_yaml.begin(); it != config_yaml.end(); ++it) { + auto key = it->first.as(); + + if (!it->second.IsScalar()) { + throw ConfigException(fmt::format("invalid value for key: {}", key)); + } + + auto value = it->second.as(); + + // the yaml library doesn't discriminate between scalar types, so we have to do that ourselves + if (std::regex_match(value, std::regex("[0-9]+"))) { + _config[key] = it->second.as(); + } else if (std::regex_match(value, std::regex("true|false", std::regex_constants::icase))) { + _config[key] = it->second.as(); + } else { + _config[key] = value; + } + } + } }; } diff --git a/src/Taps.cpp b/src/Taps.cpp index 27b4a07bf..ca8663703 100644 --- a/src/Taps.cpp +++ b/src/Taps.cpp @@ -34,5 +34,16 @@ void visor::TapManager::load(const YAML::Node &tap_yaml, bool strict) continue; } } + + auto tap_module = std::make_unique(tap_name); + + if (it->second["config"]) { + if (!it->second["config"].IsMap()) { + throw ConfigException("tap configuration is not a map"); + } + tap_module->config_set_yaml(it->second["config"]); + } + + module_add(std::move(tap_module)); } } diff --git a/src/Taps.h b/src/Taps.h index 1b201f71b..281cc3e28 100644 --- a/src/Taps.h +++ b/src/Taps.h @@ -20,6 +20,10 @@ class Tap : public AbstractModule : AbstractModule(name) { } + + void info_json(json &j) const override { + AbstractModule::_common_info_json(j); + } }; class TapManager : public AbstractManager From 8e2dcd6c0b12e4f47c0840e05ec3a0ad193fe2f2 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Wed, 21 Apr 2021 09:56:08 -0400 Subject: [PATCH 09/10] switch type to input_type. add taps endpoint to admin api --- RFCs/2021-04-16-75-taps.md | 6 +++--- src/CoreServer.cpp | 16 ++++++++++++++++ src/Taps.cpp | 14 +++++++------- src/Taps.h | 11 ++++++++--- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/RFCs/2021-04-16-75-taps.md b/RFCs/2021-04-16-75-taps.md index 4f4b810e1..dc31338b0 100644 --- a/RFCs/2021-04-16-75-taps.md +++ b/RFCs/2021-04-16-75-taps.md @@ -24,18 +24,18 @@ visor: taps: # a pcap tap which uses eth0 and is referenced by the identifier "anycast" anycast: - type: pcap + input_type: pcap config: iface: eth0 # an sflow tap which listens on the given IP and port, referenced by the identifier "pop_switch" pop_switch: - type: sflow + input_type: sflow config: port: 6343 bind: 192.168.1.1 # a dnstap tap which gets its stream from the given socket, named "trex_tap" trex_tap: - type: dnstap + input_type: dnstap config: socket: /var/dns.sock ``` diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index 4dadc4e06..4b99e905b 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -182,6 +182,22 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) res.set_content(e.what(), "text/plain"); } }); + _svr.Get(R"(/api/v1/taps)", [&](const httplib::Request &req, httplib::Response &res) { + json j; + try { + auto [handler_modules, hm_lock] = _tap_manager->module_get_all_locked(); + for (auto &[name, mod] : handler_modules) { + auto tmod = dynamic_cast(mod.get()); + if (tmod) { + tmod->info_json(j[tmod->name()]); + } + } + res.set_content(j.dump(), "text/json"); + } catch (const std::exception &e) { + res.status = 500; + res.set_content(e.what(), "text/plain"); + } + }); if (!prom_config.path.empty()) { _logger->info("enabling prometheus metrics on: {}", prom_config.path); _svr.Get(prom_config.path.c_str(), [&]([[maybe_unused]] const httplib::Request &req, httplib::Response &res) { diff --git a/src/Taps.cpp b/src/Taps.cpp index ca8663703..30f248be0 100644 --- a/src/Taps.cpp +++ b/src/Taps.cpp @@ -22,20 +22,20 @@ void visor::TapManager::load(const YAML::Node &tap_yaml, bool strict) if (!it->second.IsMap()) { throw ConfigException("expecting tap configuration map"); } - if (!it->second["type"] || !it->second["type"].IsScalar()) { - throw ConfigException("missing or invalid tap input stream 'type'"); + if (!it->second["input_type"] || !it->second["input_type"].IsScalar()) { + throw ConfigException("missing or invalid tap type key 'input_type'"); } - auto tap_type = it->second["type"].as(); - if (std::find(input_plugins.begin(), input_plugins.end(), tap_type) == input_plugins.end()) { + auto input_type = it->second["input_type"].as(); + if (std::find(input_plugins.begin(), input_plugins.end(), input_type) == input_plugins.end()) { if (strict) { - throw ConfigException(fmt::format("Tap '{}' requires input stream type '{}' which is not available", tap_name, tap_type)); + throw ConfigException(fmt::format("Tap '{}' requires input stream type '{}' which is not available", tap_name, input_type)); } else { - spdlog::get("pktvisor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, tap_type); + spdlog::get("pktvisor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, input_type); continue; } } - auto tap_module = std::make_unique(tap_name); + auto tap_module = std::make_unique(tap_name, input_type); if (it->second["config"]) { if (!it->second["config"].IsMap()) { diff --git a/src/Taps.h b/src/Taps.h index 281cc3e28..b7af0b35d 100644 --- a/src/Taps.h +++ b/src/Taps.h @@ -15,14 +15,19 @@ namespace visor { class Tap : public AbstractModule { + std::string _input_type; + public: - Tap(const std::string &name) + Tap(const std::string &name, const std::string &input_type) : AbstractModule(name) + , _input_type(input_type) { } - void info_json(json &j) const override { - AbstractModule::_common_info_json(j); + void info_json(json &j) const override + { + j["input_type"] = _input_type; + config_json(j["config"]); } }; From e7491564b589b1abd65d5b8861161684d36dadbd Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Wed, 21 Apr 2021 12:26:42 -0400 Subject: [PATCH 10/10] refactor CoreManagers out of CoreServer. add unit tests for taps --- cmd/pktvisor-pcap/main.cpp | 63 ++---------- cmd/pktvisord/main.cpp | 14 +-- src/AbstractPlugin.h | 2 +- src/CMakeLists.txt | 4 +- src/CoreManagers.cpp | 100 +++++++++++++++++++ src/CoreManagers.h | 73 ++++++++++++++ src/CoreServer.cpp | 104 +++++--------------- src/CoreServer.h | 60 ++--------- src/HandlerModulePlugin.cpp | 15 +-- src/HandlerModulePlugin.h | 7 +- src/HttpServer.h | 8 +- src/InputModulePlugin.cpp | 13 +-- src/InputModulePlugin.h | 5 +- src/Taps.cpp | 5 +- src/handlers/dns/DnsHandlerModulePlugin.cpp | 10 +- src/handlers/dns/DnsHandlerModulePlugin.h | 2 +- src/handlers/net/NetHandlerModulePlugin.cpp | 10 +- src/handlers/net/NetHandlerModulePlugin.h | 2 +- src/inputs/pcap/PcapInputModulePlugin.cpp | 8 +- src/inputs/pcap/PcapInputModulePlugin.h | 2 +- src/tests/test_taps.cpp | 70 +++++++++++++ 21 files changed, 332 insertions(+), 245 deletions(-) create mode 100644 src/CoreManagers.cpp create mode 100644 src/CoreManagers.h create mode 100644 src/tests/test_taps.cpp diff --git a/cmd/pktvisor-pcap/main.cpp b/cmd/pktvisor-pcap/main.cpp index 1b25bfd99..f1652e629 100644 --- a/cmd/pktvisor-pcap/main.cpp +++ b/cmd/pktvisor-pcap/main.cpp @@ -9,12 +9,7 @@ #include -#include "HandlerManager.h" -#include "HandlerModulePlugin.h" -#include "InputModulePlugin.h" -#include "InputStreamManager.h" -#include -#include +#include "CoreManagers.h" #include #include "handlers/static_plugins.h" @@ -60,10 +55,6 @@ void signal_handler(int signal) using namespace visor; -typedef Corrade::PluginManager::Manager InputPluginRegistry; -typedef Corrade::PluginManager::Manager HandlerPluginRegistry; -typedef Corrade::Containers::Pointer InputPluginPtr; -typedef Corrade::Containers::Pointer HandlerPluginPtr; void initialize_geo(const docopt::value &city, const docopt::value &asn) { @@ -84,48 +75,12 @@ int main(int argc, char *argv[]) true, // show help if requested VISOR_VERSION); // version string - auto logger = spdlog::stderr_color_mt("pktvisor"); + auto logger = spdlog::stderr_color_mt("visor"); if (args["-v"].asBool()) { logger->set_level(spdlog::level::debug); } - // inputs - InputPluginRegistry input_registry; - auto input_manager = std::make_unique(); - std::vector input_plugins; - - // initialize input plugins - for (auto &s : input_registry.pluginList()) { - InputPluginPtr mod = input_registry.instantiate(s); - logger->info("Load input plugin: {} {}", mod->name(), mod->pluginInterface()); - mod->init_module(input_manager.get()); - input_plugins.emplace_back(std::move(mod)); - } - - // handlers - HandlerPluginRegistry handler_registry; - auto handler_manager = std::make_unique(); - std::vector handler_plugins; - - // initialize handler plugins - for (auto &s : handler_registry.pluginList()) { - HandlerPluginPtr mod = handler_registry.instantiate(s); - logger->info("Load handler plugin: {} {}", mod->name(), mod->pluginInterface()); - mod->init_module(input_manager.get(), handler_manager.get()); - handler_plugins.emplace_back(std::move(mod)); - } - - shutdown_handler = [&]([[maybe_unused]] int signal) { - // gracefully close all inputs and handlers - auto [input_modules, im_lock] = input_manager->module_get_all_locked(); - for (auto &[name, mod] : input_modules) { - mod->stop(); - } - auto [handler_modules, hm_lock] = handler_manager->module_get_all_locked(); - for (auto &[name, mod] : handler_modules) { - mod->stop(); - } - }; + CoreManagers mgrs(nullptr); std::signal(SIGINT, signal_handler); std::signal(SIGTERM, signal_handler); @@ -164,8 +119,8 @@ int main(int argc, char *argv[]) input_stream->info_json(j["info"]); logger->info("{}", j.dump(4)); - input_manager->module_add(std::move(input_stream)); - auto [input_stream_, stream_mgr_lock] = input_manager->module_get_locked("pcap"); + mgrs.input_manager()->module_add(std::move(input_stream)); + auto [input_stream_, stream_mgr_lock] = mgrs.input_manager()->module_get_locked("pcap"); stream_mgr_lock.unlock(); auto pcap_stream = dynamic_cast(input_stream_); @@ -174,8 +129,8 @@ int main(int argc, char *argv[]) auto handler_module = std::make_unique("net", pcap_stream, periods, sample_rate); handler_module->config_set("recorded_stream", true); handler_module->start(); - handler_manager->module_add(std::move(handler_module)); - auto [handler, handler_mgr_lock] = handler_manager->module_get_locked("net"); + mgrs.handler_manager()->module_add(std::move(handler_module)); + auto [handler, handler_mgr_lock] = mgrs.handler_manager()->module_get_locked("net"); handler_mgr_lock.unlock(); net_handler = dynamic_cast(handler); } @@ -184,8 +139,8 @@ int main(int argc, char *argv[]) auto handler_module = std::make_unique("dns", pcap_stream, periods, sample_rate); handler_module->config_set("recorded_stream", true); handler_module->start(); - handler_manager->module_add(std::move(handler_module)); - auto [handler, handler_mgr_lock] = handler_manager->module_get_locked("dns"); + mgrs.handler_manager()->module_add(std::move(handler_module)); + auto [handler, handler_mgr_lock] = mgrs.handler_manager()->module_get_locked("dns"); handler_mgr_lock.unlock(); dns_handler = dynamic_cast(handler); } diff --git a/cmd/pktvisord/main.cpp b/cmd/pktvisord/main.cpp index f6439dc29..e999f9033 100644 --- a/cmd/pktvisord/main.cpp +++ b/cmd/pktvisord/main.cpp @@ -168,15 +168,15 @@ int main(int argc, char *argv[]) std::shared_ptr logger; if (args["--log-file"]) { try { - logger = spdlog::basic_logger_mt("pktvisor", args["--log-file"].asString()); + logger = spdlog::basic_logger_mt("visor", args["--log-file"].asString()); } catch (const spdlog::spdlog_ex &ex) { std::cerr << "Log init failed: " << ex.what() << std::endl; exit(EXIT_FAILURE); } } else if (args["--syslog"].asBool()) { - logger = spdlog::syslog_logger_mt("pktvisor", "pktvisord", LOG_PID); + logger = spdlog::syslog_logger_mt("visor", "pktvisord", LOG_PID); } else { - logger = spdlog::stdout_color_mt("pktvisor"); + logger = spdlog::stdout_color_mt("visor"); } if (args["-v"].asBool()) { logger->set_level(spdlog::level::debug); @@ -220,8 +220,8 @@ int main(int argc, char *argv[]) } } - // then pass to CoreServer - svr.configure_from_file(args["--config"].asString()); + // then pass to CoreManagers + svr.mgrs()->configure_from_file(args["--config"].asString()); } catch (std::runtime_error &e) { logger->error("configuration error: {}", e.what()); @@ -297,8 +297,8 @@ int main(int argc, char *argv[]) input_stream->config_set("bpf", bpf); input_stream->config_set("host_spec", host_spec); - auto input_manager = svr.input_manager(); - auto handler_manager = svr.handler_manager(); + auto input_manager = svr.mgrs()->input_manager(); + auto handler_manager = svr.mgrs()->handler_manager(); input_stream->start(); input_manager->module_add(std::move(input_stream)); diff --git a/src/AbstractPlugin.h b/src/AbstractPlugin.h index f99386c48..66f184394 100644 --- a/src/AbstractPlugin.h +++ b/src/AbstractPlugin.h @@ -32,7 +32,7 @@ class AbstractPlugin : public Corrade::PluginManager::AbstractPlugin protected: void _check_schema(json obj, SchemaMap &required); void _check_schema(json obj, SchemaMap &required, SchemaMap &optional); - virtual void _setup_routes(HttpServer &svr) = 0; + virtual void _setup_routes(HttpServer *svr) = 0; public: static std::vector pluginSearchPaths() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 733600b85..3bc7092c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(visor-core HandlerModulePlugin.cpp GeoDB.cpp CoreServer.cpp + CoreManagers.cpp Metrics.cpp Taps.cpp) add_library(Visor::Core ALIAS visor-core) @@ -48,13 +49,14 @@ add_executable(unit-tests-vizor-core tests/test_sketches.cpp tests/test_metrics.cpp tests/test_geoip.cpp + tests/test_taps.cpp ) target_include_directories(unit-tests-vizor-core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ) -target_link_libraries(unit-tests-vizor-core PRIVATE Visor::Core) +target_link_libraries(unit-tests-vizor-core PRIVATE Visor::Core ${VISOR_STATIC_PLUGINS}) add_test(NAME unit-tests-vizor-core WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src diff --git a/src/CoreManagers.cpp b/src/CoreManagers.cpp new file mode 100644 index 000000000..41c244052 --- /dev/null +++ b/src/CoreManagers.cpp @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "CoreManagers.h" +#include +#include + +namespace visor { + +CoreManagers::CoreManagers(HttpServer *svr) + : _svr(svr) +{ + + _logger = spdlog::get("visor"); + if (!_logger) { + _logger = spdlog::stderr_color_mt("visor"); + } + + if (!svr) { + _logger->warn("initializing modules with no HttpServer"); + } + + // inputs + _input_manager = std::make_unique(); + + // initialize input plugins + { + auto alias_list = _input_registry.aliasList(); + auto plugin_list = _input_registry.pluginList(); + std::vector by_alias; + std::set_difference(alias_list.begin(), alias_list.end(), + plugin_list.begin(), plugin_list.end(), std::inserter(by_alias, by_alias.begin())); + for (auto &s : by_alias) { + InputPluginPtr mod = _input_registry.instantiate(s); + _logger->info("Load input stream plugin: {} {}", s, mod->pluginInterface()); + mod->init_module(_input_manager.get(), _svr); + _input_plugins.emplace_back(std::move(mod)); + } + } + + // handlers + _handler_manager = std::make_unique(); + + // initialize handler plugins + { + auto alias_list = _handler_registry.aliasList(); + auto plugin_list = _handler_registry.pluginList(); + std::vector by_alias; + std::set_difference(alias_list.begin(), alias_list.end(), + plugin_list.begin(), plugin_list.end(), std::inserter(by_alias, by_alias.begin())); + for (auto &s : by_alias) { + HandlerPluginPtr mod = _handler_registry.instantiate(s); + _logger->info("Load stream handler plugin: {} {}", s, mod->pluginInterface()); + mod->init_module(_input_manager.get(), _handler_manager.get(), _svr); + _handler_plugins.emplace_back(std::move(mod)); + } + } + + // taps + _tap_manager = std::make_unique(&_input_registry); +} + +visor::CoreManagers::~CoreManagers() +{ + // gracefully close all inputs and handlers + auto [input_modules, im_lock] = _input_manager->module_get_all_locked(); + for (auto &[name, mod] : input_modules) { + if (mod->running()) { + _logger->info("Stopping input instance: {}", mod->name()); + mod->stop(); + } + } + auto [handler_modules, hm_lock] = _handler_manager->module_get_all_locked(); + for (auto &[name, mod] : handler_modules) { + if (mod->running()) { + _logger->info("Stopping handler instance: {}", mod->name()); + mod->stop(); + } + } +} + +void visor::CoreManagers::configure_from_file(const std::string &filename) +{ + YAML::Node config_file = YAML::LoadFile(filename); + + if (!config_file.IsMap() || !config_file["visor"]) { + throw ConfigException("invalid schema"); + } + if (!config_file["version"] || !config_file["version"].IsScalar() || config_file["version"].as() != "1.0") { + throw ConfigException("missing or unsupported version"); + } + + // taps + if (config_file["visor"]["taps"] && config_file["visor"]["taps"].IsMap()) { + _tap_manager->load(config_file["visor"]["taps"], true); + } +} + +} \ No newline at end of file diff --git a/src/CoreManagers.h b/src/CoreManagers.h new file mode 100644 index 000000000..a8cf4d453 --- /dev/null +++ b/src/CoreManagers.h @@ -0,0 +1,73 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "HandlerModulePlugin.h" +#include "InputModulePlugin.h" +#include "Taps.h" +#include + +namespace visor { + +class CoreManagers +{ + + // these hold plugin instances: these are the types of modules available for instantiation + InputPluginRegistry _input_registry; + std::vector _input_plugins; + + HandlerPluginRegistry _handler_registry; + std::vector _handler_plugins; + + // these hold instances of active modules + std::unique_ptr _input_manager; + std::unique_ptr _handler_manager; + + std::unique_ptr _tap_manager; + + std::shared_ptr _logger; + HttpServer *_svr; + +public: + CoreManagers(HttpServer *svr); + ~CoreManagers(); + + void configure_from_file(const std::string &filename); + + [[nodiscard]] const InputStreamManager *input_manager() const + { + return _input_manager.get(); + } + [[nodiscard]] const HandlerManager *handler_manager() const + { + return _handler_manager.get(); + } + [[nodiscard]] const TapManager *tap_manager() const + { + return _tap_manager.get(); + } + [[nodiscard]] const InputPluginRegistry *input_plugin_registry() const + { + return &_input_registry; + } + + [[nodiscard]] InputStreamManager *input_manager() + { + return _input_manager.get(); + } + + [[nodiscard]] HandlerManager *handler_manager() + { + return _handler_manager.get(); + } + + [[nodiscard]] TapManager *tap_manager() + { + return _tap_manager.get(); + } + +}; + +} \ No newline at end of file diff --git a/src/CoreServer.cpp b/src/CoreServer.cpp index 4b99e905b..9f8037b4a 100644 --- a/src/CoreServer.cpp +++ b/src/CoreServer.cpp @@ -6,63 +6,32 @@ #include "Metrics.h" #include "visor_config.h" #include +#include +#include #include #include -visor::CoreServer::CoreServer(bool read_only, const PrometheusConfig &prom_config) +namespace visor { + +CoreServer::CoreServer(bool read_only, const PrometheusConfig &prom_config) : _svr(read_only) + , _mgrs(&_svr) , _start_time(std::chrono::system_clock::now()) { - _logger = spdlog::get("pktvisor"); - assert(_logger); - - // inputs - _input_manager = std::make_unique(); - - // initialize input plugins - { - auto alias_list = _input_registry.aliasList(); - auto plugin_list = _input_registry.pluginList(); - std::vector by_alias; - std::set_difference(alias_list.begin(), alias_list.end(), - plugin_list.begin(), plugin_list.end(), std::inserter(by_alias, by_alias.begin())); - for (auto &s : by_alias) { - InputPluginPtr mod = _input_registry.instantiate(s); - _logger->info("Load input stream plugin: {} {}", s, mod->pluginInterface()); - mod->init_module(_input_manager.get(), _svr); - _input_plugins.emplace_back(std::move(mod)); - } - } - - // handlers - _handler_manager = std::make_unique(); - - // initialize handler plugins - { - auto alias_list = _handler_registry.aliasList(); - auto plugin_list = _handler_registry.pluginList(); - std::vector by_alias; - std::set_difference(alias_list.begin(), alias_list.end(), - plugin_list.begin(), plugin_list.end(), std::inserter(by_alias, by_alias.begin())); - for (auto &s : by_alias) { - HandlerPluginPtr mod = _handler_registry.instantiate(s); - _logger->info("Load stream handler plugin: {} {}", s, mod->pluginInterface()); - mod->init_module(_input_manager.get(), _handler_manager.get(), _svr); - _handler_plugins.emplace_back(std::move(mod)); - } + _logger = spdlog::get("visor"); + if (!_logger) { + _logger = spdlog::stderr_color_mt("visor"); } - // taps - _tap_manager = std::make_unique(&_input_registry); - _setup_routes(prom_config); if (!prom_config.instance.empty()) { Metric::add_base_label("instance", prom_config.instance); } } -void visor::CoreServer::start(const std::string &host, int port) + +void CoreServer::start(const std::string &host, int port) { if (!_svr.bind_to_port(host.c_str(), port)) { throw std::runtime_error("unable to bind host/port"); @@ -72,31 +41,18 @@ void visor::CoreServer::start(const std::string &host, int port) throw std::runtime_error("error during listen"); } } -void visor::CoreServer::stop() + +void CoreServer::stop() { _svr.stop(); - - // gracefully close all inputs and handlers - auto [input_modules, im_lock] = _input_manager->module_get_all_locked(); - for (auto &[name, mod] : input_modules) { - if (mod->running()) { - _logger->info("Stopping input instance: {}", mod->name()); - mod->stop(); - } - } - auto [handler_modules, hm_lock] = _handler_manager->module_get_all_locked(); - for (auto &[name, mod] : handler_modules) { - if (mod->running()) { - _logger->info("Stopping handler instance: {}", mod->name()); - mod->stop(); - } - } } -visor::CoreServer::~CoreServer() + +CoreServer::~CoreServer() { stop(); } -void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) + +void CoreServer::_setup_routes(const PrometheusConfig &prom_config) { _logger->info("Initialize server control plane"); @@ -140,7 +96,7 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) bool bc_period{false}; try { uint64_t period(std::stol(req.matches[1])); - auto [handler_modules, hm_lock] = _handler_manager->module_get_all_locked(); + auto [handler_modules, hm_lock] = _mgrs.handler_manager()->module_get_all_locked(); for (auto &[name, mod] : handler_modules) { auto hmod = dynamic_cast(mod.get()); // TODO need to add policy name, break backwards compatible since multiple otherwise policies will overwrite @@ -166,7 +122,7 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) json j; try { uint64_t period(std::stol(req.matches[1])); - auto [handler_modules, hm_lock] = _handler_manager->module_get_all_locked(); + auto [handler_modules, hm_lock] = _mgrs.handler_manager()->module_get_all_locked(); for (auto &[name, mod] : handler_modules) { auto hmod = dynamic_cast(mod.get()); // TODO need to add policy name, break backwards compatible since multiple otherwise policies will overwrite @@ -182,10 +138,10 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) res.set_content(e.what(), "text/plain"); } }); - _svr.Get(R"(/api/v1/taps)", [&](const httplib::Request &req, httplib::Response &res) { + _svr.Get(R"(/api/v1/taps)", [&]([[maybe_unused]] const httplib::Request &req, httplib::Response &res) { json j; try { - auto [handler_modules, hm_lock] = _tap_manager->module_get_all_locked(); + auto [handler_modules, hm_lock] = _mgrs.tap_manager()->module_get_all_locked(); for (auto &[name, mod] : handler_modules) { auto tmod = dynamic_cast(mod.get()); if (tmod) { @@ -203,7 +159,7 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) _svr.Get(prom_config.path.c_str(), [&]([[maybe_unused]] const httplib::Request &req, httplib::Response &res) { std::stringstream output; try { - auto [handler_modules, hm_lock] = _handler_manager->module_get_all_locked(); + auto [handler_modules, hm_lock] = _mgrs.handler_manager()->module_get_all_locked(); for (auto &[name, mod] : handler_modules) { auto hmod = dynamic_cast(mod.get()); if (hmod) { @@ -220,19 +176,5 @@ void visor::CoreServer::_setup_routes(const PrometheusConfig &prom_config) }); } } -void visor::CoreServer::configure_from_file(const std::string &filename) -{ - YAML::Node config_file = YAML::LoadFile(filename); - - if (!config_file.IsMap() || !config_file["visor"]) { - throw ConfigException("invalid schema"); - } - if (!config_file["version"] || !config_file["version"].IsScalar() || config_file["version"].as() != "1.0") { - throw ConfigException("missing or unsupported version"); - } - // taps - if (config_file["visor"]["taps"] && config_file["visor"]["taps"].IsMap()) { - _tap_manager->load(config_file["visor"]["taps"], true); - } -} +} \ No newline at end of file diff --git a/src/CoreServer.h b/src/CoreServer.h index 68d404023..6bd099810 100644 --- a/src/CoreServer.h +++ b/src/CoreServer.h @@ -4,16 +4,10 @@ #pragma once -#include "HandlerManager.h" -#include "HandlerModulePlugin.h" +#include "CoreManagers.h" #include "HttpServer.h" -#include "InputModulePlugin.h" -#include "InputStreamManager.h" -#include "Taps.h" -#include -#include +#include #include -#include namespace visor { @@ -25,20 +19,8 @@ struct PrometheusConfig { class CoreServer { - // these hold plugin instances: these are the types of modules available for instantiation - InputPluginRegistry _input_registry; - std::vector _input_plugins; - - HandlerPluginRegistry _handler_registry; - std::vector _handler_plugins; - - visor::HttpServer _svr; - - // these hold instances of active modules - std::unique_ptr _input_manager; - std::unique_ptr _handler_manager; - - std::unique_ptr _tap_manager; + HttpServer _svr; + CoreManagers _mgrs; std::shared_ptr _logger; std::chrono::system_clock::time_point _start_time; @@ -52,41 +34,19 @@ class CoreServer void start(const std::string &host, int port); void stop(); - void configure_from_file(const std::string &filename); - - void set_http_logger(httplib::Logger logger) + const CoreManagers *mgrs() const { - _svr.set_logger(logger); + return &_mgrs; } - const InputStreamManager *input_manager() const + CoreManagers *mgrs() { - return _input_manager.get(); - } - const HandlerManager *handler_manager() const - { - return _handler_manager.get(); - } - const TapManager *tap_manager() const - { - return _tap_manager.get(); - } - const InputPluginRegistry *input_plugin_registry() const - { - return &_input_registry; + return &_mgrs; } - InputStreamManager *input_manager() - { - return _input_manager.get(); - } - HandlerManager *handler_manager() - { - return _handler_manager.get(); - } - TapManager *tap_manager() + void set_http_logger(httplib::Logger logger) { - return _tap_manager.get(); + _svr.set_logger(logger); } }; diff --git a/src/HandlerModulePlugin.cpp b/src/HandlerModulePlugin.cpp index 8859c0d3f..d1609a427 100644 --- a/src/HandlerModulePlugin.cpp +++ b/src/HandlerModulePlugin.cpp @@ -3,26 +3,19 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "HandlerModulePlugin.h" -#include -#include namespace visor { void HandlerModulePlugin::init_module(InputStreamManager *im, - HandlerManager *hm, HttpServer &svr) -{ - assert(hm); - assert(im); - _input_manager = im; - _handler_manager = hm; - _setup_routes(svr); -} -void HandlerModulePlugin::init_module(InputStreamManager *im, HandlerManager *hm) + HandlerManager *hm, HttpServer *svr) { assert(hm); assert(im); _input_manager = im; _handler_manager = hm; + if (svr) { + _setup_routes(svr); + } } } diff --git a/src/HandlerModulePlugin.h b/src/HandlerModulePlugin.h index a466037a4..ec7e0f282 100644 --- a/src/HandlerModulePlugin.h +++ b/src/HandlerModulePlugin.h @@ -19,7 +19,7 @@ class HandlerModulePlugin : public AbstractPlugin visor::InputStreamManager *_input_manager; visor::HandlerManager *_handler_manager; - virtual void _setup_routes(HttpServer &svr) = 0; + virtual void _setup_routes(HttpServer *svr) = 0; public: static std::string pluginInterface() @@ -39,10 +39,7 @@ class HandlerModulePlugin : public AbstractPlugin void init_module(InputStreamManager *im, HandlerManager *hm, - HttpServer &svr); - - void init_module(InputStreamManager *im, - HandlerManager *hm); + HttpServer *svr); }; typedef Corrade::PluginManager::Manager HandlerPluginRegistry; diff --git a/src/HttpServer.h b/src/HttpServer.h index b890818da..e6e22635d 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -20,7 +20,7 @@ class HttpServer : public httplib::Server Server &Get(const char *pattern, Handler handler) { - spdlog::get("pktvisor")->info("Registering GET {}", pattern); + spdlog::get("visor")->info("Registering GET {}", pattern); return httplib::Server::Get(pattern, handler); } Server &Post(const char *pattern, Handler handler) @@ -28,7 +28,7 @@ class HttpServer : public httplib::Server if (_read_only) { return *this; } - spdlog::get("pktvisor")->info("Registering POST {}", pattern); + spdlog::get("visor")->info("Registering POST {}", pattern); return httplib::Server::Post(pattern, handler); } Server &Put(const char *pattern, Handler handler) @@ -36,7 +36,7 @@ class HttpServer : public httplib::Server if (_read_only) { return *this; } - spdlog::get("pktvisor")->info("Registering PUT {}", pattern); + spdlog::get("visor")->info("Registering PUT {}", pattern); return httplib::Server::Put(pattern, handler); } Server &Delete(const char *pattern, Handler handler) @@ -44,7 +44,7 @@ class HttpServer : public httplib::Server if (_read_only) { return *this; } - spdlog::get("pktvisor")->info("Registering DELETE {}", pattern); + spdlog::get("visor")->info("Registering DELETE {}", pattern); return httplib::Server::Delete(pattern, handler); } }; diff --git a/src/InputModulePlugin.cpp b/src/InputModulePlugin.cpp index 3b571c788..6a232957d 100644 --- a/src/InputModulePlugin.cpp +++ b/src/InputModulePlugin.cpp @@ -3,21 +3,16 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "InputModulePlugin.h" -#include -#include namespace visor { -void InputModulePlugin::init_module(InputStreamManager *im, HttpServer &svr) -{ - assert(im); - _input_manager = im; - _setup_routes(svr); -} -void InputModulePlugin::init_module(InputStreamManager *im) +void InputModulePlugin::init_module(InputStreamManager *im, HttpServer *svr) { assert(im); _input_manager = im; + if (svr) { + _setup_routes(svr); + } } } diff --git a/src/InputModulePlugin.h b/src/InputModulePlugin.h index fbcbb43dc..32772d33b 100644 --- a/src/InputModulePlugin.h +++ b/src/InputModulePlugin.h @@ -18,7 +18,7 @@ class InputModulePlugin : public AbstractPlugin protected: InputStreamManager *_input_manager; - virtual void _setup_routes(HttpServer &svr) = 0; + virtual void _setup_routes(HttpServer *svr) = 0; public: static std::string pluginInterface() @@ -36,8 +36,7 @@ class InputModulePlugin : public AbstractPlugin { } - void init_module(InputStreamManager *im, HttpServer &svr); - void init_module(InputStreamManager *im); + void init_module(InputStreamManager *im, HttpServer *svr); }; typedef Corrade::PluginManager::Manager InputPluginRegistry; diff --git a/src/Taps.cpp b/src/Taps.cpp index 30f248be0..f76d476fc 100644 --- a/src/Taps.cpp +++ b/src/Taps.cpp @@ -10,6 +10,7 @@ void visor::TapManager::load(const YAML::Node &tap_yaml, bool strict) { assert(tap_yaml.IsMap()); + assert(spdlog::get("visor")); auto input_plugins = _input_plugin_registry->aliasList(); @@ -18,7 +19,7 @@ void visor::TapManager::load(const YAML::Node &tap_yaml, bool strict) throw ConfigException("expecting tap identifier"); } auto tap_name = it->first.as(); - spdlog::get("pktvisor")->info("loading Tap: {}", tap_name); + spdlog::get("visor")->info("loading Tap: {}", tap_name); if (!it->second.IsMap()) { throw ConfigException("expecting tap configuration map"); } @@ -30,7 +31,7 @@ void visor::TapManager::load(const YAML::Node &tap_yaml, bool strict) if (strict) { throw ConfigException(fmt::format("Tap '{}' requires input stream type '{}' which is not available", tap_name, input_type)); } else { - spdlog::get("pktvisor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, input_type); + spdlog::get("visor")->warn("Tap '{}' requires input stream type '{}' which is not available; skipping", tap_name, input_type); continue; } } diff --git a/src/handlers/dns/DnsHandlerModulePlugin.cpp b/src/handlers/dns/DnsHandlerModulePlugin.cpp index 183020262..cce45f903 100644 --- a/src/handlers/dns/DnsHandlerModulePlugin.cpp +++ b/src/handlers/dns/DnsHandlerModulePlugin.cpp @@ -16,10 +16,10 @@ namespace visor::handler::dns { using namespace visor::input::pcap; using json = nlohmann::json; -void DnsHandlerModulePlugin::_setup_routes(HttpServer &svr) +void DnsHandlerModulePlugin::_setup_routes(HttpServer *svr) { // CREATE - svr.Post("/api/v1/inputs/pcap/(\\w+)/handlers/dns", [this](const httplib::Request &req, httplib::Response &res) { + svr->Post("/api/v1/inputs/pcap/(\\w+)/handlers/dns", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto body = json::parse(req.body); @@ -84,7 +84,7 @@ void DnsHandlerModulePlugin::_setup_routes(HttpServer &svr) res.set_content(result.dump(), "text/json"); } }); - svr.Get("/api/v1/inputs/pcap/(\\w+)/handlers/dns/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { + svr->Get("/api/v1/inputs/pcap/(\\w+)/handlers/dns/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto input_name = req.matches[1]; @@ -117,7 +117,7 @@ void DnsHandlerModulePlugin::_setup_routes(HttpServer &svr) res.set_content(result.dump(), "text/json"); } }); - svr.Get("/api/v1/inputs/pcap/(\\w+)/handlers/dns/(\\w+)/bucket/(\\d+)", [this](const httplib::Request &req, httplib::Response &res) { + svr->Get("/api/v1/inputs/pcap/(\\w+)/handlers/dns/(\\w+)/bucket/(\\d+)", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto input_name = req.matches[1]; @@ -151,7 +151,7 @@ void DnsHandlerModulePlugin::_setup_routes(HttpServer &svr) } }); // DELETE - svr.Delete("/api/v1/inputs/pcap/(\\w+)/handlers/dns/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { + svr->Delete("/api/v1/inputs/pcap/(\\w+)/handlers/dns/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto input_name = req.matches[1]; diff --git a/src/handlers/dns/DnsHandlerModulePlugin.h b/src/handlers/dns/DnsHandlerModulePlugin.h index 0fa4b743c..8ed03d48c 100644 --- a/src/handlers/dns/DnsHandlerModulePlugin.h +++ b/src/handlers/dns/DnsHandlerModulePlugin.h @@ -12,7 +12,7 @@ class DnsHandlerModulePlugin : public HandlerModulePlugin { protected: - void _setup_routes(HttpServer &svr) override; + void _setup_routes(HttpServer *svr) override; public: explicit DnsHandlerModulePlugin(Corrade::PluginManager::AbstractManager &manager, const std::string &plugin) diff --git a/src/handlers/net/NetHandlerModulePlugin.cpp b/src/handlers/net/NetHandlerModulePlugin.cpp index 0a3f73aff..a781ae2e9 100644 --- a/src/handlers/net/NetHandlerModulePlugin.cpp +++ b/src/handlers/net/NetHandlerModulePlugin.cpp @@ -16,10 +16,10 @@ namespace visor::handler::net { using namespace visor::input::pcap; using json = nlohmann::json; -void NetHandlerModulePlugin::_setup_routes(HttpServer &svr) +void NetHandlerModulePlugin::_setup_routes(HttpServer *svr) { // CREATE - svr.Post("/api/v1/inputs/pcap/(\\w+)/handlers/net", [this](const httplib::Request &req, httplib::Response &res) { + svr->Post("/api/v1/inputs/pcap/(\\w+)/handlers/net", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto body = json::parse(req.body); @@ -85,7 +85,7 @@ void NetHandlerModulePlugin::_setup_routes(HttpServer &svr) res.set_content(result.dump(), "text/json"); } }); - svr.Get("/api/v1/inputs/pcap/(\\w+)/handlers/net/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { + svr->Get("/api/v1/inputs/pcap/(\\w+)/handlers/net/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto input_name = req.matches[1]; @@ -119,7 +119,7 @@ void NetHandlerModulePlugin::_setup_routes(HttpServer &svr) res.set_content(result.dump(), "text/json"); } }); - svr.Get("/api/v1/inputs/pcap/(\\w+)/handlers/net/(\\w+)/bucket/(\\d+)", [this](const httplib::Request &req, httplib::Response &res) { + svr->Get("/api/v1/inputs/pcap/(\\w+)/handlers/net/(\\w+)/bucket/(\\d+)", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto input_name = req.matches[1]; @@ -154,7 +154,7 @@ void NetHandlerModulePlugin::_setup_routes(HttpServer &svr) } }); // DELETE - svr.Delete("/api/v1/inputs/pcap/(\\w+)/handlers/net/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { + svr->Delete("/api/v1/inputs/pcap/(\\w+)/handlers/net/(\\w+)", [this](const httplib::Request &req, httplib::Response &res) { json result; try { auto input_name = req.matches[1]; diff --git a/src/handlers/net/NetHandlerModulePlugin.h b/src/handlers/net/NetHandlerModulePlugin.h index e6577a6da..94baa7e0c 100644 --- a/src/handlers/net/NetHandlerModulePlugin.h +++ b/src/handlers/net/NetHandlerModulePlugin.h @@ -13,7 +13,7 @@ class NetHandlerModulePlugin : public HandlerModulePlugin { protected: - void _setup_routes(HttpServer &svr) override; + void _setup_routes(HttpServer *svr) override; public: explicit NetHandlerModulePlugin(Corrade::PluginManager::AbstractManager &manager, const std::string &plugin) diff --git a/src/inputs/pcap/PcapInputModulePlugin.cpp b/src/inputs/pcap/PcapInputModulePlugin.cpp index 945c0c987..4d2b53d0a 100644 --- a/src/inputs/pcap/PcapInputModulePlugin.cpp +++ b/src/inputs/pcap/PcapInputModulePlugin.cpp @@ -11,17 +11,17 @@ CORRADE_PLUGIN_REGISTER(VisorInputPcap, visor::input::pcap::PcapInputModulePlugi namespace visor::input::pcap { -void PcapInputModulePlugin::_setup_routes(HttpServer &svr) +void PcapInputModulePlugin::_setup_routes(HttpServer *svr) { // CREATE - svr.Post("/api/v1/inputs/pcap", std::bind(&PcapInputModulePlugin::_create, this, std::placeholders::_1, std::placeholders::_2)); + svr->Post("/api/v1/inputs/pcap", std::bind(&PcapInputModulePlugin::_create, this, std::placeholders::_1, std::placeholders::_2)); // DELETE - svr.Delete("/api/v1/inputs/pcap/(\\w+)", std::bind(&PcapInputModulePlugin::_delete, this, std::placeholders::_1, std::placeholders::_2)); + svr->Delete("/api/v1/inputs/pcap/(\\w+)", std::bind(&PcapInputModulePlugin::_delete, this, std::placeholders::_1, std::placeholders::_2)); // GET - svr.Get("/api/v1/inputs/pcap/(\\w+)", std::bind(&PcapInputModulePlugin::_read, this, std::placeholders::_1, std::placeholders::_2)); + svr->Get("/api/v1/inputs/pcap/(\\w+)", std::bind(&PcapInputModulePlugin::_read, this, std::placeholders::_1, std::placeholders::_2)); } void PcapInputModulePlugin::_create(const httplib::Request &req, httplib::Response &res) diff --git a/src/inputs/pcap/PcapInputModulePlugin.h b/src/inputs/pcap/PcapInputModulePlugin.h index cd7b4e7f9..fe62b9fa6 100644 --- a/src/inputs/pcap/PcapInputModulePlugin.h +++ b/src/inputs/pcap/PcapInputModulePlugin.h @@ -14,7 +14,7 @@ class PcapInputModulePlugin : public visor::InputModulePlugin { protected: - void _setup_routes(HttpServer &svr) override; + void _setup_routes(HttpServer *svr) override; void _create(const httplib::Request &req, httplib::Response &res); void _read(const httplib::Request &req, httplib::Response &res); diff --git a/src/tests/test_taps.cpp b/src/tests/test_taps.cpp new file mode 100644 index 000000000..69fae2844 --- /dev/null +++ b/src/tests/test_taps.cpp @@ -0,0 +1,70 @@ +#include "CoreManagers.h" +#include "InputModulePlugin.h" +#include "inputs/static_plugins.h" +#include +#include +#include + +using namespace visor; + +auto sample_config = R"( +version: "1.0" + +visor: + config: + verbose: true + taps: + wired: + input_type: pcap + config: + iface: en7 + number: 123 + boolean: true + wireless: + input_type: pcap + config: + iface: en0 +)"; + +auto sample_config_bad = R"( +version: "1.0" + +visor: + config: + verbose: true + taps: + wired: + input_type: nonexistent + config: + iface: en7 +)"; + +TEST_CASE("Taps", "[taps]") +{ + + SECTION("Good Config") + { + CoreManagers mgrs(nullptr); + YAML::Node config_file = YAML::Load(sample_config); + + CHECK(config_file["visor"]["taps"]); + CHECK(config_file["visor"]["taps"].IsMap()); + CHECK_NOTHROW(mgrs.tap_manager()->load(config_file["visor"]["taps"], true)); + + auto [tap, lock] = mgrs.tap_manager()->module_get_locked("wired"); + CHECK(tap->name() == "wired"); + CHECK(tap->config_get("iface") == "en7"); + CHECK(tap->config_get("number") == 123); + CHECK(tap->config_get("boolean") == true); + } + + SECTION("Bad Config") + { + CoreManagers mgrs(nullptr); + YAML::Node config_file = YAML::Load(sample_config_bad); + + CHECK(config_file["visor"]["taps"]); + CHECK(config_file["visor"]["taps"].IsMap()); + CHECK_THROWS(mgrs.tap_manager()->load(config_file["visor"]["taps"], true)); + } +}