added node type and sub-type properties
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 28 Jul 2016 09:17:34 +0000 (12:17 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 28 Jul 2016 09:17:34 +0000 (12:17 +0300)
13 files changed:
include/netxmsdb.h
include/nms_cscp.h
include/nxcldefs.h
sql/schema.in
src/java/client/netxms-base/src/main/java/org/netxms/base/NXCPCodes.java
src/java/client/netxms-client/src/main/java/org/netxms/client/constants/NodeType.java [new file with mode: 0644]
src/java/client/netxms-client/src/main/java/org/netxms/client/objects/AbstractNode.java
src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/GeneralInfo.java
src/server/core/node.cpp
src/server/core/nxsl_classes.cpp
src/server/include/nms_objects.h
src/server/tools/nxdbmgr/upgrade.cpp
webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/GeneralInfo.java

index 3e4b872..5e00b6a 100644 (file)
@@ -23,6 +23,6 @@
 #ifndef _netxmsdb_h
 #define _netxmsdb_h
 
-#define DB_FORMAT_VERSION   408
+#define DB_FORMAT_VERSION   409
 
 #endif
index 04e6426..7eaccf9 100644 (file)
@@ -1128,6 +1128,7 @@ typedef struct
 #define VID_TOOLTIP_DCI_COUNT       ((UINT32)542)
 #define VID_CONTROLLER_ID           ((UINT32)543)
 #define VID_CHASSIS_ID              ((UINT32)544)
+#define VID_NODE_SUBTYPE            ((UINT32)545)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((UINT32)0x00800000)
index 7661d16..18c5f5f 100644 (file)
@@ -44,6 +44,7 @@
 #define MAX_AGENT_VERSION_LEN    64
 #define MAX_PLATFORM_NAME_LEN    64
 #define MAX_PACKAGE_NAME_LEN     64
+#define MAX_NODE_SUBTYPE_LENGTH  128
 #define GROUP_EVERYONE           ((UINT32)0x80000000)
 #define INVALID_UID              ((UINT32)0xFFFFFFFF)
 #define OBJECT_STATUS_COUNT      9
index 69e3d3e..d917b91 100644 (file)
@@ -439,6 +439,8 @@ CREATE TABLE nodes
   last_agent_comm_time integer not null,
   syslog_msg_count SQL_INT64 not null,
   snmp_trap_count SQL_INT64 not null,
+  node_type integer not null,
+  node_subtype varchar(127) null,
   PRIMARY KEY(id)
 ) TABLE_TYPE;
 
index 1536d79..c93ab5a 100644 (file)
@@ -916,6 +916,7 @@ public class NXCPCodes
    public static final long VID_TOOLTIP_DCI_COUNT = 542;
    public static final long VID_CONTROLLER_ID = 543;
    public static final long VID_CHASSIS_ID = 544;
+   public static final long VID_NODE_SUBTYPE = 545;
 
        public static final long VID_ACL_USER_BASE = 0x00001000L;
        public static final long VID_ACL_USER_LAST = 0x00001FFFL;
diff --git a/src/java/client/netxms-client/src/main/java/org/netxms/client/constants/NodeType.java b/src/java/client/netxms-client/src/main/java/org/netxms/client/constants/NodeType.java
new file mode 100644 (file)
index 0000000..50b423b
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * NetXMS - open source network management system
+ * Copyright (C) 2003-2016 Victor Kirhenshtein
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.netxms.client.constants;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.netxms.base.Logger;
+
+/**
+ * Node type
+ */
+public enum NodeType
+{
+   UNKNOWN(0),
+   PHYSICAL(1),
+   VIRTUAL(2),
+   CONTROLLER(3);
+
+   private int value;
+   private static Map<Integer, NodeType> lookupTable = new HashMap<Integer, NodeType>();
+
+   static
+   {
+      for(NodeType element : NodeType.values())
+      {
+         lookupTable.put(element.value, element);
+      }
+   }
+
+   /**
+    * @param value
+    */
+   private NodeType(int value)
+   {
+      this.value = value;
+   }
+
+   /**
+    * @return
+    */
+   public int getValue()
+   {
+      return value;
+   }
+
+   /**
+    * @param value
+    * @return
+    */
+   public static NodeType getByValue(int value)
+   {
+      final NodeType element = lookupTable.get(value);
+      if (element == null)
+      {
+         Logger.warning(NodeType.class.getName(), "Unknown element " + value);
+         return UNKNOWN; // fallback
+      }
+      return element;
+   }
+}
index 847efe3..d8afc94 100644 (file)
@@ -26,6 +26,7 @@ import org.netxms.base.NXCPMessage;
 import org.netxms.client.MacAddress;
 import org.netxms.client.NXCSession;
 import org.netxms.client.constants.AgentCacheMode;
