refactor(userspace/engine): uniform json lib in rules description and not print from engine

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
Jason Dellaluce
2023-11-20 14:48:43 +00:00
committed by poiana
parent 95968defa5
commit e3943ccac3
5 changed files with 86 additions and 88 deletions

View File

@@ -505,17 +505,17 @@ std::size_t falco_engine::add_source(const std::string &source,
return m_sources.insert(src, source); return m_sources.insert(src, source);
} }
template <typename T> inline Json::Value sequence_to_json_array(const T& seq) template <typename T> inline nlohmann::json sequence_to_json_array(const T& seq)
{ {
Json::Value ret = Json::arrayValue; nlohmann::json ret = nlohmann::json::array();
for (auto it = seq.begin(); it != seq.end(); it++) for (auto it = seq.begin(); it != seq.end(); it++)
{ {
ret.append(*it); ret.push_back(*it);
} }
return ret; return ret;
} }
void falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const nlohmann::json falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{ {
// use previously-loaded collector definitions and the compiled // use previously-loaded collector definitions and the compiled
// output of rules, macros, and lists. // output of rules, macros, and lists.
@@ -524,103 +524,69 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
throw falco_exception("rules most be loaded before describing them"); throw falco_exception("rules most be loaded before describing them");
} }
if(!json)
{
static const char *rule_fmt = "%-50s %s\n";
fprintf(stdout, rule_fmt, "Rule", "Description");
fprintf(stdout, rule_fmt, "----", "-----------");
if(!rule)
{
for(auto &r : m_rules)
{
auto str = falco::utils::wrap_text(r.description, 51, 110) + "\n";
fprintf(stdout, rule_fmt, r.name.c_str(), str.c_str());
}
}
else
{
auto r = m_rules.at(*rule);
if(r == nullptr)
{
return;
}
auto str = falco::utils::wrap_text(r->description, 51, 110) + "\n";
fprintf(stdout, rule_fmt, r->name.c_str(), str.c_str());
}
return;
}
// use collected and compiled info to print a json output // use collected and compiled info to print a json output
Json::FastWriter writer; nlohmann::json output;
std::string json_str;
if(!rule) if(!rule)
{ {
// In this case we build json information about
// all rules, macros and lists
Json::Value output;
// Store required engine version // Store required engine version
auto required_engine_version = m_rule_collector.required_engine_version(); auto required_engine_version = m_rule_collector.required_engine_version();
output["required_engine_version"] = required_engine_version.version.as_string(); output["required_engine_version"] = required_engine_version.version.as_string();
// Store required plugin versions // Store required plugin versions
Json::Value plugin_versions = Json::arrayValue; nlohmann::json plugin_versions = nlohmann::json::array();
auto required_plugin_versions = m_rule_collector.required_plugin_versions(); auto required_plugin_versions = m_rule_collector.required_plugin_versions();
for(const auto& req : required_plugin_versions) for(const auto& req : required_plugin_versions)
{ {
Json::Value r; nlohmann::json r;
r["name"] = req.at(0).name; r["name"] = req.at(0).name;
r["version"] = req.at(0).version; r["version"] = req.at(0).version;
Json::Value alternatives = Json::arrayValue; nlohmann::json alternatives = nlohmann::json::array();
for(size_t i = 1; i < req.size(); i++) for(size_t i = 1; i < req.size(); i++)
{ {
Json::Value alternative; nlohmann::json alternative;
alternative["name"] = req[i].name; alternative["name"] = req[i].name;
alternative["version"] = req[i].version; alternative["version"] = req[i].version;
alternatives.append(alternative); alternatives.push_back(alternative);
} }
r["alternatives"] = alternatives; r["alternatives"] = alternatives;
plugin_versions.append(r); plugin_versions.push_back(r);
} }
output["required_plugin_versions"] = plugin_versions; output["required_plugin_versions"] = plugin_versions;
// Store information about rules // Store information about rules
Json::Value rules_array = Json::arrayValue; nlohmann::json rules_array = nlohmann::json::array();
for(const auto& r : m_last_compile_output->rules) for(const auto& r : m_last_compile_output->rules)
{ {
auto info = m_rule_collector.rules().at(r.name); auto info = m_rule_collector.rules().at(r.name);
Json::Value rule; nlohmann::json rule;
get_json_details(rule, r, *info, plugins); get_json_details(rule, r, *info, plugins);
rules_array.append(rule); rules_array.push_back(rule);
} }
output["rules"] = rules_array; output["rules"] = rules_array;
// Store information about macros // Store information about macros
Json::Value macros_array = Json::arrayValue; nlohmann::json macros_array = nlohmann::json::array();
for(const auto &m : m_last_compile_output->macros) for(const auto &m : m_last_compile_output->macros)
{ {
auto info = m_rule_collector.macros().at(m.name); auto info = m_rule_collector.macros().at(m.name);
Json::Value macro; nlohmann::json macro;
get_json_details(macro, m, *info, plugins); get_json_details(macro, m, *info, plugins);
macros_array.append(macro); macros_array.push_back(macro);
} }
output["macros"] = macros_array; output["macros"] = macros_array;
// Store information about lists // Store information about lists
Json::Value lists_array = Json::arrayValue; nlohmann::json lists_array = nlohmann::json::array();
for(const auto &l : m_last_compile_output->lists) for(const auto &l : m_last_compile_output->lists)
{ {
auto info = m_rule_collector.lists().at(l.name); auto info = m_rule_collector.lists().at(l.name);
Json::Value list; nlohmann::json list;
get_json_details(list, l, *info, plugins); get_json_details(list, l, *info, plugins);
lists_array.append(list); lists_array.push_back(list);
} }
output["lists"] = lists_array; output["lists"] = lists_array;
json_str = writer.write(output);
} }
else else
{ {
@@ -631,21 +597,24 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
throw falco_exception("Rule \"" + *rule + "\" is not loaded"); throw falco_exception("Rule \"" + *rule + "\" is not loaded");
} }
auto r = m_rules.at(ri->name); auto r = m_rules.at(ri->name);
Json::Value rule;
nlohmann::json rule;
get_json_details(rule, *r, *ri, plugins); get_json_details(rule, *r, *ri, plugins);
json_str = writer.write(rule); nlohmann::json rules_array = nlohmann::json::array();
rules_array.push_back(rule);
output["rules"] = rules_array;
} }
fprintf(stdout, "%s", json_str.c_str()); return output;
} }
void falco_engine::get_json_details( void falco_engine::get_json_details(
Json::Value &out, nlohmann::json &out,
const falco_rule &r, const falco_rule &r,
const rule_loader::rule_info &info, const rule_loader::rule_info &info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{ {
Json::Value rule_info; nlohmann::json rule_info;
// Fill general rule information // Fill general rule information
rule_info["name"] = r.name; rule_info["name"] = r.name;
@@ -665,7 +634,7 @@ void falco_engine::get_json_details(
// get details related to the condition's filter // get details related to the condition's filter
filter_details details; filter_details details;
filter_details compiled_details; filter_details compiled_details;
Json::Value json_details; nlohmann::json json_details;
for(const auto &m : m_rule_collector.macros()) for(const auto &m : m_rule_collector.macros())
{ {
details.known_macros.insert(m.name); details.known_macros.insert(m.name);
@@ -726,7 +695,7 @@ void falco_engine::get_json_details(
out["details"]["exception_operators"] = sequence_to_json_array(exception_operators); out["details"]["exception_operators"] = sequence_to_json_array(exception_operators);
// Store event types // Store event types
Json::Value events; nlohmann::json events;
get_json_evt_types(events, info.source, r.condition.get()); get_json_evt_types(events, info.source, r.condition.get());
out["details"]["events"] = events; out["details"]["events"] = events;
@@ -739,7 +708,7 @@ void falco_engine::get_json_details(
// - The fields used in the rule's condition, output, and exceptions // - The fields used in the rule's condition, output, and exceptions
// - The evt types used in the rule's condition checks, that can potentially // - The evt types used in the rule's condition checks, that can potentially
// match plugin-provided async events // match plugin-provided async events
Json::Value used_plugins; nlohmann::json used_plugins;
// note: making a union of conditions's and output's fields // note: making a union of conditions's and output's fields
// note: the condition's AST accounts for all the resolved refs and exceptions // note: the condition's AST accounts for all the resolved refs and exceptions
compiled_details.fields.insert(out_fields.begin(), out_fields.end()); compiled_details.fields.insert(out_fields.begin(), out_fields.end());
@@ -748,12 +717,12 @@ void falco_engine::get_json_details(
} }
void falco_engine::get_json_details( void falco_engine::get_json_details(
Json::Value& out, nlohmann::json& out,
const falco_macro& m, const falco_macro& m,
const rule_loader::macro_info& info, const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{ {
Json::Value macro_info; nlohmann::json macro_info;
macro_info["name"] = m.name; macro_info["name"] = m.name;
macro_info["condition"] = info.cond; macro_info["condition"] = info.cond;
@@ -766,7 +735,7 @@ void falco_engine::get_json_details(
// get details related to the condition's filter // get details related to the condition's filter
filter_details details; filter_details details;
filter_details compiled_details; filter_details compiled_details;
Json::Value json_details; nlohmann::json json_details;
for(const auto &m : m_rule_collector.macros()) for(const auto &m : m_rule_collector.macros())
{ {
details.known_macros.insert(m.name); details.known_macros.insert(m.name);
@@ -787,7 +756,7 @@ void falco_engine::get_json_details(
out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields); out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields);
// Store event types // Store event types
Json::Value events; nlohmann::json events;
get_json_evt_types(events, "", m.condition.get()); get_json_evt_types(events, "", m.condition.get());
out["details"]["events"] = events; out["details"]["events"] = events;
@@ -800,20 +769,20 @@ void falco_engine::get_json_details(
// if a macro uses a plugin's field, we can't be sure which plugin actually // if a macro uses a plugin's field, we can't be sure which plugin actually
// is used until we resolve the macro ref in a rule providing a source for // is used until we resolve the macro ref in a rule providing a source for
// disambiguation. // disambiguation.
out["details"]["plugins"] = Json::arrayValue; out["details"]["plugins"] = nlohmann::json::array();
} }
void falco_engine::get_json_details( void falco_engine::get_json_details(
Json::Value& out, nlohmann::json& out,
const falco_list& l, const falco_list& l,
const rule_loader::list_info& info, const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{ {
Json::Value list_info; nlohmann::json list_info;
list_info["name"] = l.name; list_info["name"] = l.name;
// note: the syntactic definitions still has the list refs unresolved // note: the syntactic definitions still has the list refs unresolved
Json::Value items = Json::arrayValue; nlohmann::json items = nlohmann::json::array();
std::unordered_set<std::string> lists; std::unordered_set<std::string> lists;
for(const auto &i : info.items) for(const auto &i : info.items)
{ {
@@ -825,7 +794,7 @@ void falco_engine::get_json_details(
lists.insert(i); lists.insert(i);
continue; continue;
} }
items.append(i); items.push_back(i);
} }
list_info["items"] = items; list_info["items"] = items;
@@ -833,11 +802,11 @@ void falco_engine::get_json_details(
out["details"]["used"] = l.used; out["details"]["used"] = l.used;
out["details"]["lists"] = sequence_to_json_array(lists); out["details"]["lists"] = sequence_to_json_array(lists);
out["details"]["items_compiled"] = sequence_to_json_array(l.items); out["details"]["items_compiled"] = sequence_to_json_array(l.items);
out["details"]["plugins"] = Json::arrayValue; // always empty out["details"]["plugins"] = nlohmann::json::array(); // always empty
} }
void falco_engine::get_json_evt_types( void falco_engine::get_json_evt_types(
Json::Value& out, nlohmann::json& out,
const std::string& source, const std::string& source,
libsinsp::filter::ast::expr* ast) const libsinsp::filter::ast::expr* ast) const
{ {
@@ -860,7 +829,7 @@ void falco_engine::get_json_evt_types(
} }
void falco_engine::get_json_used_plugins( void falco_engine::get_json_used_plugins(
Json::Value& out, nlohmann::json& out,
const std::string& source, const std::string& source,
const std::unordered_set<std::string>& evtnames, const std::unordered_set<std::string>& evtnames,
const std::unordered_set<std::string>& fields, const std::unordered_set<std::string>& fields,

View File

@@ -136,7 +136,7 @@ public:
// Print details on the given rule. If rule is NULL, print // Print details on the given rule. If rule is NULL, print
// details on all rules. // details on all rules.
// //
void describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const; nlohmann::json describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
// //
// Print statistics on how many events matched each rule. // Print statistics on how many events matched each rule.
@@ -315,26 +315,26 @@ private:
// Retrieve json details from rules, macros, lists // Retrieve json details from rules, macros, lists
void get_json_details( void get_json_details(
Json::Value& out, nlohmann::json& out,
const falco_rule& r, const falco_rule& r,
const rule_loader::rule_info& info, const rule_loader::rule_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const; const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details( void get_json_details(
Json::Value& out, nlohmann::json& out,
const falco_macro& m, const falco_macro& m,
const rule_loader::macro_info& info, const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const; const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details( void get_json_details(
Json::Value& out, nlohmann::json& out,
const falco_list& l, const falco_list& l,
const rule_loader::list_info& info, const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const; const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_evt_types( void get_json_evt_types(
Json::Value& out, nlohmann::json& out,
const std::string& source, const std::string& source,
libsinsp::filter::ast::expr* ast) const; libsinsp::filter::ast::expr* ast) const;
void get_json_used_plugins( void get_json_used_plugins(
Json::Value& out, nlohmann::json& out,
const std::string& source, const std::string& source,
const std::unordered_set<std::string>& evttypes, const std::unordered_set<std::string>& evttypes,
const std::unordered_set<std::string>& fields, const std::unordered_set<std::string>& fields,

View File

@@ -20,6 +20,8 @@ limitations under the License.
#include "../state.h" #include "../state.h"
#include "../run_result.h" #include "../run_result.h"
#include <nlohmann/json.hpp>
namespace falco { namespace falco {
namespace app { namespace app {
namespace actions { namespace actions {
@@ -29,6 +31,8 @@ void print_enabled_event_sources(falco::app::state& s);
void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr<sinsp>& inspector); void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr<sinsp>& inspector);
void check_for_ignored_events(falco::app::state& s); void check_for_ignored_events(falco::app::state& s);
void format_plugin_info(std::shared_ptr<sinsp_plugin> p, std::ostream& os); void format_plugin_info(std::shared_ptr<sinsp_plugin> p, std::ostream& os);
void format_described_rules_as_text(const nlohmann::json& v, std::ostream& os);
falco::app::run_result open_offline_inspector(falco::app::state& s); falco::app::run_result open_offline_inspector(falco::app::state& s);
falco::app::run_result open_live_inspector( falco::app::run_result open_live_inspector(
falco::app::state& s, falco::app::state& s,

View File

@@ -16,6 +16,7 @@ limitations under the License.
*/ */
#include "helpers.h" #include "helpers.h"
#include "falco_utils.h"
#include <plugin_manager.h> #include <plugin_manager.h>
#include <unordered_set> #include <unordered_set>
@@ -126,3 +127,22 @@ void falco::app::actions::format_plugin_info(std::shared_ptr<sinsp_plugin> p, st
os << " - Async Events" << std::endl; os << " - Async Events" << std::endl;
} }
} }
static void format_two_columns(std::ostream& os, const std::string& l, const std::string& r)
{
static constexpr const int s_max_line_len = 4096;
char buf[s_max_line_len];
snprintf(buf, sizeof(buf) - 1, "%-50s %s", l.c_str(), r.c_str());
os << buf << std::endl;
}
void falco::app::actions::format_described_rules_as_text(const nlohmann::json& v, std::ostream& os)
{
format_two_columns(os, "Rule", "Description");
format_two_columns(os, "----", "-----------");
for(const auto &r : v["rules"])
{
auto str = falco::utils::wrap_text(r["info"]["description"], 51, 110) + "\n";
format_two_columns(os, r["info"]["name"], str);
}
}

View File

@@ -155,17 +155,22 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
s.engine->enable_rule_by_tag(s.options.enabled_rule_tags, true); s.engine->enable_rule_by_tag(s.options.enabled_rule_tags, true);
} }
if (s.options.describe_all_rules) // printout of `-L` option
if (s.options.describe_all_rules || !s.options.describe_rule.empty())
{ {
std::string* rptr = !s.options.describe_rule.empty() ? &(s.options.describe_rule) : nullptr;
const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins(); const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins();
s.engine->describe_rule(NULL, plugins, s.config->m_json_output); auto out = s.engine->describe_rule(rptr, plugins);
return run_result::exit();
if (!s.config->m_json_output)
{
format_described_rules_as_text(out, std::cout);
}
else
{
std::cout << out.dump() << std::endl;
} }
if (!s.options.describe_rule.empty())
{
const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins();
s.engine->describe_rule(&(s.options.describe_rule), plugins, s.config->m_json_output);
return run_result::exit(); return run_result::exit();
} }