Fix message origin for runtime created config object (create/delete events)

This commit is contained in:
Michael Friedrich 2019-08-13 14:53:06 +02:00
parent fcca9643bc
commit c30edd0a34
7 changed files with 67 additions and 24 deletions

View File

@ -357,7 +357,7 @@ void ConfigObject::PreActivate()
SetActive(true, true);
}
void ConfigObject::Activate(bool runtimeCreated)
void ConfigObject::Activate(bool runtimeCreated, const Value& cookie)
{
CONTEXT("Activating object '" + GetName() + "' of type '" + GetReflectionType()->GetName() + "'");
@ -372,7 +372,7 @@ void ConfigObject::Activate(bool runtimeCreated)
SetAuthority(true);
}
NotifyActive();
NotifyActive(cookie);
}
void ConfigObject::Stop(bool runtimeRemoved)
@ -384,7 +384,7 @@ void ConfigObject::Stop(bool runtimeRemoved)
SetStopCalled(true);
}
void ConfigObject::Deactivate(bool runtimeRemoved)
void ConfigObject::Deactivate(bool runtimeRemoved, const Value& cookie)
{
CONTEXT("Deactivating object '" + GetName() + "' of type '" + GetReflectionType()->GetName() + "'");
@ -403,7 +403,7 @@ void ConfigObject::Deactivate(bool runtimeRemoved)
ASSERT(GetStopCalled());
NotifyActive();
NotifyActive(cookie);
}
void ConfigObject::OnConfigLoaded()

View File

@ -44,8 +44,8 @@ public:
void Unregister();
void PreActivate();
void Activate(bool runtimeCreated = false);
void Deactivate(bool runtimeRemoved = false);
void Activate(bool runtimeCreated = false, const Value& cookie = Empty);
void Deactivate(bool runtimeRemoved = false, const Value& cookie = Empty);
void SetAuthority(bool authority);
void Start(bool runtimeCreated = false) override;

View File

@ -624,7 +624,8 @@ bool ConfigItem::CommitItems(const ActivationContext::Ptr& context, WorkQueue& u
return true;
}
bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated, bool silent, bool withModAttrs)
bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated,
bool silent, bool withModAttrs, const Value& cookie)
{
static boost::mutex mtx;
boost::mutex::scoped_lock lock(mtx);
@ -692,7 +693,7 @@ bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr
<< objectType->GetActivationPriority();
#endif /* I2_DEBUG */
object->Activate(runtimeCreated);
object->Activate(runtimeCreated, cookie);
}
}

View File

@ -53,7 +53,8 @@ public:
const String& name);
static bool CommitItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems, bool silent = false);
static bool ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated = false, bool silent = false, bool withModAttrs = false);
static bool ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated = false,
bool silent = false, bool withModAttrs = false, const Value& cookie = Empty);
static bool RunWithActivationContext(const Function::Ptr& function);

View File

