TEST_F(DecoratorsConfigParserPluginTests, test_decorators_run_interval) { // Prevent loads from executing. FLAGS_disable_decorators = true; Config::getInstance().update(config_data_); // Mimic the schedule's execution. FLAGS_disable_decorators = false; runDecorators(DECORATE_INTERVAL, 60); QueryLogItem item; getDecorations(item.decorations); ASSERT_EQ(item.decorations.size(), 2U); EXPECT_EQ(item.decorations.at("internal_60_test"), "test"); std::string log_line; serializeQueryLogItemJSON(item, log_line); std::string expected = "{\"snapshot\":\"\",\"action\":\"snapshot\",\"decorations\":{\"internal_" "60_test\":\"test\",\"one\":\"1\"},\"name\":\"\",\"hostIdentifier\":\"\"," "\"calendarTime\":\"\",\"unixTime\":\"0\"}\n"; EXPECT_EQ(log_line, expected); // Now clear and run again. clearDecorations("awesome"); runDecorators(DECORATE_INTERVAL, 60 * 60); QueryLogItem second_item; getDecorations(second_item.decorations); ASSERT_EQ(second_item.decorations.size(), 2U); }
TEST_F(DecoratorsConfigParserPluginTests, test_decorators_run_load) { // Re-enable the decorators, then update the config. // The 'load' decorator set should run every time the config is updated. FLAGS_disable_decorators = false; Config::getInstance().update(config_data_); QueryLogItem item; getDecorations(item.decorations); ASSERT_EQ(item.decorations.size(), 3U); EXPECT_EQ(item.decorations["load_test"], "test"); }
TEST_F(DecoratorsConfigParserPluginTests, test_decorators_list) { // Assume the decorators are disabled. Config::getInstance().update(config_data_); auto parser = Config::getParser("decorators"); EXPECT_NE(parser, nullptr); // Expect the decorators to be disabled by default. QueryLogItem item; getDecorations(item.decorations); EXPECT_EQ(item.decorations.size(), 0U); }
Status BufferedLogForwarder::logStatus(const std::vector<StatusLogLine>& log, size_t time) { // Append decorations to status // Assemble a decorations tree to append to each status buffer line. pt::ptree dtree; std::map<std::string, std::string> decorations; getDecorations(decorations); for (const auto& decoration : decorations) { dtree.put(decoration.first, decoration.second); } for (const auto& item : log) { // Convert the StatusLogLine into ptree format, to convert to JSON. pt::ptree buffer; buffer.put("severity", (google::LogSeverity)item.severity); buffer.put("filename", item.filename); buffer.put("line", item.line); buffer.put("message", item.message); buffer.put("version", kVersion); if (decorations.size() > 0) { buffer.put_child("decorations", dtree); } // Convert to JSON, for storing a string-representation in the database. std::string json; try { std::stringstream json_output; pt::write_json(json_output, buffer, false); json = json_output.str(); } catch (const pt::json_parser::json_parser_error& e) { // The log could not be represented as JSON. return Status(1, e.what()); } // Store the status line in a backing store. if (!json.empty()) { json.pop_back(); } std::string index = genStatusIndex(time); Status status = addValueWithCount(kLogs, index, json); if (!status.ok()) { // Do not continue if any line fails. return status; } } return Status(0); }
inline void launchQuery(const std::string& name, const ScheduledQuery& query) { // Execute the scheduled query and create a named query object. LOG(INFO) << "Executing scheduled query " << name << ": " << query.query; runDecorators(DECORATE_ALWAYS); auto sql = monitor(name, query); if (!sql.ok()) { LOG(ERROR) << "Error executing scheduled query " << name << ": " << sql.getMessageString(); return; } // Fill in a host identifier fields based on configuration or availability. std::string ident = getHostIdentifier(); // A query log item contains an optional set of differential results or // a copy of the most-recent execution alongside some query metadata. QueryLogItem item; item.name = name; item.identifier = ident; item.time = osquery::getUnixTime(); item.epoch = FLAGS_schedule_epoch; item.calendar_time = osquery::getAsciiTime(); getDecorations(item.decorations); if (query.options.count("snapshot") && query.options.at("snapshot")) { // This is a snapshot query, emit results with a differential or state. item.snapshot_results = std::move(sql.rows()); logSnapshotQuery(item); return; } // Create a database-backed set of query results. auto dbQuery = Query(name, query); // Comparisons and stores must include escaped data. sql.escapeResults(); Status status; DiffResults diff_results; // Add this execution's set of results to the database-tracked named query. // We can then ask for a differential from the last time this named query // was executed by exact matching each row. if (!FLAGS_events_optimize || !sql.eventBased()) { status = dbQuery.addNewResults( sql.rows(), item.epoch, item.counter, diff_results); if (!status.ok()) { std::string line = "Error adding new results to database: " + status.what(); LOG(ERROR) << line; // If the database is not available then the daemon cannot continue. Initializer::requestShutdown(EXIT_CATASTROPHIC, line); } } else { diff_results.added = std::move(sql.rows()); } if (diff_results.added.empty() && diff_results.removed.empty()) { // No diff results or events to emit. return; } VLOG(1) << "Found results for query: " << name; item.results = diff_results; if (query.options.count("removed") && !query.options.at("removed")) { item.results.removed.clear(); } status = logQueryLogItem(item); if (!status.ok()) { // If log directory is not available, then the daemon shouldn't continue. std::string error = "Error logging the results of query: " + name + ": " + status.toString(); LOG(ERROR) << error; Initializer::requestShutdown(EXIT_CATASTROPHIC, error); } }