Template auto-apply and container auto-bind works for clusters
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 4 Dec 2016 11:18:09 +0000 (13:18 +0200)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 4 Dec 2016 11:18:09 +0000 (13:18 +0200)
ChangeLog
src/server/core/cluster.cpp
src/server/core/container.cpp
src/server/core/dctarget.cpp
src/server/core/node.cpp
src/server/core/poll.cpp
src/server/core/template.cpp
src/server/include/nms_objects.h

index 9c4d71f..b33c82b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,7 @@
 - New NXSL "Node" class attributes: isInMaintenanceMode, lastAgentCommTime
 - Access to object's alarms in NXSL via "alarms" attribute in "NetObj" class
 - Operator "new" in NXSL which can be used to instantiate objects if object class supports it
+- Template auto-apply and container auto-bind works for clusters
 - H3C driver correctly reads IPv6 addresses on interfaces
 - SMS driver for Nexmo service
 - SMS driver for SMSEagle gateway
index 3b178b1..fea92a0 100644 (file)
@@ -31,7 +31,8 @@ Cluster::Cluster() : DataCollectionTarget()
    m_syncNetworks = new ObjectArray<InetAddress>(8, 8, true);
        m_dwNumResources = 0;
        m_pResourceList = NULL;
-       m_tmLastPoll = 0;
+       m_lastStatusPoll = 0;
+   m_lastConfigurationPoll = 0;
        m_zoneId = 0;
 }
 
@@ -44,7 +45,8 @@ Cluster::Cluster(const TCHAR *pszName, UINT32 zoneId) : DataCollectionTarget(psz
    m_syncNetworks = new ObjectArray<InetAddress>(8, 8, true);
        m_dwNumResources = 0;
        m_pResourceList = NULL;
-       m_tmLastPoll = 0;
+   m_lastStatusPoll = 0;
+   m_lastConfigurationPoll = 0;
        m_zoneId = zoneId;
 }
 
@@ -512,6 +514,40 @@ bool Cluster::isVirtualAddr(const InetAddress& addr)
        return bRet;
 }
 
+/**
+ * Entry point for configuration poller thread
+ */
+void Cluster::configurationPoll(PollerInfo *poller)
+{
+   poller->startExecution();
+   ObjectTransactionStart();
+   configurationPoll(NULL, 0, poller);
+   ObjectTransactionEnd();
+   delete poller;
+}
+
+/**
+ * Configuration poll
+ */
+void Cluster::configurationPoll(ClientSession *pSession, UINT32 dwRqId, PollerInfo *poller)
+{
+   if (IsShutdownInProgress())
+      return;
+
+   DbgPrintf(6, _T("CLUSTER STATUS POLL [%s]: Applying templates"), m_name);
+   applyUserTemplates();
+
+   DbgPrintf(6, _T("CLUSTER STATUS POLL [%s]: Updating container bindings"), m_name);
+   updateContainerMembership();
+
+   lockProperties();
+   m_lastConfigurationPoll = time(NULL);
+   m_flags &= ~CLF_QUEUED_FOR_CONFIGURATION_POLL;
+   unlockProperties();
+
+   DbgPrintf(6, _T("CLUSTER CONFIGURATION POLL [%s]: Finished"), m_name);
+}
+
 /**
  * Entry point for status poller thread
  */
@@ -670,7 +706,7 @@ void Cluster::statusPoll(ClientSession *pSession, UINT32 dwRqId, PollerInfo *pol
        lockProperties();
        if (bModified)
                setModified();
-       m_tmLastPoll = time(NULL);
+       m_lastStatusPoll = time(NULL);
        m_flags &= ~CLF_QUEUED_FOR_STATUS_POLL;
        unlockProperties();
 
index 8907679..a6e4ba1 100644 (file)
@@ -308,9 +308,9 @@ void Container::setAutoBindFilter(const TCHAR *script)
 }
 
 /**
- * Check if node should be placed into container
+ * Check if object should be placed into container
  */