+import org.netxms.client.constants.NodeType;
 
 /**
  * Abstract base class for node objects.
@@ -92,7 +93,8 @@ public abstract class AbstractNode extends DataCollectionTarget implements RackE
        protected String primaryName;
        protected int flags;
        protected int runtimeFlags;
-       protected int nodeType;
+       protected NodeType nodeType;
+       protected String nodeSubType;
        protected int requredPollCount;
        protected long pollerNodeId;
        protected long agentProxyId;
@@ -156,7 +158,8 @@ public abstract class AbstractNode extends DataCollectionTarget implements RackE
                primaryName = msg.getFieldAsString(NXCPCodes.VID_PRIMARY_NAME);
                flags = msg.getFieldAsInt32(NXCPCodes.VID_FLAGS);
                runtimeFlags = msg.getFieldAsInt32(NXCPCodes.VID_RUNTIME_FLAGS);
-               nodeType = msg.getFieldAsInt32(NXCPCodes.VID_NODE_TYPE);
+               nodeType = NodeType.getByValue(msg.getFieldAsInt16(NXCPCodes.VID_NODE_TYPE));
+               nodeSubType = msg.getFieldAsString(NXCPCodes.VID_NODE_SUBTYPE);
                requredPollCount = msg.getFieldAsInt32(NXCPCodes.VID_REQUIRED_POLLS);
                pollerNodeId = msg.getFieldAsInt64(NXCPCodes.VID_POLLER_NODE_ID);
                agentProxyId = msg.getFieldAsInt64(NXCPCodes.VID_AGENT_PROXY);
@@ -221,12 +224,20 @@ public abstract class AbstractNode extends DataCollectionTarget implements RackE
        /**
         * @return the nodeType
         */
-       public int getNodeType()
+       public NodeType getNodeType()
        {
                return nodeType;
        }
 
        /**
+    * @return the nodeSubType
+    */
+   public String getNodeSubType()
+   {
+      return nodeSubType;
+   }
+
+   /**
         * @return the requredPollCount
         */
        public int getRequredPollCount()
index 516874f..4d76a07 100644 (file)
@@ -150,6 +150,7 @@ public class GeneralInfo extends TableElement
                                if ((node.getFlags() & AbstractNode.NF_IS_BRIDGE) != 0)
                                        addPair(Messages.get().GeneralInfo_BridgeBaseAddress, node.getBridgeBaseAddress().toString());
                                addPair(Messages.get().GeneralInfo_Driver, node.getDriverName(), false);
+            addPair("Node Type", node.getNodeType().toString(), false);
             if (node.getBootTime() != null)
                addPair(Messages.get().GeneralInfo_BootTime, RegionalSettings.getDateTimeFormat().format(node.getBootTime()), false);
             if (node.hasAgent())
