if (!rotation_method.IsEmpty() && rotation_method != "HOURLY" && rotation_method != "DAILY" &&
rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") {
- ConfigCompilerContext::GetInstance()->AddError(false, "Validation failed for " +
+ ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Rotation method '" + rotation_method + "' is invalid.");
}
}
ConfigCompiler::CompileText(name, fragment);
}
- bool hasError = false;
-
- BOOST_FOREACH(const ConfigCompilerError& error, ConfigCompilerContext::GetInstance()->GetErrors()) {
- if (!error.Warning) {
- hasError = true;
- break;
- }
- }
-
- /* Don't link or validate if we have already encountered at least one error. */
- if (!hasError) {
- ConfigItem::LinkItems();
- ConfigItem::ValidateItems();
- }
-
- hasError = false;
-
- BOOST_FOREACH(const ConfigCompilerError& error, ConfigCompilerContext::GetInstance()->GetErrors()) {
- if (error.Warning) {
- Log(LogWarning, "icinga-app", "Config warning: " + error.Message);
- } else {
- hasError = true;
- Log(LogCritical, "icinga-app", "Config error: " + error.Message);
- }
- }
-
- if (hasError)
- return false;
-
- if (validateOnly)
- return true;
-
- if (Application::GetInstance()) {
- Log(LogCritical, "icinga-app", "You must not manually create an Application object.");
- return false;
- }
-
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>();
builder->SetType(Application::GetApplicationType());
builder->SetName("application");
ConfigItem::Ptr item = builder->Compile();
item->Register();
- ConfigItem::ActivateItems();
+ bool result = ConfigItem::ActivateItems(validateOnly);
+
+ BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
+ if (message.Error)
+ Log(LogCritical, "config", "Config error: " + message.Text);
+ else
+ Log(LogWarning, "config", "Config warning: " + message.Text);
+ }
+
+ if (!result)
+ return false;
ConfigItem::DiscardItems();
ConfigType::DiscardTypes();
{
std::ostringstream msgbuf;
msgbuf << "Unterminated string found: " << *yylloc;
- ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str());
BEGIN(INITIAL);
}
YY_BREAK
/* error, constant is out-of-bounds */
std::ostringstream msgbuf;
msgbuf << "Constant is out-of-bounds: " << yytext << " " << *yylloc;
- ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str());
}
lb_append_char(&string_buf, result);
*/
std::ostringstream msgbuf;
msgbuf << "Bad escape sequence found: " << yytext << " " << *yylloc;
- ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str());
}
YY_BREAK
case 6:
<STRING>\n {
std::ostringstream msgbuf;
msgbuf << "Unterminated string found: " << *yylloc;
- ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str());
BEGIN(INITIAL);
}
/* error, constant is out-of-bounds */
std::ostringstream msgbuf;
msgbuf << "Constant is out-of-bounds: " << yytext << " " << *yylloc;
- ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str());
}
lb_append_char(&string_buf, result);
*/
std::ostringstream msgbuf;
msgbuf << "Bad escape sequence found: " << yytext << " " << *yylloc;
- ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str());
}
<STRING>\\n { lb_append_char(&string_buf, '\n'); }
{
std::ostringstream message;
message << *locp << ": " << err;
- ConfigCompilerContext::GetInstance()->AddError(false, message.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
}
int yyparse(ConfigCompiler *context);
try {
yyparse(this);
} catch (const std::exception& ex) {
- ConfigCompilerContext::GetInstance()->AddError(false, boost::diagnostic_information(ex));
+ ConfigCompilerContext::GetInstance()->AddMessage(true, boost::diagnostic_information(ex));
}
}
{
std::ostringstream message;
message << *locp << ": " << err;
- ConfigCompilerContext::GetInstance()->AddError(false, message.str());
+ ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
}
int yyparse(ConfigCompiler *context);
try {
yyparse(this);
} catch (const std::exception& ex) {
- ConfigCompilerContext::GetInstance()->AddError(false, boost::diagnostic_information(ex));
+ ConfigCompilerContext::GetInstance()->AddMessage(true, boost::diagnostic_information(ex));
}
}
using namespace icinga;
-void ConfigCompilerContext::AddError(bool warning, const String& message)
+void ConfigCompilerContext::AddMessage(bool error, const String& message)
{
- m_Errors.push_back(ConfigCompilerError(warning, message));
+ m_Messages.push_back(ConfigCompilerMessage(error, message));
}
-std::vector<ConfigCompilerError> ConfigCompilerContext::GetErrors(void) const
+std::vector<ConfigCompilerMessage> ConfigCompilerContext::GetMessages(void) const
{
- return m_Errors;
+ return m_Messages;
+}
+
+bool ConfigCompilerContext::HasErrors(void) const
+{
+ BOOST_FOREACH(const ConfigCompilerMessage& message, m_Messages) {
+ if (message.Error)
+ return true;
+ }
+
+ return false;
}
void ConfigCompilerContext::Reset(void)
{
- m_Errors.clear();
+ m_Messages.clear();
}
ConfigCompilerContext *ConfigCompilerContext::GetInstance(void)
namespace icinga
{
-struct I2_CONFIG_API ConfigCompilerError
+struct I2_CONFIG_API ConfigCompilerMessage
{
- bool Warning;
- String Message;
+ bool Error;
+ String Text;
- ConfigCompilerError(bool warning, const String& message)
- : Warning(warning), Message(message)
+ ConfigCompilerMessage(bool error, const String& text)
+ : Error(error), Text(text)
{ }
};
class I2_CONFIG_API ConfigCompilerContext
{
public:
- void AddError(bool warning, const String& message);
- std::vector<ConfigCompilerError> GetErrors(void) const;
+ void AddMessage(bool error, const String& message);
+ std::vector<ConfigCompilerMessage> GetMessages(void) const;
+ bool HasErrors(void) const;
void Reset(void);
static ConfigCompilerContext *GetInstance(void);
private:
- std::vector<ConfigCompilerError> m_Errors;
+ std::vector<ConfigCompilerMessage> m_Messages;
};
}
std::ostringstream message;
message << "Parent object '" << name << "' does not"
" exist (" << m_DebugInfo << ")";
- BOOST_THROW_EXCEPTION(std::invalid_argument(message.str()));
- }
-
- parent->Link();
+ ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
+ } else {
+ parent->Link();
- ExpressionList::Ptr pexprl = parent->GetLinkedExpressionList();
- m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, pexprl, m_DebugInfo));
+ ExpressionList::Ptr pexprl = parent->GetLinkedExpressionList();
+ m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, pexprl, m_DebugInfo));
+ }
}
m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, m_ExpressionList, m_DebugInfo));
return ConfigItem::Ptr();
}
-void ConfigItem::LinkItems(void)
+void ConfigItem::ValidateItem(void)
{
- Log(LogInformation, "config", "Linking config items...");
+ ConfigType::Ptr ctype = ConfigType::GetByName(GetType());
- ConfigItem::Ptr item;
- BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) {
- item->Link();
+ if (!ctype) {
+ ConfigCompilerContext::GetInstance()->AddMessage(false, "No validation type found for object '" + GetName() + "' of type '" + GetType() + "'");
+
+ return;
}
+
+ ctype->ValidateItem(GetSelf());
}
-void ConfigItem::ValidateItems(void)
+bool ConfigItem::ActivateItems(bool validateOnly)
{
- Log(LogInformation, "config", "Validating config items...");
+ if (ConfigCompilerContext::GetInstance()->HasErrors())
+ return false;
+
+ Log(LogInformation, "config", "Linking config items...");
ConfigItem::Ptr item;
BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) {
- ConfigType::Ptr ctype = ConfigType::GetByName(item->GetType());
-
- if (!ctype) {
- ConfigCompilerContext::GetInstance()->AddError(true, "No validation type found for object '" + item->GetName() + "' of type '" + item->GetType() + "'");
-
- continue;
- }
-
- ctype->ValidateItem(item);
+ item->Link();
}
-}
-void ConfigItem::ActivateItems(void)
-{
+ if (ConfigCompilerContext::GetInstance()->HasErrors())
+ return false;
+
Log(LogInformation, "config", "Activating config items");
std::vector<DynamicObject::Ptr> objects;
- ConfigItem::Ptr item;
BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) {
DynamicObject::Ptr object = item->Commit();
object->OnConfigLoaded();
}
+ BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) {
+ item->ValidateItem();
+ }
+
+ if (ConfigCompilerContext::GetInstance()->HasErrors())
+ return false;
+
+ if (validateOnly)
+ return true;
+
/* restore the previous program state */
DynamicObject::RestoreObjects(Application::GetStatePath());
ASSERT(object->IsActive());
}
}
+
+ return true;
}
void ConfigItem::DiscardItems(void)
static ConfigItem::Ptr GetObject(const String& type,
const String& name);
- static void LinkItems(void);
- static void ValidateItems(void);
- static void ActivateItems(void);
+ void ValidateItem(void);
+
+ static bool ActivateItems(bool validateOnly);
static void DiscardItems(void);
private:
Value value = dictionary->Get(require);
if (value.IsEmpty()) {
- ConfigCompilerContext::GetInstance()->AddError(false,
+ ConfigCompilerContext::GetInstance()->AddMessage(true,
"Required attribute is missing: " + LocationToString(locations));
}
}
if (overallResult == ValidationUnknownField)
- ConfigCompilerContext::GetInstance()->AddError(true, "Unknown attribute: " + LocationToString(locations));
+ ConfigCompilerContext::GetInstance()->AddMessage(false, "Unknown attribute: " + LocationToString(locations));
else if (overallResult == ValidationInvalidType) {
String message = "Invalid value for attribute: " + LocationToString(locations);
if (!hint.IsEmpty())
message += ": " + hint;
- ConfigCompilerContext::GetInstance()->AddError(false, message);
+ ConfigCompilerContext::GetInstance()->AddMessage(true, message);
}
if (!subRuleLists.empty() && value.IsObjectType<Dictionary>())
locations.push_back("Attribute '" + require + "'");
if (array->GetLength() < index) {
- ConfigCompilerContext::GetInstance()->AddError(false,
+ ConfigCompilerContext::GetInstance()->AddMessage(true,
"Required array index is missing: " + LocationToString(locations));
}
}
if (overallResult == ValidationUnknownField)
- ConfigCompilerContext::GetInstance()->AddError(true, "Unknown attribute: " + LocationToString(locations));
+ ConfigCompilerContext::GetInstance()->AddMessage(false, "Unknown attribute: " + LocationToString(locations));
else if (overallResult == ValidationInvalidType) {
String message = "Invalid value for array index: " + LocationToString(locations);
if (!hint.IsEmpty())
message += ": " + hint;
- ConfigCompilerContext::GetInstance()->AddError(false, message);
+ ConfigCompilerContext::GetInstance()->AddMessage(true, message);
}
if (!subRuleLists.empty() && value.IsObjectType<Dictionary>())
Array::Ptr array;
switch (m_Operator) {
+ case OperatorNop:
+ /* Nothing to do here. */
+
+ return;
+
case OperatorExecute:
if (!valueExprl)
BOOST_THROW_EXCEPTION(std::invalid_argument("Operand for OperatorExecute must be an ExpressionList."));
exprl->ExtractFiltered(keys, result);
}
}
+
+void Expression::ErasePath(const std::vector<String>& path)
+{
+ ASSERT(!path.empty());
+
+ if (path[0] == m_Key) {
+ if (path.size() == 1) {
+ m_Operator = OperatorNop;
+ } else if (m_Value.IsObjectType<ExpressionList>()) {
+ ExpressionList::Ptr exprl = m_Value;
+
+ std::vector<String> sub_path(path.begin() + 1, path.end());
+ exprl->ErasePath(sub_path);
+ }
+ } else if (m_Operator == OperatorExecute) {
+ ExpressionList::Ptr exprl = m_Value;
+ exprl->ErasePath(path);
+ }
+}
+
+void Expression::FindDebugInfoPath(const std::vector<String>& path, DebugInfo& result) const
+{
+ ASSERT(!path.empty());
+
+ if (path[0] == m_Key) {
+ if (path.size() == 1) {
+ result = m_DebugInfo;
+ } else if (m_Value.IsObjectType<ExpressionList>()) {
+ ExpressionList::Ptr exprl = m_Value;
+
+ std::vector<String> sub_path(path.begin() + 1, path.end());
+ exprl->FindDebugInfoPath(sub_path, result);
+ }
+ } else if (m_Operator == OperatorExecute) {
+ ExpressionList::Ptr exprl = m_Value;
+ exprl->FindDebugInfoPath(path, result);
+ }
+}
*/
enum ExpressionOperator
{
+ OperatorNop,
OperatorExecute,
OperatorSet,
OperatorPlus,
void ExtractPath(const std::vector<String>& path, const shared_ptr<ExpressionList>& result) const;
void ExtractFiltered(const std::set<String, string_iless>& keys, const shared_ptr<ExpressionList>& result) const;
+ void ErasePath(const std::vector<String>& path);
+
+ void FindDebugInfoPath(const std::vector<String>& path, DebugInfo& result) const;
+
private:
String m_Key;
ExpressionOperator m_Operator;
expression.ExtractFiltered(keys, result);
}
}
+
+void ExpressionList::ErasePath(const std::vector<String>& path)
+{
+ BOOST_FOREACH(Expression& expression, m_Expressions) {
+ expression.ErasePath(path);
+ }
+}
+
+void ExpressionList::FindDebugInfoPath(const std::vector<String>& path, DebugInfo& result) const
+{
+ BOOST_FOREACH(const Expression& expression, m_Expressions) {
+ expression.FindDebugInfoPath(path, result);
+ }
+}
void ExtractPath(const std::vector<String>& path, const ExpressionList::Ptr& result) const;
void ExtractFiltered(const std::set<String, string_iless>& keys, const ExpressionList::Ptr& result) const;
+ void ErasePath(const std::vector<String>& path);
+
+ void FindDebugInfoPath(const std::vector<String>& path, DebugInfo& result) const;
+
private:
std::vector<Expression> m_Expressions;
};
using namespace icinga;
-REGISTER_SCRIPTFUNCTION(ValidateServiceDictionary, &Host::ValidateServiceDictionary);
-
REGISTER_TYPE(Host);
void Host::Start(void)
namebuf << GetName() << ":" << svcname;
String name = namebuf.str();
- ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(item->GetDebugInfo());
+ std::vector<String> path;
+ path.push_back("services");
+ path.push_back(svcname);
+
+ DebugInfo di;
+ item->GetLinkedExpressionList()->FindDebugInfoPath(path, di);
+
+ if (di.Path.IsEmpty())
+ di = item->GetDebugInfo();
+
+ ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(di);
builder->SetType("Service");
builder->SetName(name);
builder->AddExpression("host_name", OperatorSet, GetName());
builder->AddExpressionList(host_exprl);
/* Clone attributes from the service expression list. */
- std::vector<String> path;
- path.push_back("services");
- path.push_back(svcname);
-
ExpressionList::Ptr svc_exprl = boost::make_shared<ExpressionList>();
item->GetLinkedExpressionList()->ExtractPath(path, svc_exprl);
+
+ std::vector<String> dpath;
+ dpath.push_back("templates");
+ svc_exprl->ErasePath(dpath);
+
builder->AddExpressionList(svc_exprl);
ConfigItem::Ptr serviceItem = builder->Compile();
return GetServices().size();
}
-Value Host::ValidateServiceDictionary(const String& location, const Dictionary::Ptr& attrs)
-{
- ObjectLock olock(attrs);
-
- String key;
- Value value;
- BOOST_FOREACH(boost::tie(key, value), attrs) {
- std::vector<String> templates;
-
- if (!value.IsObjectType<Dictionary>())
- BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be a dictionary."));
-
- Dictionary::Ptr serviceDesc = value;
-
- Array::Ptr templatesArray = serviceDesc->Get("templates");
-
- if (templatesArray) {
- ObjectLock tlock(templatesArray);
-
- BOOST_FOREACH(const Value& tmpl, templatesArray) {
- templates.push_back(tmpl);
- }
- }
-
- BOOST_FOREACH(const String& name, templates) {
- ConfigItem::Ptr item = ConfigItem::GetObject("Service", name);
-
- if (!item)
- ConfigCompilerContext::GetInstance()->AddError(false, "Validation failed for " +
- location + ": Template '" + name + "' not found.");
- }
- }
-
- return Empty;
-}
-
Service::Ptr Host::GetServiceByShortName(const Value& name) const
{
if (name.IsScalar()) {
int GetTotalServices(void) const;
- static Value ValidateServiceDictionary(const String& location, const Dictionary::Ptr& attrs);
-
static HostState CalculateState(ServiceState state, bool reachable);
HostState GetState(void) const;
}
},
%attribute dictionary "services" {
- %validator "ValidateServiceDictionary",
-
%attribute dictionary "*" {
%attribute array "templates" {
%attribute name(Service) "*"
},
- %attribute string "short_name",
+/* %attribute string "short_name",
%attribute string "display_name",
%attribute dictionary "macros" {
%attribute number "notification_state_filter",
%attribute name(TimePeriod) "notification_period"
}
- },
+ },*/
}
},
- %attribute dictionary "notifications" {
+/* %attribute dictionary "notifications" {
%attribute dictionary "*" {
%attribute array "templates" {
%attribute name(Notification) "*"
%attribute number "notification_state_filter",
%attribute name(TimePeriod) "notification_period"
}
- },
+ },*/
/* service attributes */
%attribute number "max_check_attempts",
%attribute name(Notification) "*"
},
- %attribute dictionary "macros" {
+/* %attribute dictionary "macros" {
%attribute string "*"
},
%attribute number "notification_type_filter",
%attribute number "notification_state_filter",
- %attribute name(TimePeriod) "notification_period"
+ %attribute name(TimePeriod) "notification_period"*/
}
}
}
namebuf << GetName() << ":" << nfcname;
String name = namebuf.str();
- ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(item->GetDebugInfo());
+ std::vector<String> path;
+ path.push_back("notifications");
+ path.push_back(nfcname);
+
+ DebugInfo di;
+ item->GetLinkedExpressionList()->FindDebugInfoPath(path, di);
+
+ if (di.Path.IsEmpty())
+ di = item->GetDebugInfo();
+
+ ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(di);
builder->SetType("Notification");
builder->SetName(name);
builder->AddExpression("host_name", OperatorSet, host->GetName());
builder->AddExpressionList(svc_exprl);
/* Clone attributes from the notification expression list. */
- std::vector<String> path;
- path.push_back("notifications");
- path.push_back(nfcname);
-
ExpressionList::Ptr nfc_exprl = boost::make_shared<ExpressionList>();
item->GetLinkedExpressionList()->ExtractPath(path, nfc_exprl);
+
+ std::vector<String> dpath;
+ dpath.push_back("templates");
+ nfc_exprl->ErasePath(dpath);
+
builder->AddExpressionList(nfc_exprl);
ConfigItem::Ptr notificationItem = builder->Compile();