-AutoBindDecision Container::isSuitableForNode(Node *node)
+AutoBindDecision Container::isSuitableForObject(NetObj *object)
 {
    AutoBindDecision result = AutoBindDecision_Ignore;
 
@@ -333,7 +333,9 @@ AutoBindDecision Container::isSuitableForNode(Node *node)
    if (filter == NULL)
       return result;
 
-   filter->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, node)));
+   filter->setGlobalVariable(_T("$object"), object->createNXSLObject());
+   if (object->getObjectClass() == OBJECT_NODE)
+      filter->setGlobalVariable(_T("$node"), object->createNXSLObject());
    if (filter->run())
    {
       NXSL_Value *value = filter->getResult();
index 979cccb..63a878a 100644 (file)
@@ -1102,3 +1102,101 @@ UINT32 DataCollectionTarget::getEffectiveSourceNode(DCObject *dco)
 {
    return dco->getSourceNode();
 }
+
+/**
+ * Filter for selecting templates from objects
+ */
+static bool TemplateSelectionFilter(NetObj *object, void *userData)
+{
+   return (object->getObjectClass() == OBJECT_TEMPLATE) && !object->isDeleted() && ((Template *)object)->isAutoApplyEnabled();
+}
+
+/**
+ * Apply user templates
+ */
+void DataCollectionTarget::applyUserTemplates()
+{
+   if (IsShutdownInProgress())
+      return;
+
+   ObjectArray<NetObj> *templates = g_idxObjectById.getObjects(true, TemplateSelectionFilter);
+   for(int i = 0; i < templates->size(); i++)
+   {
+      Template *pTemplate = (Template *)templates->get(i);
+      AutoBindDecision decision = pTemplate->isApplicable(this);
+      if (decision == AutoBindDecision_Bind)
+      {
+         if (!pTemplate->isChild(m_id))
+         {
+            DbgPrintf(4, _T("DataCollectionTarget::applyUserTemplates(): applying template %d \"%s\" to object %d \"%s\""),
+                      pTemplate->getId(), pTemplate->getName(), m_id, m_name);
+            pTemplate->applyToTarget(this);
+            PostEvent(EVENT_TEMPLATE_AUTOAPPLY, g_dwMgmtNode, "isis", m_id, m_name, pTemplate->getId(), pTemplate->getName());
+         }
+      }
+      else if (decision == AutoBindDecision_Unbind)
+      {
+         if (pTemplate->isAutoRemoveEnabled() && pTemplate->isChild(m_id))
+         {
+            DbgPrintf(4, _T("DataCollectionTarget::applyUserTemplates(): removing template %d \"%s\" from object %d \"%s\""),
+                      pTemplate->getId(), pTemplate->getName(), m_id, m_name);
+            pTemplate->deleteChild(this);
+            deleteParent(pTemplate);
+            pTemplate->queueRemoveFromTarget(m_id, true);
+            PostEvent(EVENT_TEMPLATE_AUTOREMOVE, g_dwMgmtNode, "isis", m_id, m_name, pTemplate->getId(), pTemplate->getName());
+         }
+      }
+      pTemplate->decRefCount();
+   }
+   delete templates;
+}
+
+/**
+ * Filter for selecting containers from objects
+ */
+static bool ContainerSelectionFilter(NetObj *object, void *userData)
+{
+   return (object->getObjectClass() == OBJECT_CONTAINER) && !object->isDeleted() && ((Container *)object)->isAutoBindEnabled();
+}
+
+/**
+ * Update container membership
+ */
+void DataCollectionTarget::updateContainerMembership()
+{
+   if (IsShutdownInProgress())
+      return;
+
+   ObjectArray<NetObj> *containers = g_idxObjectById.getObjects(true, ContainerSelectionFilter);
+   for(int i = 0; i < containers->size(); i++)
+   {
+      Container *pContainer = (Container *)containers->get(i);
+      AutoBindDecision decision = pContainer->isSuitableForObject(this);
+      if (decision == AutoBindDecision_Bind)
+      {
+         if (!pContainer->isChild(m_id))
+         {
+            DbgPrintf(4, _T("DataCollectionTarget::updateContainerMembership(): binding object %d \"%s\" to container %d \"%s\""),
+                      m_id, m_name, pContainer->getId(), pContainer->getName());
+            pContainer->addChild(this);
+            addParent(pContainer);
+            PostEvent(EVENT_CONTAINER_AUTOBIND, g_dwMgmtNode, "isis", m_id, m_name, pContainer->getId(), pContainer->getName());
+            pContainer->calculateCompoundStatus();
+         }
+      }
+      else if (decision == AutoBindDecision_Unbind)
+      {
+         if (pContainer->isAutoUnbindEnabled() && pContainer->isChild(m_id))
+         {
+            DbgPrintf(4, _T("DataCollectionTarget::updateContainerMembership(): removing object %d \"%s\" from container %d \"%s\""),
+                      m_id, m_name, pContainer->getId(), pContainer->getName());
+            pContainer->deleteChild(this);
+            deleteParent(pContainer);
+            PostEvent(EVENT_CONTAINER_AUTOUNBIND, g_dwMgmtNode, "isis", m_id, m_name, pContainer->getId(), pContainer->getName());
+            pContainer->calculateCompoundStatus();
+         }
+      }
+      pContainer->decRefCount();
+   }
+   delete containers;
+}
index 7e3df3d..22516e6 100644 (file)
@@ -3269,104 +3269,6 @@ bool Node::updateInterfaceConfiguration(UINT32 rqid, int maskBits)
    return hasChanges;
 }
 