index ac82ebb..d6208bc 100644 (file)
@@ -35,6 +35,8 @@ Node::Node() : DataCollectionTarget()
 {
        m_primaryName[0] = 0;
    m_status = STATUS_UNKNOWN;
+   m_type = NODE_TYPE_UNKNOWN;
+   m_subType[0] = 0;
    m_dwFlags = 0;
    m_dwDynamicFlags = 0;
    m_zoneId = 0;
@@ -124,6 +126,8 @@ Node::Node(const InetAddress& addr, UINT32 dwFlags, UINT32 agentProxy, UINT32 sn
 {
    addr.toString(m_primaryName);
    m_status = STATUS_UNKNOWN;
+   m_type = NODE_TYPE_UNKNOWN;
+   m_subType[0] = 0;
    m_ipAddress = addr;
    m_dwFlags = dwFlags;
    m_dwDynamicFlags = 0;
@@ -280,7 +284,8 @@ bool Node::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
       _T("runtime_flags,down_since,boot_time,driver_name,icmp_proxy,")
       _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,")
       _T("rack_id,rack_image,rack_position,rack_height,")
-      _T("last_agent_comm_time,syslog_msg_count,snmp_trap_count FROM nodes WHERE id=?"));
+      _T("last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
+      _T("node_type,node_subtype FROM nodes WHERE id=?"));
        if (hStmt == NULL)
                return false;
 
@@ -365,6 +370,8 @@ bool Node::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
    m_lastAgentCommTime = DBGetFieldLong(hResult, 0, 37);
    m_syslogMessageCount = DBGetFieldInt64(hResult, 0, 38);
    m_snmpTrapCount = DBGetFieldInt64(hResult, 0, 39);
+   m_type = (NodeType)DBGetFieldLong(hResult, 0, 40);
+   DBGetField(hResult, 0, 41, m_subType, MAX_NODE_SUBTYPE_LENGTH);
 
    DBFreeResult(hResult);
        DBFreeStatement(hStmt);
@@ -461,7 +468,7 @@ BOOL Node::saveToDatabase(DB_HANDLE hdb)
                        _T("use_ifxtable=?,usm_auth_password=?,usm_priv_password=?,usm_methods=?,snmp_sys_name=?,bridge_base_addr=?,")
                        _T("runtime_flags=?,down_since=?,driver_name=?,rack_image=?,rack_position=?,rack_height=?,rack_id=?,boot_time=?,")
          _T("agent_cache_mode=?,snmp_sys_contact=?,snmp_sys_location=?,last_agent_comm_time=?,")
-         _T("syslog_msg_count=?,snmp_trap_count=? WHERE id=?"));
+         _T("syslog_msg_count=?,snmp_trap_count=?,node_type=?,node_subtype=? WHERE id=?"));
        }
    else
        {
@@ -470,8 +477,9 @@ BOOL Node::saveToDatabase(DB_HANDLE hdb)
                  _T("agent_port,auth_method,secret,snmp_oid,uname,agent_version,platform_name,poller_node_id,zone_guid,")
                  _T("proxy_node,snmp_proxy,icmp_proxy,required_polls,use_ifxtable,usm_auth_password,usm_priv_password,usm_methods,")
                  _T("snmp_sys_name,bridge_base_addr,runtime_flags,down_since,driver_name,rack_image,rack_position,rack_height,rack_id,boot_time,")
-        _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,last_agent_comm_time,syslog_msg_count,snmp_trap_count,id) ")
-                 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+        _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
+        _T("node_type,node_subtype,id) ")
+                 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
        }
        if (hStmt == NULL)
        {
@@ -530,7 +538,9 @@ BOOL Node::saveToDatabase(DB_HANDLE hdb)
        DBBind(hStmt, 38, DB_SQLTYPE_INTEGER, (LONG)m_lastAgentCommTime);
    DBBind(hStmt, 39, DB_SQLTYPE_BIGINT, m_syslogMessageCount);
    DBBind(hStmt, 40, DB_SQLTYPE_BIGINT, m_snmpTrapCount);
-       DBBind(hStmt, 41, DB_SQLTYPE_INTEGER, m_id);
+   DBBind(hStmt, 41, DB_SQLTYPE_INTEGER, (INT32)m_type);
+   DBBind(hStmt, 42, DB_SQLTYPE_VARCHAR, m_subType, DB_BIND_STATIC);
+       DBBind(hStmt, 43, DB_SQLTYPE_INTEGER, m_id);
 
        BOOL bResult = DBExecute(hStmt);
        DBFreeStatement(hStmt);
@@ -2233,6 +2243,19 @@ void Node::configurationPoll(ClientSession *pSession, UINT32 dwRqId, PollerInfo
          agentUnlock();
       }
 
+               // Update node type
+               NodeType type = detectNodeType();
+      nxlog_debug(5, _T("ConfPoll(%s): detected node type: %d (%s)"), m_name, type, typeName(type));
+               lockProperties();
+               if ((type != NODE_TYPE_UNKNOWN) && (type != m_type))
+               {
+                  m_type = type;
+                  hasChanges = true;
+                  nxlog_debug(5, _T("ConfPoll(%s): node type set to %d (%s)"), m_name, type, typeName(type));
+         sendPollerMsg(dwRqId, _T("   Node type changed to %s\r\n"), typeName(type));
+               }
+               unlockProperties();
+
                // Execute hook script
                poller->setStatus(_T("hook"));
                executeHookScript(_T("ConfigurationPoll"));
@@ -2259,6 +2282,34 @@ void Node::configurationPoll(ClientSession *pSession, UINT32 dwRqId, PollerInfo
    }
 }
 