@ -99,7 +99,11 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
/* object does not exist, create it through the API */
Array::Ptr errors = new Array();
if (!ConfigObjectUtility::CreateObject(ptype, objName, config, errors, nullptr)) {
/*
* Create the config object through our internal API.
* IMPORTANT: Pass the origin to prevent cluster sync loops.
*/
if (!ConfigObjectUtility::CreateObject(ptype, objName, config, errors, nullptr, origin)) {
Log(LogCritical, "ApiListener")
<< "Could not create object '" << objName << "':";
@ -238,7 +242,11 @@ Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin
Array::Ptr errors = new Array();
if (!ConfigObjectUtility::DeleteObject(object, true, errors, nullptr)) {
/*
* Delete the config object through our internal API.
* IMPORTANT: Pass the origin to prevent cluster sync loops.
*/
if (!ConfigObjectUtility::DeleteObject(object, true, errors, nullptr, origin)) {
Log(LogCritical, "ApiListener", "Could not delete object:");
ObjectLock olock(errors);

View File

@ -148,7 +148,7 @@ String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const Stri
}
bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName,
const String& config, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation)
const String& config, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation, const Value& cookie)
{
CreateStorage();
@ -188,9 +188,37 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
std::vector<ConfigItem::Ptr> newItems;
/* Disable logging for object creation, but do so ourselves later on. */
if (!ConfigItem::CommitItems(ascope.GetContext(), upq, newItems, true) || !ConfigItem::ActivateItems(upq, newItems, true, true)) {
/*
* Disable logging for object creation, but do so ourselves later on.
* Duplicate the error handling for better logging and debugging here.
*/
if (!ConfigItem::CommitItems(ascope.GetContext(), upq, newItems, true)) {
if (errors) {
Log(LogNotice, "ConfigObjectUtility")
<< "Failed to commit config item '" << fullName << "'. Aborting and emoving config path '" << path << "'.";
Utility::Remove(path);
for (const boost::exception_ptr& ex : upq.GetExceptions()) {
errors->Add(DiagnosticInformation(ex, false));
if (diagnosticInformation)
diagnosticInformation->Add(DiagnosticInformation(ex));
}
}
return false;
}
/*
* Activate the config object.
* IMPORTANT: Forward the cookie aka origin in order to prevent sync loops in the same zone!
*/
if (!ConfigItem::ActivateItems(upq, newItems, true, true, cookie)) {
if (errors) {
Log(LogNotice, "ConfigObjectUtility")
<< "Failed to activate config object '" << fullName << "'. Aborting and emoving config path '" << path << "'.";
Utility::Remove(path);
for (const boost::exception_ptr& ex : upq.GetExceptions()) {
@ -211,7 +239,6 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
if (type->GetName() != "Comment" && type->GetName() != "Downtime")
ApiListener::UpdateObjectAuthority();
Log(LogInformation, "ConfigObjectUtility")
<< "Created and activated object '" << fullName << "' of type '" << type->GetName() << "'.";
@ -231,7 +258,7 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
}
bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade,
const Array::Ptr& errors, const Array::Ptr& diagnosticInformation)
const Array::Ptr& errors, const Array::Ptr& diagnosticInformation, const Value& cookie)
{
std::vector<Object::Ptr> parents = DependencyGraph::GetParents(object);
@ -255,7 +282,7 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
if (!parentObj)
continue;
DeleteObjectHelper(parentObj, cascade, errors, diagnosticInformation);
DeleteObjectHelper(parentObj, cascade, errors, diagnosticInformation, cookie);
}
ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, name);
@ -263,8 +290,13 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
try {
/* mark this object for cluster delete event */
object->SetExtension("ConfigObjectDeleted", true);
/* triggers signal for DB IDO and other interfaces */
object->Deactivate(true);
/*
* Trigger deactivation signal for DB IDO and runtime object delections.
* IMPORTANT: Specify the cookie aka origin in order to prevent sync loops
* in the same zone!
*/
object->Deactivate(true, cookie);
if (item)
item->Unregister();
@ -298,7 +330,8 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
return true;
}
bool ConfigObjectUtility::DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation)
bool ConfigObjectUtility::DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors,
const Array::Ptr& diagnosticInformation, const Value& cookie)
{
if (object->GetPackage() != "_api") {
if (errors)
@ -307,5 +340,5 @@ bool ConfigObjectUtility::DeleteObject(const ConfigObject::Ptr& object, bool cas
return false;
}
return DeleteObjectHelper(object, cascade, errors, diagnosticInformation);
return DeleteObjectHelper(object, cascade, errors, diagnosticInformation, cookie);
}

View File

@ -30,15 +30,15 @@ public:
bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs);
static bool CreateObject(const Type::Ptr& type, const String& fullName,
const String& config, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation);
const String& config, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation, const Value& cookie = Empty);
static bool DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors,
const Array::Ptr& diagnosticInformation);
const Array::Ptr& diagnosticInformation, const Value& cookie = Empty);
private:
static String EscapeName(const String& name);
static bool DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors,
const Array::Ptr& diagnosticInformation);
const Array::Ptr& diagnosticInformation, const Value& cookie = Empty);
};
}