#include "configuration.hpp" #include "../utils.hpp" #include "perform_probe.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace configuration { // writes output files to persist data bool writeJsonFiles(const nlohmann::json& systemConfiguration) { std::filesystem::create_directory(configurationOutDir); std::ofstream output(currentConfiguration); if (!output.good()) { return false; } output << systemConfiguration.dump(4); output.close(); return true; } // reads json files out of the filesystem bool loadConfigurations(std::list& configurations) { // find configuration files std::vector jsonPaths; if (!findFiles( std::vector{configurationDirectory, hostConfigurationDirectory}, R"(.*\.json)", jsonPaths)) { std::cerr << "Unable to find any configuration files in " << configurationDirectory << "\n"; return false; } std::ifstream schemaStream( std::string(schemaDirectory) + "/" + globalSchema); if (!schemaStream.good()) { std::cerr << "Cannot open schema file, cannot validate JSON, exiting\n\n"; std::exit(EXIT_FAILURE); return false; } nlohmann::json schema = nlohmann::json::parse(schemaStream, nullptr, false, true); if (schema.is_discarded()) { std::cerr << "Illegal schema file detected, cannot validate JSON, exiting\n"; std::exit(EXIT_FAILURE); return false; } for (auto& jsonPath : jsonPaths) { std::ifstream jsonStream(jsonPath.c_str()); if (!jsonStream.good()) { std::cerr << "unable to open " << jsonPath.string() << "\n"; continue; } auto data = nlohmann::json::parse(jsonStream, nullptr, false, true); if (data.is_discarded()) { std::cerr << "syntax error in " << jsonPath.string() << "\n"; continue; } /* * todo(james): reenable this once less things are in flight * if (!validateJson(schema, data)) { std::cerr << "Error validating " << jsonPath.string() << "\n"; continue; } */ if (data.type() == nlohmann::json::value_t::array) { for (auto& d : data) { configurations.emplace_back(d); } } else { configurations.emplace_back(data); } } return true; } // Iterate over new configuration and erase items from old configuration. void deriveNewConfiguration(const nlohmann::json& oldConfiguration, nlohmann::json& newConfiguration) { for (auto it = newConfiguration.begin(); it != newConfiguration.end();) { auto findKey = oldConfiguration.find(it.key()); if (findKey != oldConfiguration.end()) { it = newConfiguration.erase(it); } else { it++; } } } // validates a given input(configuration) with a given json schema file. bool validateJson(const nlohmann::json& schemaFile, const nlohmann::json& input) { valijson::Schema schema; valijson::SchemaParser parser; valijson::adapters::NlohmannJsonAdapter schemaAdapter(schemaFile); parser.populateSchema(schemaAdapter, schema); valijson::Validator validator; valijson::adapters::NlohmannJsonAdapter targetAdapter(input); return validator.validate(schema, targetAdapter, nullptr); } // Extract the D-Bus interfaces to probe from the JSON config files. std::set getProbeInterfaces() { std::set interfaces; std::list configurations; if (!configuration::loadConfigurations(configurations)) { return interfaces; } for (auto it = configurations.begin(); it != configurations.end();) { auto findProbe = it->find("Probe"); if (findProbe == it->end()) { std::cerr << "configuration file missing probe:\n " << *it << "\n"; it++; continue; } nlohmann::json probeCommand; if ((*findProbe).type() != nlohmann::json::value_t::array) { probeCommand = nlohmann::json::array(); probeCommand.push_back(*findProbe); } else { probeCommand = *findProbe; } for (const nlohmann::json& probeJson : probeCommand) { const std::string* probe = probeJson.get_ptr(); if (probe == nullptr) { std::cerr << "Probe statement wasn't a string, can't parse"; continue; } // Skip it if the probe cmd doesn't contain an interface. if (probe::findProbeType(*probe)) { continue; } // syntax requires probe before first open brace auto findStart = probe->find('('); if (findStart != std::string::npos) { std::string interface = probe->substr(0, findStart); interfaces.emplace(interface); } } it++; } return interfaces; } } // namespace configuration