+/**
+ * Detect node type
+ */
+NodeType Node::detectNodeType()
+{
+   NodeType type = NODE_TYPE_UNKNOWN;
+   if (m_dwFlags & NF_IS_SNMP)
+   {
+      nxlog_debug(6, _T("Node::detectNodeType(%s [%d]): SNMP node, driver name is %s"), m_name, m_id, m_driver->getName());
+
+      // Assume physical device if it supports SNMP and driver is not "GENERIC"
+      // FIXME: add driver method to determine node type
+      if (_tcscmp(m_driver->getName(), _T("GENERIC")))
+      {
+         type = NODE_TYPE_PHYSICAL;
+      }
+      else
+      {
+         if (m_dwFlags & NF_IS_PRINTER)
+         {
+            // Assume that printers are physical devices
+            type = NODE_TYPE_PHYSICAL;
+         }
+      }
+   }
+   return type;
+}
+
 /**
  * Configuration poll: check for NetXMS agent
  */
@@ -4635,6 +4686,8 @@ void Node::fillMessageInternal(NXCPMessage *pMsg)
    DataCollectionTarget::fillMessageInternal(pMsg);
    pMsg->setField(VID_IP_ADDRESS, m_ipAddress);
        pMsg->setField(VID_PRIMARY_NAME, m_primaryName);
+   pMsg->setField(VID_NODE_TYPE, (INT16)m_type);
+   pMsg->setField(VID_NODE_SUBTYPE, m_subType);
    pMsg->setField(VID_FLAGS, m_dwFlags);
    pMsg->setField(VID_RUNTIME_FLAGS, m_dwDynamicFlags);
    pMsg->setField(VID_AGENT_PORT, m_agentPort);
@@ -7682,3 +7735,12 @@ void Node::collectProxyInfo(ProxyInfo *info)
    if (isTarget)
       addProxySnmpTarget(info, this);
 }
+
+/**
+ * Get node type name from type
+ */
+const TCHAR *Node::typeName(NodeType type)
+{
+   static const TCHAR *names[] = { _T("Unknown"), _T("Physical"), _T("Virtual"), _T("Controller") };
+   return ((type >= 0) && (type < sizeof(names) / sizeof(const TCHAR *))) ? names[type] : names[0];
+}
index bfc50d2..8565ff3 100644 (file)
@@ -472,10 +472,18 @@ NXSL_Value *NXSL_NodeClass::getAttr(NXSL_Object *object, const TCHAR *attr)
    {
       value = new NXSL_Value((LONG)node->getSNMPVersion());
    }
+   else if (!_tcscmp(attr, _T("subType")))
+   {
+      value = new NXSL_Value(node->getSubType());
+   }
    else if (!_tcscmp(attr, _T("sysDescription")))
    {
       value = new NXSL_Value(node->getSysDescription());
    }
