stephb9959
2023-03-08 09:32:14 -08:00
parent c5e63ce95b
commit 7ad4de4960
3 changed files with 150 additions and 92 deletions

View File

@@ -2,8 +2,8 @@
// Created by stephane bourque on 2021-09-14.
//
#include <iostream>
#include <fstream>
#include <iostream>
#include <regex>
#include "ConfigurationValidator.h"
@@ -17,14 +17,15 @@
#include "fmt/format.h"
#include <valijson/adapters/poco_json_adapter.hpp>
#include <valijson/utils/poco_json_utils.hpp>
#include <valijson/constraints/constraint.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/utils/poco_json_utils.hpp>
#include <valijson/validator.hpp>
#include <valijson/constraints/constraint.hpp>
static const std::string GitUCentralJSONSchemaFile{
"https://raw.githubusercontent.com/Telecominfraproject/wlan-ucentral-schema/main/ucentral.schema.json"};
"https://raw.githubusercontent.com/Telecominfraproject/wlan-ucentral-schema/main/"
"ucentral.schema.json"};
static std::string DefaultUCentralSchema = R"foo(
@@ -3091,6 +3092,20 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"metrics.wifi-scan": {
"type": "object",
"properties": {
"interval": {
"type": "integer"
},
"verbose": {
"type": "boolean"
},
"information-elements": {
"type": "boolean"
}
}
},
"metrics.telemetry": {
"type": "object",
"properties": {
@@ -3100,7 +3115,22 @@ static std::string DefaultUCentralSchema = R"foo(
"types": {
"type": "array",
"items": {
"type": "string"
"type": "string",
"enum": [
"ssh",
"health",
"health.dns",
"health.dhcp",
"health.radius",
"health.memory",
"client",
"client.join",
"client.leave",
"client.key-mismatch",
"wifi",
"wifi.start",
"wifi.stop"
]
}
}
}
@@ -3111,7 +3141,22 @@ static std::string DefaultUCentralSchema = R"foo(
"types": {
"type": "array",
"items": {
"type": "string"
"type": "string",
"enum": [
"ssh",
"health",
"health.dns",
"health.dhcp",
"health.radius",
"health.memory",
"client",
"client.join",
"client.leave",
"client.key-mismatch",
"wifi",
"wifi.start",
"wifi.stop"
]
}
}
}
@@ -3131,6 +3176,9 @@ static std::string DefaultUCentralSchema = R"foo(
"dhcp-snooping": {
"$ref": "#/$defs/metrics.dhcp-snooping"
},
"wifi-scan": {
"$ref": "#/$defs/metrics.wifi-scan"
},
"telemetry": {
"$ref": "#/$defs/metrics.telemetry"
},
@@ -3184,7 +3232,6 @@ static std::string DefaultUCentralSchema = R"foo(
)foo";
static inline bool IsIPv4(const std::string &value) {
Poco::Net::IPAddress A;
return ((Poco::Net::IPAddress::tryParse(value, A) && A.family() == Poco::Net::IPAddress::IPv4));
@@ -3242,57 +3289,68 @@ bool ExternalValijsonFormatChecker(const std::string &format, const std::string
if (format == "uc-cidr4") {
if (IsCIDRv4(value))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid CIDR IPv4 block",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid CIDR IPv4 block", value));
} else if (format == "uc-cidr6") {
if (IsCIDRv6(value))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid CIDR IPv6 block",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid CIDR IPv6 block", value));
} else if (format == "uc-cidr") {
if (IsCIDR(value))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid CIDR block",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid CIDR block", value));
} else if (format == "uc-mac") {
if (std::regex_match(value, mac_regex))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid MAC address",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid MAC address", value));
} else if (format == "uc-timeout") {
if (std::regex_match(value, uc_timeout_regex))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid timeout value",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid timeout value", value));
} else if (format == "uc-host") {
if (IsIP(value))
return true;
if (std::regex_match(value, host_regex))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid hostname",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid hostname", value));
} else if (format == "fqdn" || format == "uc-fqdn") {
if (std::regex_match(value, host_regex))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid FQDN",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid FQDN", value));
} else if (format == "uc-base64") {
std::string s{value};
Poco::trimInPlace(s);
if ((s.size() % 4 == 0) && std::regex_match(s, b64_regex))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid base 64 value",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid base 64 value", value));
} else if (format == "uri") {
try {
Poco::URI uri(value);
return true;
} catch (...) {
}
if(results) results->pushError(context,fmt::format("{} is not a valid URL",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid URL", value));
} else if (format == "uc-portrange") {
try {
if (IsPortRangeIsValid(value))
return true;
} catch (...) {
}
if(results) results->pushError(context,fmt::format("{} is not a valid post range",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid post range", value));
} else if (format == "ip") {
if (IsIP(value))
return true;
if(results) results->pushError(context,fmt::format("{} is not a valid IP address",value));
if (results)
results->pushError(context, fmt::format("{} is not a valid IP address", value));
}
return true;
}
@@ -3304,9 +3362,7 @@ namespace OpenWifi {
return 0;
}
void ConfigurationValidator::Stop() {
}
void ConfigurationValidator::Stop() {}
bool ConfigurationValidator::SetSchema(const std::string &SchemaStr) {
try {
@@ -3318,9 +3374,9 @@ namespace OpenWifi {
SchemaParser_->populateSchema(*PocoJsonAdapter_, *RootSchema_);
Initialized_ = Working_ = true;
return true;
} catch(const Poco::Exception &E) {
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch(...) {
} catch (...) {
Logger().error("Validation schema is invalid, falling back.");
}
return false;
@@ -3331,7 +3387,7 @@ namespace OpenWifi {
return;
std::string GitSchema;
if(MicroServiceConfigGetBool("ucentral.datamodel.internal",true)) {
if (MicroServiceConfigGetBool("ucentral.datamodel.internal", true)) {
SetSchema(DefaultUCentralSchema);
poco_information(Logger(), "Using uCentral validation from built-in default.");
return;
@@ -3339,34 +3395,35 @@ namespace OpenWifi {
try {
auto GitURI =
MicroServiceConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile);
if(Utils::wgets(GitURI, GitSchema) && SetSchema(GitSchema)) {
poco_information(Logger(),"Using uCentral data model validation schema from GIT.");
MicroServiceConfigGetString("ucentral.datamodel.uri", GitUCentralJSONSchemaFile);
if (Utils::wgets(GitURI, GitSchema) && SetSchema(GitSchema)) {
poco_information(Logger(), "Using uCentral data model validation schema from GIT.");
return;
} else {
std::string FileName{MicroServiceDataDirectory() + "/ucentral.schema.json"};
std::ifstream input(FileName);
std::stringstream schema_file;
schema_file << input.rdbuf();
input.close();
if (SetSchema(schema_file.str())) {
poco_information(
Logger(), "Using uCentral data model validation schema from local file.");
return;
} else {
std::string FileName{ MicroServiceDataDirectory() + "/ucentral.schema.json" };
std::ifstream input(FileName);
std::stringstream schema_file;
schema_file << input.rdbuf();
input.close();
if(SetSchema(schema_file.str())) {
poco_information(Logger(),
"Using uCentral data model validation schema from local file.");
return;
}
}
}
} catch (const Poco::Exception &E) {
} catch (...) {
}
SetSchema(DefaultUCentralSchema);
poco_information(Logger(),"Using uCentral data model validation schema from built-in default.");
poco_information(Logger(),
"Using uCentral data model validation schema from built-in default.");
}
bool ConfigurationValidator::Validate(const std::string &C, std::vector<std::string> &Errors, bool Strict) {
if(Working_) {
try {
bool ConfigurationValidator::Validate(const std::string &C, std::vector<std::string> &Errors,
bool Strict) {
if (Working_) {
try {
Poco::JSON::Parser P;
auto Doc = P.parse(C).extract<Poco::JSON::Object::Ptr>();
valijson::adapters::PocoJsonAdapter Tester(Doc);
@@ -3375,27 +3432,28 @@ namespace OpenWifi {
if (Validator.validate(*RootSchema_, Tester, &Results)) {
return true;
}
for(const auto &error:Results) {
for (const auto &error : Results) {
Errors.push_back(error.description);
}
return false;
} catch(const Poco::Exception &E) {
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch(const std::exception &E) {
Logger().warning(fmt::format("Error wile validating a configuration (1): {}", E.what()));
} catch(...) {
} catch (const std::exception &E) {
Logger().warning(
fmt::format("Error wile validating a configuration (1): {}", E.what()));
} catch (...) {
Logger().warning("Error wile validating a configuration (2)");
}
}
if(Strict)
}
}
if (Strict)
return false;
return true;
}
return true;
}
void ConfigurationValidator::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
poco_information(Logger(),"Reinitializing.");
Working_ = Initialized_ = false;
Init();
}
void ConfigurationValidator::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
poco_information(Logger(), "Reinitializing.");
Working_ = Initialized_ = false;
Init();
}
}
} // namespace OpenWifi