-/**
- * Filter for selecting templates from objects
- */
-static bool TemplateSelectionFilter(NetObj *object, void *userData)
-{
-   return (object->getObjectClass() == OBJECT_TEMPLATE) && !object->isDeleted() && ((Template *)object)->isAutoApplyEnabled();
-}
-
-/**
- * Apply user templates
- */
-void Node::applyUserTemplates()
-{
-   if (IsShutdownInProgress())
-      return;
-
-   ObjectArray<NetObj> *templates = g_idxObjectById.getObjects(true, TemplateSelectionFilter);
-   for(int i = 0; i < templates->size(); i++)
-   {
-      Template *pTemplate = (Template *)templates->get(i);
-      AutoBindDecision decision = pTemplate->isApplicable(this);
-      if (decision == AutoBindDecision_Bind)
-      {
-         if (!pTemplate->isChild(m_id))
-         {
-            DbgPrintf(4, _T("Node::ApplyUserTemplates(): applying template %d \"%s\" to node %d \"%s\""),
-                      pTemplate->getId(), pTemplate->getName(), m_id, m_name);
-            pTemplate->applyToTarget(this);
-            PostEvent(EVENT_TEMPLATE_AUTOAPPLY, g_dwMgmtNode, "isis", m_id, m_name, pTemplate->getId(), pTemplate->getName());
-         }
-      }
-      else if (decision == AutoBindDecision_Unbind)
-      {
-         if (pTemplate->isAutoRemoveEnabled() && pTemplate->isChild(m_id))
-         {
-            DbgPrintf(4, _T("Node::ApplyUserTemplates(): removing template %d \"%s\" from node %d \"%s\""),
-                      pTemplate->getId(), pTemplate->getName(), m_id, m_name);
-            pTemplate->deleteChild(this);
-            deleteParent(pTemplate);
-            pTemplate->queueRemoveFromTarget(m_id, true);
-            PostEvent(EVENT_TEMPLATE_AUTOREMOVE, g_dwMgmtNode, "isis", m_id, m_name, pTemplate->getId(), pTemplate->getName());
-         }
-      }
-      pTemplate->decRefCount();
-   }
-   delete templates;
-}
-
-/**
- * Filter for selecting containers from objects
- */
-static bool ContainerSelectionFilter(NetObj *object, void *userData)
-{
-   return (object->getObjectClass() == OBJECT_CONTAINER) && !object->isDeleted() && ((Container *)object)->isAutoBindEnabled();
-}
-
-/**
- * Update container membership
- */
-void Node::updateContainerMembership()
-{
-   if (IsShutdownInProgress())
-      return;
-
-   ObjectArray<NetObj> *containers = g_idxObjectById.getObjects(true, ContainerSelectionFilter);
-   for(int i = 0; i < containers->size(); i++)
-   {
-      Container *pContainer = (Container *)containers->get(i);
-      AutoBindDecision decision = pContainer->isSuitableForNode(this);
-      if (decision == AutoBindDecision_Bind)
-      {
-         if (!pContainer->isChild(m_id))
-         {
-            DbgPrintf(4, _T("Node::updateContainerMembership(): binding node %d \"%s\" to container %d \"%s\""),
-                      m_id, m_name, pContainer->getId(), pContainer->getName());
-            pContainer->addChild(this);
-            addParent(pContainer);
-            PostEvent(EVENT_CONTAINER_AUTOBIND, g_dwMgmtNode, "isis", m_id, m_name, pContainer->getId(), pContainer->getName());
-            pContainer->calculateCompoundStatus();
-         }
-      }
-      else if (decision == AutoBindDecision_Unbind)
-      {
-         if (pContainer->isAutoUnbindEnabled() && pContainer->isChild(m_id))
-         {
-            DbgPrintf(4, _T("Node::updateContainerMembership(): removing node %d \"%s\" from container %d \"%s\""),
-                      m_id, m_name, pContainer->getId(), pContainer->getName());
-            pContainer->deleteChild(this);
-            deleteParent(pContainer);
-            PostEvent(EVENT_CONTAINER_AUTOUNBIND, g_dwMgmtNode, "isis", m_id, m_name, pContainer->getId(), pContainer->getName());
-            pContainer->calculateCompoundStatus();
-         }
-      }
-      pContainer->decRefCount();
-   }
-   delete containers;
-}
-
 /**
  * Entry point for instance discovery poller
  */