+   else if (!_tcscmp(attr, _T("type")))
+   {
+      value = new NXSL_Value((INT32)node->getType());
+   }
    else if (!_tcscmp(attr, _T("zone")))
        {
       if (g_flags & AF_ENABLE_ZONING)
index b0aee07..5810c5b 100644 (file)
@@ -1247,6 +1247,17 @@ public:
 class Subnet;
 struct ProxyInfo;
 
+/**
+ * Node subtypes
+ */
+enum NodeType
+{
+   NODE_TYPE_UNKNOWN = 0,
+   NODE_TYPE_PHYSICAL = 1,
+   NODE_TYPE_VIRTUAL = 2,
+   NODE_TYPE_CONTROLLER = 3
+};
+
 /**
  * Node
  */
@@ -1276,6 +1287,8 @@ protected:
        TCHAR m_primaryName[MAX_DNS_NAME];
    UINT32 m_dwFlags;
    UINT32 m_dwDynamicFlags;       // Flags used at runtime by server
+   NodeType m_type;
+   TCHAR m_subType[MAX_NODE_SUBTYPE_LENGTH];
        int m_iPendingStatus;
        int m_iPollCount;
        int m_iRequiredPollCount;
@@ -1384,6 +1397,7 @@ protected:
        void updatePrimaryIpAddr();
        bool confPollAgent(UINT32 dwRqId);
        bool confPollSnmp(UINT32 dwRqId);
+       NodeType detectNodeType();
        bool querySnmpSysProperty(SNMP_Transport *snmp, const TCHAR *oid, const TCHAR *propName, UINT32 pollRqId, TCHAR **value);
        void checkBridgeMib(SNMP_Transport *pTransport);
        void checkIfXTable(SNMP_Transport *pTransport);
@@ -1439,6 +1453,8 @@ public:
 
    const InetAddress& getIpAddress() const { return m_ipAddress; }
    UINT32 getZoneId() const { return m_zoneId; }
+   NodeType getType() const { return m_type; }
+   const TCHAR *getSubType() const { return m_subType; }
    UINT32 getFlags() const { return m_dwFlags; }
    UINT32 getRuntimeFlags() const { return m_dwDynamicFlags; }
    void setFlag(UINT32 flag) { lockProperties(); m_dwFlags |= flag; setModified(); unlockProperties(); }
@@ -1625,6 +1641,8 @@ public:
 
        void incSyslogMessageCount();
        void incSnmpTrapCount();
+
+       static const TCHAR *typeName(NodeType type);
 };
 
 /**
index fd31874..a0447a8 100644 (file)
@@ -683,6 +683,22 @@ static bool SetSchemaVersion(int version)
    return SQLQuery(query);
 }
 
+/**
+ * Upgrade from V408 to V409
+ */
+static BOOL H_UpgradeFromV408(int currVersion, int newVersion)
+{
+   static const TCHAR *batch =
+      _T("ALTER TABLE nodes ADD node_type integer\n")
+      _T("ALTER TABLE nodes ADD node_subtype varchar(127)\n")
+      _T("UPDATE nodes SET node_type=0\n")
+      _T("<END>");
+   CHK_EXEC(SQLBatch(batch));
+
+   CHK_EXEC(SetSchemaVersion(409));
+   return TRUE;
+}
+
 /**
  * Upgrade from V407 to V408
  */
@@ -10285,6 +10301,7 @@ static struct
    { 405, 406, H_UpgradeFromV405 },
    { 406, 407, H_UpgradeFromV406 },
    { 407, 408, H_UpgradeFromV407 },
+   { 408, 409, H_UpgradeFromV408 },
    { 0, 0, NULL }
 };
 
index 26b7fd4..c350f50 100644 (file)
@@ -150,6 +150,7 @@ public class GeneralInfo extends TableElement
                                if ((node.getFlags() & AbstractNode.NF_IS_BRIDGE) != 0)
                                        addPair(Messages.get().GeneralInfo_BridgeBaseAddress, node.getBridgeBaseAddress().toString());
                                addPair(Messages.get().GeneralInfo_Driver, node.getDriverName(), false);
+            addPair("Node Type", node.getNodeType().toString(), false);
             if (node.getBootTime() != null)
                addPair(Messages.get().GeneralInfo_BootTime, RegionalSettings.getDateTimeFormat().format(node.getBootTime()), false);
             if (node.hasAgent())