index 58da258..927b5e1 100644 (file)
@@ -542,6 +542,12 @@ static void QueueForPolling(NetObj *object, void *data)
                                        DbgPrintf(6, _T("Cluster %d \"%s\" queued for status poll"), (int)cluster->getId(), cluster->getName());
                ThreadPoolExecute(g_pollerThreadPool, cluster, &Cluster::statusPoll, RegisterPoller(POLLER_TYPE_STATUS, cluster));
                                }
+            if (cluster->isReadyForConfigurationPoll())
+            {
+               cluster->lockForConfigurationPoll();
+               DbgPrintf(6, _T("Cluster %d \"%s\" queued for configuration poll"), (int)cluster->getId(), cluster->getName());
+               ThreadPoolExecute(g_pollerThreadPool, cluster, &Cluster::configurationPoll, RegisterPoller(POLLER_TYPE_CONFIGURATION, cluster));
+            }
                        }
                        break;
                case OBJECT_BUSINESSSERVICE:
index b890e03..41bc455 100644 (file)
@@ -1182,11 +1182,11 @@ void Template::prepareForDeletion()
 }
 
 /**
- * Check if template should be automatically applied to node
+ * Check if template should be automatically applied to given data collection target
  * Returns AutoBindDecision_Bind if applicable, AutoBindDecision_Unbind if not, 
  * AutoBindDecision_Ignore if no change required (script error or no auto apply)
  */
-AutoBindDecision Template::isApplicable(Node *node)
+AutoBindDecision Template::isApplicable(DataCollectionTarget *target)
 {
        AutoBindDecision result = AutoBindDecision_Ignore;
 
@@ -1209,7 +1209,9 @@ AutoBindDecision Template::isApplicable(Node *node)
    if (filter == NULL)
       return result;
 
-   filter->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, node)));
+   filter->setGlobalVariable(_T("$object"), target->createNXSLObject());
+   if (target->getObjectClass() == OBJECT_NODE)
+      filter->setGlobalVariable(_T("$node"), target->createNXSLObject());
    if (filter->run())
    {
       NXSL_Value *value = filter->getResult();
index cfd1146..2335cb7 100644 (file)
@@ -114,8 +114,9 @@ bool NXCORE_EXPORTABLE ExecuteQueryOnObject(DB_HANDLE hdb, UINT32 objectId, cons
 /**
  * Cluster runtime flags
  */
-#define CLF_QUEUED_FOR_STATUS_POLL     0x0001
-#define CLF_DOWN                       0x0002
+#define CLF_QUEUED_FOR_STATUS_POLL        0x0001
+#define CLF_DOWN                          0x0002
+#define CLF_QUEUED_FOR_CONFIGURATION_POLL 0x0004
 
 /**
  * Extended agent connection
@@ -753,7 +754,7 @@ public:
    StringSet *getDCIScriptList();
 
    BOOL applyToTarget(DataCollectionTarget *pNode);
-       AutoBindDecision isApplicable(Node *node);
+       AutoBindDecision isApplicable(DataCollectionTarget *object);
        bool isAutoApplyEnabled() { return (m_flags & TF_AUTO_APPLY) ? true : false; }
        bool isAutoRemoveEnabled() { return ((m_flags & (TF_AUTO_APPLY | TF_AUTO_REMOVE)) == (TF_AUTO_APPLY | TF_AUTO_REMOVE)) ? true : false; }
        void setAutoApplyFilter(const TCHAR *filter);
@@ -1006,6 +1007,9 @@ protected:
 
    NetObj *objectFromParameter(const TCHAR *param);
 
+   void applyUserTemplates();
+   void updateContainerMembership();
+
    void addProxyDataCollectionElement(ProxyInfo *info, const DCObject *dco);
    void addProxySnmpTarget(ProxyInfo *info, const Node *node);
    virtual void collectProxyInfo(ProxyInfo *info);
@@ -1165,7 +1169,8 @@ protected:
    ObjectArray<InetAddress> *m_syncNetworks;
        UINT32 m_dwNumResources;
        CLUSTER_RESOURCE *m_pResourceList;
-       time_t m_tmLastPoll;
+       time_t m_lastStatusPoll;
+   time_t m_lastConfigurationPoll;
        UINT32 m_zoneId;
 
    virtual void fillMessageInternal(NXCPMessage *pMsg);
@@ -1204,7 +1209,18 @@ public:
    {
       return ((m_status != STATUS_UNMANAGED) && (!m_isDeleted) &&
               (!(m_flags & CLF_QUEUED_FOR_STATUS_POLL)) &&
-              ((UINT32)time(NULL) - (UINT32)m_tmLastPoll > g_dwStatusPollingInterval))
+              ((UINT32)time(NULL) - (UINT32)m_lastStatusPoll > g_dwStatusPollingInterval))
+                  ? true : false;
+   }
+
+   void configurationPoll(PollerInfo *poller);
+   void configurationPoll(ClientSession *pSession, UINT32 dwRqId, PollerInfo *poller);
+   void lockForConfigurationPoll() { m_flags |= CLF_QUEUED_FOR_CONFIGURATION_POLL; }
+   bool isReadyForConfigurationPoll()
+   {
+      return ((m_status != STATUS_UNMANAGED) && (!m_isDeleted) &&
+              (!(m_flags & CLF_QUEUED_FOR_CONFIGURATION_POLL)) &&
+              ((UINT32)time(NULL) - (UINT32)m_lastConfigurationPoll > g_dwConfigurationPollingInterval))
                   ? true : false;
    }
 
@@ -1423,13 +1439,11 @@ protected:
        bool checkNetworkPath(UINT32 dwRqId);
        bool checkNetworkPathElement(UINT32 nodeId, const TCHAR *nodeType, bool isProxy, UINT32 dwRqId);
 
-       void applyUserTemplates();
        void doInstanceDiscovery(UINT32 requestId);
        StringMap *getInstanceList(DCItem *dci);
        bool updateInstances(DCItem *root, StringMap *instances, UINT32 requestId);
    void syncDataCollectionWithAgent(AgentConnectionEx *conn);
 
-       void updateContainerMembership();
        bool updateInterfaceConfiguration(UINT32 rqid, int maskBits);
    bool deleteDuplicateInterfaces(UINT32 rqid);
    void updatePhysicalContainerBinding(int containerClass, UINT32 containerId);
@@ -1928,7 +1942,7 @@ public:
 
    void linkObject(NetObj *pObject) { addChild(pObject); pObject->addParent(this); }
 
-   AutoBindDecision isSuitableForNode(Node *node);
+   AutoBindDecision isSuitableForObject(NetObj *object);
        bool isAutoBindEnabled() { return (m_flags & CF_AUTO_BIND) ? true : false; }
        bool isAutoUnbindEnabled() { return ((m_flags & (CF_AUTO_BIND | CF_AUTO_UNBIND)) == (CF_AUTO_BIND | CF_AUTO_UNBIND)) ? true : false; }