Initial commit for vmgr subagent
authorzev <zev@radensolutions.com>
Tue, 19 Jul 2016 14:09:51 +0000 (17:09 +0300)
committerzev <zev@radensolutions.com>
Tue, 19 Jul 2016 14:14:31 +0000 (17:14 +0300)
configure.ac
include/nms_util.h
libsqlplus.so [new file with mode: 0755]
src/agent/subagents/vmgr/Makefile.am [new file with mode: 0644]
src/agent/subagents/vmgr/dataproviders.cpp [new file with mode: 0644]
src/agent/subagents/vmgr/hostconnections.cpp [new file with mode: 0644]
src/agent/subagents/vmgr/vmgr.cpp [new file with mode: 0644]
src/agent/subagents/vmgr/vmgr.h [new file with mode: 0644]

index bd852c3..6a4c7b8 100644 (file)
@@ -102,6 +102,7 @@ DISABLE_READLINE="no"
 TUXEDO_LIBS=""
 TUXEDO_TPINIT=""
 MONGODB_LIBS=""
+VMGR_LIBS=""
 DISABLE_IPV6="no"
 IPV6_SUPPORT="no"
 INSTALL_LIBPATH=""
@@ -301,6 +302,15 @@ AC_ARG_WITH(mongodb,
        COMPONENTS="$COMPONENTS mongodb"
 fi ])
 
+AC_ARG_WITH(vmgr,
+[AS_HELP_STRING(--with-vmgr,build VirtualHost managmet subagent)],
+[ if test "x$withval" != "xno" ; then
+       if test "x$withval" != "x" && test "x$withval" != "xyes" ; then
+               VMGR_BASE="$withval"
+       fi
+       COMPONENTS="$COMPONENTS vmgr"
+fi ])
+
 AC_ARG_WITH(sqlite,
 [AS_HELP_STRING(--with-sqlite,build SQLite database driver)],
 [ if test "x$withval" != "xno" ; then
@@ -561,7 +571,7 @@ AC_ARG_WITH(dist,
 [AS_HELP_STRING(--with-dist,for maintainers only)],
        DB_DRIVERS=" mysql pgsql odbc mssql sqlite oracle db2 informix"
        MODULES="appagent jansson libexpat libstrophe libtre zlib libnetxms install sqlite snmp libnxsl libnxmb libnxlp libnxcc db server smsdrv agent libnxmap client nxscript nxcproxy nxlptest tools"
-       SUBAGENT_DIRS="linux ds18x20 freebsd openbsd minix netbsd sunos aix ipso hpux odbcquery informix oracle lmsensors darwin rpi java ubntlw netsvc db2 tuxedo mongodb"
+       SUBAGENT_DIRS="linux ds18x20 freebsd openbsd minix netbsd sunos aix ipso hpux odbcquery informix oracle lmsensors darwin rpi java ubntlw netsvc db2 tuxedo mongodb vmgr"
        AGENT_DIRS="libnxtux"
        SMSDRV_DIRS="kannel nxagent slack text2reach websms"
    HDLINK_DIRS="jira"
@@ -848,6 +858,11 @@ if test $? = 0; then
        SUBAGENT_DIRS="$SUBAGENT_DIRS mongodb"
 fi
 
+check_substr "$COMPONENTS" "vmgr"
+if test $? = 0; then
+       SUBAGENT_DIRS="$SUBAGENT_DIRS vmgr"
+fi
+
 check_substr "$COMPONENTS" "sdk"
 if test $? = 0; then
        if test "x$STATIC_BUILD" = "xyes"; then
@@ -2909,7 +2924,7 @@ if test $? = 0; then
                MONGODB_LDFLAGS="-L/usr/local/lib"
                CPPFLAGS="$CPPFLAGS $MONGODB_CPPFLAGS"
                LDFLAGS="$LDFLAGS $MONGODB_LDFLAGS"
-    fi
+       fi
        
        AC_CHECK_HEADER(mongoc.h,,AC_MSG_ERROR([*** Cannot find mongoc.h - check your MongoDB installation ***]))
        AC_CHECK_LIB(mongoc-1.0, nanosleep, [ MONGODB_LIBS="$MONGODB_LIBS -lmongoc-1.0" ])
@@ -2922,6 +2937,37 @@ if test $? = 0; then
        LIBS="$OLD_LIBS"
 fi
 
+#--------------------------------------------------------------------
+# VMGR
+#--------------------------------------------------------------------
+
+check_substr "$COMPONENTS" "vmgr"
+if test $? = 0; then
+       OLD_CPPFLAGS="$CPPFLAGS"
+       OLD_LDFLAGS="$LDFLAGS"
+       OLD_LIBS="$LIBS"
+
+       if test "x$VMGR_BASE" != "x"; then
+               VMGR_CPPFLAGS="-I$VMGR_BASE/include/libvirt/"
+               VMGR_LDFLAGS="-L$VMGR_BASE/lib"
+               CPPFLAGS="$CPPFLAGS $VMGR_CPPFLAGS"
+               LDFLAGS="$LDFLAGS $VMGR_LDFLAGS"
+       else
+               VMGR_CPPFLAGS="-I/usr/include/libvirt/"
+               VMGR_LDFLAGS="-L/usr/lib"
+               CPPFLAGS="$CPPFLAGS $VMGR_CPPFLAGS"
+               LDFLAGS="$LDFLAGS $VMGR_LDFLAGS"
+       fi
+       
+       AC_CHECK_HEADER(libvirt.h,,AC_MSG_ERROR([*** Cannot find libvirt.h - check your libvirt installation ***]))
+       AC_CHECK_LIB(virt, nanosleep, [ VMGR_LIBS="$VMGR_LIBS -lvirt" ])
+       LIBS="$LIBS $VMGR_LIBS"
+
+       CPPFLAGS="$OLD_CPPFLAGS"
+       LDFLAGS="$OLD_LDFLAGS"
+       LIBS="$OLD_LIBS"
+fi
+
 #--------------------------------------------------------------------
 # Other settings
 #--------------------------------------------------------------------
@@ -3040,6 +3086,9 @@ AC_SUBST(TUXEDO_TPINIT)
 AC_SUBST(MONGODB_CPPFLAGS)
 AC_SUBST(MONGODB_LDFLAGS)
 AC_SUBST(MONGODB_LIBS)
+AC_SUBST(VMGR_CPPFLAGS)
+AC_SUBST(VMGR_LDFLAGS)
+AC_SUBST(VMGR_LIBS)
 AC_SUBST(INSTALL_LIBPATH)
 AC_SUBST(ZEROMQ_CPPFLAGS)
 AC_SUBST(ZEROMQ_LDFLAGS)
@@ -3162,6 +3211,7 @@ AC_CONFIG_FILES([
        src/agent/subagents/mongodb/Makefile
        src/agent/subagents/ubntlw/Makefile
        src/agent/subagents/ups/Makefile
+       src/agent/subagents/vmgr/Makefile
        src/agent/subagents/winnt/Makefile
        src/agent/subagents/winperf/Makefile
        src/agent/subagents/wmi/Makefile
@@ -3499,6 +3549,13 @@ if test "x${ZEROMQ_LDFLAGS}" != "x"; then
        echo "ZeroMQ LDFLAGS          : ${ZEROMQ_LDFLAGS}"
 fi
 
+if test "x${VMGR_CPPFLAGS}" != "x"; then
+       echo "Vmgr CPPFLAGS     : ${VMGR_CPPFLAGS}"
+fi
+if test "x${VMGR_LDFLAGS}" != "x"; then
+       echo "Vmgr LDFLAGS         : ${VMGR_LDFLAGS}"
+fi
+
 FLAGS_CPP="src/tools/nxdevcfg/flags.cpp"
 echo "/* Automatically generated by configure */" > $FLAGS_CPP
 echo "#include <nms_common.h>" >> $FLAGS_CPP
index 4bef06d..1d12c07 100644 (file)
@@ -621,6 +621,7 @@ public:
        StringObjectMap(bool objectOwner) : StringMapBase(objectOwner) { m_objectDestructor = destructor; }
 
        void set(const TCHAR *key, T *object) { setObject((TCHAR *)key, (void *)object, false); }
+       void setPreallocated(TCHAR *key, T *object) { setObject((TCHAR *)key, (void *)object, true); }
        T *get(const TCHAR *key) const { return (T*)getObject(key); }
 };
 
diff --git a/libsqlplus.so b/libsqlplus.so
new file mode 100755 (executable)
index 0000000..fcf5b39
Binary files /dev/null and b/libsqlplus.so differ
diff --git a/src/agent/subagents/vmgr/Makefile.am b/src/agent/subagents/vmgr/Makefile.am
new file mode 100644 (file)
index 0000000..7ed6066
--- /dev/null
@@ -0,0 +1,18 @@
+SUBAGENT = vmgr
+
+pkglib_LTLIBRARIES = vmgr.la
+vmgr_la_SOURCES = vmgr.cpp hostconnections.cpp dataproviders.cpp
+vmgr_la_CPPFLAGS=-I@top_srcdir@/include @VMGR_CPPFLAGS@
+vmgr_la_LDFLAGS = -module -avoid-version -export-symbols ../subagent.sym @VMGR_LDFLAGS@
+vmgr_la_LIBADD = ../../libnxagent/libnxagent.la ../../../libnetxms/libnetxms.la @VMGR_LIBS@
+
+EXTRA_DIST = vmgr.vcproj vmgr.h
+
+if !STATIC_BUILD
+install-exec-hook:
+       if test "x`uname -s`" = "xAIX" ; then OBJECT_MODE=@OBJECT_MODE@ $(AR) x $(DESTDIR)$(pkglibdir)/$(SUBAGENT).a $(DESTDIR)$(pkglibdir)/$(SUBAGENT)@SHLIB_SUFFIX@ ; rm -f $(DESTDIR)$(pkglibdir)/$(SUBAGENT).a ; fi
+       mv -f $(DESTDIR)$(pkglibdir)/$(SUBAGENT)@SHLIB_SUFFIX@ $(DESTDIR)$(pkglibdir)/$(SUBAGENT).nsm
+       rm -f $(DESTDIR)$(pkglibdir)/$(SUBAGENT).la
+       rm -f $(DESTDIR)$(libdir)/libnsm_$(SUBAGENT)@SHLIB_SUFFIX@
+       ln -s netxms/$(SUBAGENT).nsm $(DESTDIR)$(libdir)/libnsm_$(SUBAGENT)@SHLIB_SUFFIX@
+endif
diff --git a/src/agent/subagents/vmgr/dataproviders.cpp b/src/agent/subagents/vmgr/dataproviders.cpp
new file mode 100644 (file)
index 0000000..2d63198
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ ** File management subagent
+ ** Copyright (C) 2016 Raden Solutions
+ **
+ ** 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.
+ **
+ **/
+
+#include "vmgr.h"
+
+
+/**
+ * --------------------------------
+ * Parameter, list, table providers
+ * --------------------------------
+ */
+
+/**
+ * Get list of configured VMs
+ */
+LONG H_GetHostList(const TCHAR *cmd, const TCHAR *arg, StringList *value, AbstractCommSession *session)
+{
+   StringList *keyList = g_connectionList.keys();
+       for(int i = 0; i < keyList->size(); i++)
+               value->add(keyList->get(i));
+       return SYSINFO_RC_SUCCESS;
+}
+
+/**
+ * Get parameter form capabilities
+ */
+LONG H_GetFromCapabilities(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
+{
+   TCHAR name[256];
+
+       if (!AgentGetParameterArg(pszParam, 1, name, 256))
+               return SYSINFO_RC_UNSUPPORTED;
+
+   HostConnections *conn = g_connectionList.get(name);
+   if(conn == NULL)
+      return SYSINFO_RC_NO_SUCH_INSTANCE;
+
+   const char *xml = conn->getCapabilitiesAndLock();
+   if(xml == NULL)
+      return SYSINFO_RC_ERROR;
+
+   Config conf;
+   if(!conf.loadXmlConfigFromMemory(xml, strlen(xml), NULL, "capabilities", false))
+      return SYSINFO_RC_ERROR;
+
+   ret_string(pValue, conf.getValue(pArg, _T("")));
+   conn->unlockCapabilities();
+       return SYSINFO_RC_SUCCESS;
+}
+
+/**
+ * Get UINT32 parameters
+ */
+LONG H_GetUIntParam(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
+{
+   TCHAR name[256];
+
+       if (!AgentGetParameterArg(pszParam, 1, name, 256))
+               return SYSINFO_RC_UNSUPPORTED;
+
+   HostConnections *conn = g_connectionList.get(name);
+   if(conn == NULL)
+      return SYSINFO_RC_NO_SUCH_INSTANCE;
+
+   UINT32 resultValue = 0;
+   LONG result = SYSINFO_RC_SUCCESS;
+
+   switch(*pArg)
+   {
+      case 'C': //CPU.MaxCount
+         resultValue = conn->getMaxVCpuCount();
+         if(resultValue == -1)
+            result = SYSINFO_RC_UNSUPPORTED;
+         break;
+      case 'F': //CPU.Frequency
+      {
+         const virNodeInfo *nodeInfo = conn->getNodeInfoAndLock();
+         if(nodeInfo == NULL)
+         {
+            result = SYSINFO_RC_UNSUPPORTED;
+         }
+         else
+         {
+            resultValue = nodeInfo->mhz;
+         }
+         break;
+         conn->unlockNodeInfo();
+      }
+      default:
+         result = SYSINFO_RC_ERROR;
+   }
+
+   ret_uint(pValue, resultValue);
+
+       return result;
+}
+
+/**
+ * Get UINT64 parameters
+ */
+LONG H_GetUInt64Param(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
+{
+   TCHAR name[256];
+
+       if (!AgentGetParameterArg(pszParam, 1, name, 256))
+               return SYSINFO_RC_UNSUPPORTED;
+
+   HostConnections *conn = g_connectionList.get(name);
+   if(conn == NULL)
+      return SYSINFO_RC_NO_SUCH_INSTANCE;
+
+   UINT64 resultValue = 0;
+   LONG result = SYSINFO_RC_SUCCESS;
+
+   switch(*pArg)
+   {
+      case 'F': //FreeMemory
+         resultValue = conn->getHostFreeMemory();
+         if(resultValue == 0)
+         {
+            result = SYSINFO_RC_UNSUPPORTED;
+         }
+         else
+            resultValue*1024;
+         break;
+      case 'M': //MemorySize
+      {
+         const virNodeInfo *nodeInfo = conn->getNodeInfoAndLock();
+         if(nodeInfo == NULL)
+         {
+            result = SYSINFO_RC_UNSUPPORTED;
+         }
+         else
+         {
+            resultValue = nodeInfo->memory*1024;
+         }
+         break;
+         conn->unlockNodeInfo();
+      }
+      case 'V': //ConnectionVersion
+         resultValue = conn->getConnectionVersion();
+         if(resultValue == -1)
+         {
+            result = SYSINFO_RC_UNSUPPORTED;
+         }
+         break;
+      case 'L': //LibraryVersion
+         resultValue = conn->getLibraryVersion();
+         if(resultValue == -1)
+         {
+            result = SYSINFO_RC_UNSUPPORTED;
+         }
+         break;
+      default:
+         result = SYSINFO_RC_ERROR;
+   }
+
+   ret_uint64(pValue, resultValue);
+
+       return result;
+}
+
+/**
+ * Get string parameters
+ */
+LONG H_GetStringParam(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
+{
+   TCHAR name[256];
+
+       if (!AgentGetParameterArg(pszParam, 1, name, 256))
+               return SYSINFO_RC_UNSUPPORTED;
+
+   HostConnections *conn = g_connectionList.get(name);
+   if(conn == NULL)
+      return SYSINFO_RC_NO_SUCH_INSTANCE;
+
+   char *resultValue = NULL;
+   LONG result = SYSINFO_RC_SUCCESS;
+
+   switch(*pArg)
+   {
+      case 'M': //Model
+      {
+         const virNodeInfo *nodeInfo = conn->getNodeInfoAndLock();
+         if(nodeInfo == NULL)
+         {
+            result = SYSINFO_RC_UNSUPPORTED;
+         }
+         else
+         {
+            resultValue = (char *)nodeInfo->model;
+         }
+         break;
+         conn->unlockNodeInfo();
+      }
+      case 'C': //ConnectionType
+         resultValue = (char *)conn->getConnectionType();
+         if(resultValue == NULL)
+            result = SYSINFO_RC_UNSUPPORTED;
+         break;
+      default:
+         result = SYSINFO_RC_ERROR;
+   }
+
+   ret_mbstring(pValue, resultValue);
+
+       return result;
+}
+
+/**
+ * Get domain(VM) list
+ */
+LONG H_GetVMList(const TCHAR *cmd, const TCHAR *arg, StringList *value, AbstractCommSession *session)
+{
+   TCHAR name[256];
+
+       if (!AgentGetParameterArg(cmd, 1, name, 256))
+               return SYSINFO_RC_UNSUPPORTED;
+
+   HostConnections *conn = g_connectionList.get(name);
+   if(conn == NULL)
+      return SYSINFO_RC_NO_SUCH_INSTANCE;
+
+   StringList *keyList = conn->getDomainListAndLock()->keys();
+       for(int i = 0; i < keyList->size(); i++)
+               value->add(keyList->get(i));
+   conn->unlockDomainList();
+       return SYSINFO_RC_SUCCESS;
+}
+
+static const TCHAR *vmStateMapping[] =
+{
+   _T("no state"),
+   _T("Running"),
+   _T("blocked on resource"),
+   _T("paused by user"),
+   _T("shut down"),
+   _T("shut off"),
+   _T("crashed"),
+   _T("suspended by guest power management")
+};
+
+static const TCHAR *vmOpStateMapping[] =
+{
+   _T("Ready to accept commands"),
+   _T("Background job is running"),
+   _T("Occupied by a running command"),
+   _T("Unusable")
+};
+
+static const TCHAR *vmOpStateDescMapping[] =
+{
+   _T("No reason"),
+   _T("Unknown"),
+   _T("Monitor connection is broken"),
+   _T("Error caused due to internal failure in libvirt")
+};
+
+EnumerationCallbackResult FillVMData(const TCHAR *key, const void *obj, void *userData)
+{
+   virDomainPtr vm = (virDomainPtr)obj;
+   Table *value = (Table *)userData;
+
+   value->addRow();
+   value->set(0, virDomainGetID(vm));
+   value->set(1, key);
+   char uuid[VIR_UUID_STRING_BUFLEN];
+   if(virDomainGetUUIDString(vm,uuid) == 0)
+      value->set(2, uuid);
+   else
+      value->set(2, _T(""));
+   virDomainInfo info;
+   if(virDomainGetInfo(vm, &info) == 0)
+   {
+      value->set(3, info.state < 8 ? vmStateMapping[info.state] :  _T("Unkonown"));
+      value->set(6, (UINT64)info.maxMem);
+      value->set(7, (UINT64)info.memory);
+      value->set(8, info.nrVirtCpu);
+      value->set(9, info.cpuTime);
+   }
+   else
+   {
+      value->set(3, _T("Unkonown"));
+      value->set(6, 0);
+      value->set(7, 0);
+      value->set(8, 0);
+      value->set(9, 0);
+   }
+
+   char *osType = virDomainGetOSType(vm);
+   if(osType != NULL)
+   {
+      value->set(4, osType);
+      free(osType);
+   }
+   else
+      value->set(4, _T("Unkonown"));
+
+   int autostart;
+   if(virDomainGetAutostart(vm, &autostart) == 0)
+   {
+      value->set(5, autostart == 0 ? _T("No") : _T("Yes"));
+   }
+   else
+      value->set(5, _T("Unkonown"));
+
+   virDomainControlInfo cInfo;
+   if(virDomainGetControlInfo(vm, &cInfo,0) == 0)
+   {
+      value->set(10, cInfo.state > 4 ? _T("Unknown") : vmOpStateMapping[cInfo.state]);
+      value->set(11, cInfo.details > 4 ? _T("Unknown") : vmOpStateDescMapping[cInfo.details]);
+      value->set(12, cInfo.stateTime);
+   }
+   else
+   {
+      value->set(10, _T("Unkonown"));
+      value->set(11, _T(""));
+      value->set(12, 0);
+   }
+
+   INT64 seconds;
+   UINT32 nsec;
+   if(virDomainGetTime(vm, &seconds, &nsec, 0) == 0)
+      value->set(13, seconds);
+   else
+      value->set(13, 0);
+
+   int pers = virDomainIsPersistent(vm);
+   value->set(14, pers == -1 ? _T("Unknown") : pers == 1 ? _T("Yes") : _T("No"));
+
+   return _CONTINUE;
+}
+
+/**
+ * Get domain(VM) table
+ */
+LONG H_GetVMTable(const TCHAR *cmd, const TCHAR *arg, Table *value, AbstractCommSession *)
+{
+   TCHAR name[256];
+
+       if (!AgentGetParameterArg(cmd, 1, name, 256))
+               return SYSINFO_RC_UNSUPPORTED;
+
+   HostConnections *conn = g_connectionList.get(name);
+   if(conn == NULL)
+      return SYSINFO_RC_NO_SUCH_INSTANCE;
+
+   const StringObjectMap<virDomain> *domains = conn->getDomainListAndLock();
+
+   value->addColumn(_T("ID"), DCI_DT_UINT, _T("ID"));
+       value->addColumn(_T("NAME"), DCI_DT_STRING, _T("Name"), true);
+       value->addColumn(_T("UUID"), DCI_DT_STRING, _T("UUID"));
+       value->addColumn(_T("STATE"), DCI_DT_STRING, _T("State"));
+       value->addColumn(_T("OS"), DCI_DT_STRING, _T("OS"));
+       value->addColumn(_T("AUTOSTART"), DCI_DT_STRING, _T("Autostart scheduled"));
+       value->addColumn(_T("MAX_MEMORY"), DCI_DT_UINT64, _T("Maximum VM available memory"));
+       value->addColumn(_T("MEMORY"), DCI_DT_UINT64, _T("Memory currently used by VM"));
+       value->addColumn(_T("VIRTUAL_CPU_COUNT"), DCI_DT_UINT, _T("CPU count available for VM"));
+       value->addColumn(_T("VIRTUAL_CPU_TIME"), DCI_DT_UINT64, _T("CPU time used for VM in nanoseconds"));
+       value->addColumn(_T("CONTROL_STATE"), DCI_DT_STRING, _T("VM control state"));
+       value->addColumn(_T("STATE_DETAILS"), DCI_DT_STRING, _T("VM control state details"));
+       value->addColumn(_T("CONTROL_STATE_DURATION"), DCI_DT_UINT, _T("Time since VM entered the control state"));
+       value->addColumn(_T("TIME"), DCI_DT_UINT, _T("Current VM time")); // +DISPLAY NAME AND TYPE
+       value->addColumn(_T("IS_PERSISTENT"), DCI_DT_STRING, _T("VM is persistent"));
+
+   domains->forEach(FillVMData, value);
+   conn->unlockDomainList();
+   return SYSINFO_RC_SUCCESS;
+}
+
+
+
+/**
+ * Get domain(VM) table
+ */
+LONG H_GetIfaceTable(const TCHAR *cmd, const TCHAR *arg, Table *value, AbstractCommSession *)
+{
+   TCHAR name[256];
+   if (!AgentGetParameterArg(cmd, 1, name, 256))
+   return SYSINFO_RC_UNSUPPORTED;
+
+   HostConnections *conn = g_connectionList.get(name);
+   if(conn == NULL)
+      return SYSINFO_RC_NO_SUCH_INSTANCE;
+
+   const StringList *ifaceList = conn->getIfaceListAndLock();
+
+   value->addColumn(_T("NAME"), DCI_DT_STRING, _T("Name"), true);
+   for(int i=0; i < ifaceList->size(); i++)
+   {
+      value->addRow();
+      value->set(0, ifaceList->get(i));
+   }
+
+   conn->unlockIfaceList();
+   return SYSINFO_RC_SUCCESS;
+}
diff --git a/src/agent/subagents/vmgr/hostconnections.cpp b/src/agent/subagents/vmgr/hostconnections.cpp
new file mode 100644 (file)
index 0000000..2ed51b3
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ ** File management subagent
+ ** Copyright (C) 2016 Raden Solutions
+ **
+ ** 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.
+ **
+ **/
+
+#include "vmgr.h"
+
+/**
+ * Host connection constructor
+ */
+HostConnections::HostConnections(const TCHAR *name, const char *url, const char *login, const char *password)
+{
+   m_name = _tcsdup(name);
+   m_url = strdup(url);
+   m_login = strdup(login);
+   m_password = strdup(password);
+   m_domains.setMalloc(false);
+   m_iface.setMalloc(false);
+}
+
+/**
+ * Host connection initial constructor
+ */
+HostConnections::~HostConnections()
+{
+   disconnect();
+   free(m_url);
+   free(m_name);
+   free(m_login);
+   free(m_password);
+}
+
+/**
+ * Authentication callback
+ */
+int HostConnections::authCb(virConnectCredentialPtr cred, unsigned int ncred, void *cbdata)
+{
+   HostConnections *obj = (HostConnections *)cbdata;
+   for (int i = 0; i < ncred; i++)
+   {
+      if (cred[i].type == VIR_CRED_AUTHNAME)
+      {
+         cred[i].result = strdup(obj->m_login);
+         cred[i].resultlen = strlen(obj->m_login);
+      }
+      else if (cred[i].type == VIR_CRED_PASSPHRASE)
+      {
+         cred[i].result = strdup(obj->m_password);
+         cred[i].resultlen = strlen(obj->m_password);
+      }
+    }
+
+    return 0;
+}
+
+/**
+ * Authentication credentials
+ */
+static int authCreds[] = {
+    VIR_CRED_AUTHNAME,
+    VIR_CRED_PASSPHRASE,
+};
+
+/**
+ * Function that initiate connection to host
+ */
+bool HostConnections::connect()
+{
+   virConnectAuth auth;
+   auth.cb = authCb;
+   auth.cbdata = this;
+   auth.credtype = authCreds;
+   auth.ncredtype = sizeof(authCreds)/sizeof(int);
+   m_connection = virConnectOpenAuth(m_url, &auth, 0);
+   return m_connection != NULL;
+}
+
+/**
+ * Function that close connection to host and cleans all libvirt specific data
+ */
+void HostConnections::disconnect()
+{
+   if(m_connection != NULL)
+      virConnectClose(m_connection);
+}
+
+/**
+ * Updates capability XML chase if required and returns it or null
+ */
+const char *HostConnections::getCapabilitiesAndLock()
+{
+   if(m_capabilities.shouldUpdate())
+   {
+      m_capabilities.setWriteLock();
+      char *caps = virConnectGetCapabilities(m_connection);
+      if (caps == NULL)
+      {
+         virError err;
+         virCopyLastError(&err);
+         AgentWriteLog(6, _T("VMGR: virConnectGetCapabilities failed: %hs"), err.message);
+         virResetError(&err);
+         return NULL;
+      }
+      m_capabilities.updateChaseAndUnlock(caps);
+      //AgentWriteLog(NXLOG_DEBUG, _T("VMGR: Capabilities of connection %hs: %hs"), m_url, caps);
+   }
+
+   return m_capabilities.getDataAndLock();
+}
+
+void HostConnections::unlockCapabilities()
+{
+   m_capabilities.unlock();
+}
+
+/**
+ * Retrieves maximum number of virtual CPUs per-guest the underlying virtualization technology supports, or -1 in case of error
+ */
+UINT32 HostConnections::getMaxVCpuCount()
+{
+   return virConnectGetMaxVcpus(m_connection, NULL);
+}
+
+/**
+ * Retrieves the total amount of free memory on the virtualization host in KiB, or 0 in case of error
+ */
+UINT64 HostConnections::getHostFreeMemory()
+{
+   return virNodeGetFreeMemory(m_connection);
+}
+
+/**
+ * Updates virNodeInfo structure chase if required and returns it or null in case of error
+ */
+const virNodeInfo *HostConnections::getNodeInfoAndLock()
+{
+   if(m_nodeInfo.shouldUpdate())
+   {
+      m_nodeInfo.setWriteLock();
+      virNodeInfo *nodeInfo = (virNodeInfo *) malloc(sizeof(virNodeInfo));
+      if (virNodeGetInfo(m_connection, nodeInfo) == -1)
+      {
+         virError err;
+         virCopyLastError(&err);
+         AgentWriteLog(6, _T("VMGR: virConnectGetCapabilities failed: %hs"), err.message);
+         virResetError(&err);
+         free(nodeInfo);
+         return NULL;
+      }
+      m_nodeInfo.updateChaseAndUnlock(nodeInfo);
+   }
+
+   return m_nodeInfo.getDataAndLock();
+}
+
+void HostConnections::unlockNodeInfo()
+{
+   m_nodeInfo.unlock();
+}
+
+/**
+ * Returns the type of virtualization in use on this connection, or null in case of error
+ */
+const char *HostConnections::getConnectionType()
+{
+   return virConnectGetType(m_connection);
+}
+
+/**
+ * Returns the version of the host virtualization software in use, or -1 in case of error
+ */
+UINT64 HostConnections::getConnectionVersion()
+{
+   unsigned long int ver;
+   if(virConnectGetVersion(m_connection, &ver) == 0)
+      return (UINT64)ver;
+   else
+      return -1;
+}
+
+/**
+ * Returns the version of the libvirt software in use on the host, or -1 in case of error
+ */
+UINT64 HostConnections::getLibraryVersion()
+{
+   unsigned long int ver;
+   if(virConnectGetLibVersion(m_connection, &ver) == 0)
+      return (UINT64)ver;
+   else
+      return -1;
+}
+
+/**---------
+ * Donamins
+ *----------/
+
+/**
+ * List running VMs(domains)
+ */
+const StringObjectMap<virDomain> *HostConnections::getDomainListAndLock()
+{
+   if(m_domains.shouldUpdate())
+   {
+      m_domains.setWriteLock();
+      virDomainPtr *vms;
+      int ret = virConnectListAllDomains(m_connection, &vms, 0);
+      if (ret < 0)
+         return NULL;
+
+      StringObjectMapC<virDomain> *allDomains = new StringObjectMapC<virDomain>(true);
+
+      for (int i = 0; i < ret; i++)
+      {
+#ifdef UNICODE
+         allDomains->setPreallocated(WideStringFromMBString(virDomainGetName(vms[i])), vms[i]);
+#else
+         allDomains->set(virDomainGetName(vms[i]), vms[i]);
+#endif
+      }
+      free(vms);
+      m_domains.updateChaseAndUnlock(allDomains);
+   }
+   return m_domains.getDataAndLock();
+}
+
+void HostConnections::unlockDomainList()
+{
+   m_domains.unlock();
+}
+
+/**---------
+ * Iface
+ */
+
+/**
+ * List interfaces
+ */
+const StringList *HostConnections::getIfaceListAndLock()
+{
+   if(m_iface.shouldUpdate())
+   {
+      m_iface.setWriteLock();
+
+      int activeCount = virConnectNumOfInterfaces(m_connection);
+      int inactiveCount = virConnectNumOfDefinedInterfaces(m_connection);
+      StringList *ifaceList = new StringList();
+
+      if(activeCount != -1)
+      {
+         char **active = (char **)malloc(sizeof(char *) * activeCount);
+         virConnectListInterfaces(m_connection, active, activeCount);
+         for(int i=0; i < activeCount; i++)
+         {
+            virInterfacePtr iface = virInterfaceLookupByName(m_connection, active[i]);
+            //AgentWriteLog(6, _T("VMGR: iface info!!!: %hs"), virInterfaceGetXMLDesc(iface, 0));
+
+            ifaceList->addMBString(active[i]);
+            free(active[i]);
+         }
+         free(active);
+      }
+
+      if(inactiveCount != -1)
+      {
+         char **inactive = (char **)malloc(sizeof(char *) * inactiveCount);
+         virConnectListDefinedInterfaces(m_connection, inactive, inactiveCount);
+         for(int i=0; i < inactiveCount; i++)
+         {
+            virInterfacePtr iface = virInterfaceLookupByName(m_connection, inactive[i]);
+            //AgentWriteLog(6, _T("VMGR: iface info!!!: %hs"), virInterfaceGetXMLDesc(iface, 0));
+
+            ifaceList->addMBString(inactive[i]);
+            free(inactive[i]);
+         }
+         free(inactive);
+      }
+      m_iface.updateChaseAndUnlock(ifaceList);
+   }
+   return m_iface.getDataAndLock();
+}
+
+void HostConnections::unlockIfaceList()
+{
+   m_iface.unlock();
+}
diff --git a/src/agent/subagents/vmgr/vmgr.cpp b/src/agent/subagents/vmgr/vmgr.cpp
new file mode 100644 (file)
index 0000000..1bff845
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ ** File management subagent
+ ** Copyright (C) 2016 Raden Solutions
+ **
+ ** 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.
+ **
+ **/
+
+#include "vmgr.h"
+
+/**
+ * General VM connection list
+ */
+StringObjectMap<HostConnections> g_connectionList(true);
+
+/**
+ * Configuration file template for host list
+ */
+static TCHAR *s_hostList = NULL;
+static NX_CFG_TEMPLATE m_cfgTemplate[] =
+{
+       { _T("Host"), CT_STRING_LIST, _T('\n'), 0, 0, 0, &s_hostList },
+       { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL }
+};
+
+/**
+ * Configuration file template for host detailed configuration
+ */
+static char s_url[512];
+static char s_login[64];
+static char s_password[128];
+static NX_CFG_TEMPLATE m_aditionalCfgTemplate[] =
+{
+       { _T("Url"), CT_MB_STRING, 0, 0, 512, 0, s_url },
+       { _T("Username"), CT_MB_STRING, 0, 0, 64, 0, s_login },
+       { _T("Password"), CT_MB_STRING, 0, 0, 128, 0, s_password },
+       { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL }
+};
+
+/**
+ * Adds connection object to array if it was possible to connect to it
+ */
+bool AddConnection(const TCHAR *name)
+{
+   HostConnections *conn = new HostConnections(name, s_url, s_login, s_password);
+   bool success = conn->connect();
+   if(!success)
+   {
+      delete conn;
+   }
+   else
+   {
+      g_connectionList.set(name, conn);
+   }
+   return success;
+}
+
+void AddHostConfiguraiton(TCHAR *hostName, Config *config)
+{
+   TCHAR section[512];
+   _sntprintf(section, 512, _T("VMGR:%s"), hostName);
+   s_url[0] = 0;
+   s_login[0] = 0;
+   s_password[0] = 0;
+       bool success = config->parseTemplate(section, m_aditionalCfgTemplate);
+       if (success)
+       {
+          StrStripA(s_url);
+          StrStripA(s_login);
+          StrStripA(s_password);
+       }
+
+   if(!success || s_url[0] == 0 || !AddConnection(hostName))
+   {
+      AgentWriteLog(NXLOG_WARNING, _T("VMGR: Unable to add connection URL \"%hs\" for connection name \"%s\""), s_url, hostName);
+   }
+   else
+   {
+      AgentWriteLog(6, _T("VMGR: VM successfully added: URL \"%hs\", name \"%s\""), s_url, hostName);
+   }
+}
+
+
+/**
+ * Callback for global libvirt errors
+ */
+static void customGlobalErrorFunc(void *userdata, virErrorPtr err)
+{
+   int lvl = NXLOG_DEBUG;
+   switch(err->level)
+   {
+   case VIR_ERR_WARNING:
+      lvl = NXLOG_WARNING;
+      break;
+   case VIR_ERR_ERROR:
+      lvl = NXLOG_ERROR;
+      break;
+   default:
+      lvl = NXLOG_DEBUG;
+      break;
+   }
+   AgentWriteLog(lvl, _T("VMGR: %hs"), err->message);
+}
+
+/**
+ * Function that sets all common configurations for libvirt
+ */
+void InitLibvirt()
+{
+   virSetErrorFunc(NULL, customGlobalErrorFunc);
+}
+
+/**
+ * Subagent initialization
+ */
+static BOOL SubagentInit(Config *config)
+{
+       // Parse configuration
+       bool success = config->parseTemplate(_T("VMGR"), m_cfgTemplate);
+       if (success)
+       {
+               if (s_hostList != NULL)
+               {
+         TCHAR *item, *itemEnd;
+         for(item = s_hostList; *item != 0; item = itemEnd + 1)
+         {
+            itemEnd = _tcschr(item, _T('\n'));
+            if (itemEnd != NULL)
+               *itemEnd = 0;
+            StrStrip(item);
+            AddHostConfiguraiton(item, config);
+         }
+               }
+
+               if(s_hostList == NULL || g_connectionList.size() == 0)
+      {
+         AgentWriteLog(NXLOG_ERROR,
+               _T("VMGR: No connection URL found. Vmgr subagent will not be started."));
+         success = false;
+      }
+       }
+       free(s_hostList);
+       InitLibvirt();
+
+   AgentWriteDebugLog(2, _T("VMGR: subagent initialized"));
+   return success;
+}
+
+/**
+ * Called by master agent at unload
+ */
+static void SubagentShutdown()
+{
+   //Preparations for shutdown
+}
+
+/**
+ * Process commands like get files in folder, delete file/folder, copy file/folder, move file/folder
+ */
+static BOOL ProcessCommands(UINT32 command, NXCPMessage *request, NXCPMessage *response, AbstractCommSession *session)
+{
+   switch(command)
+   {
+      default:
+         return FALSE;
+   }
+}
+
+/**
+ * Supported parameters
+ */
+static NETXMS_SUBAGENT_PARAM s_parameters[] =
+{
+   { _T("VMGR.Host.CPU.Arch(*)"), H_GetFromCapabilities, _T("/host/cpu/arch"), DCI_DT_STRING, _T("Host CPU architecture") },
+   { _T("VMGR.Host.CPU.MaxCount(*)"), H_GetUIntParam, _T("C"), DCI_DT_UINT, _T("Host maximum virtual CPU count") },
+   { _T("VMGR.Host.FreeMemory(*)"), H_GetUInt64Param, _T("F"), DCI_DT_UINT64, _T("Host free memory") },
+   { _T("VMGR.Host.MemorySize(*)"), H_GetUInt64Param, _T("M"), DCI_DT_UINT64, _T("Host memory size") },
+   { _T("VMGR.Host.CPU.Model(*)"), H_GetStringParam, _T("M"), DCI_DT_STRING, _T("Host CPU model name") },
+   { _T("VMGR.Host.CPU.Frequency(*)"), H_GetUIntParam, _T("F"), DCI_DT_UINT, _T("Host CPU frequency") },
+   { _T("VMGR.Host.ConnectionType(*)"), H_GetStringParam, _T("C"), DCI_DT_STRING, _T("Connection type") },
+   { _T("VMGR.Host.LibraryVersion(*)"), H_GetUInt64Param, _T("L"), DCI_DT_UINT64, _T("Library version") },
+   { _T("VMGR.Host.ConnectionVersion(*)"), H_GetUInt64Param, _T("V"), DCI_DT_UINT64, _T("Connection version") }
+};
+
+/**
+ * Supported lists(enums)
+ */
+static NETXMS_SUBAGENT_LIST s_lists[] =
+{
+       { _T("VMGR.VMList"), H_GetHostList, NULL },
+       { _T("VMGR.VMList"), H_GetVMList, NULL }
+};
+
+/**
+ * Supported tables
+ */
+static NETXMS_SUBAGENT_TABLE m_tables[] =
+{
+       { _T("VMGR.VM(*)"), H_GetVMTable, NULL, _T("NAME"), _T("Connection VM table") },
+       { _T("VMGR.InterfaceList(*)"), H_GetIfaceTable, NULL, _T("NAME"), _T("Connection interface list") }
+};
+
+/**
+ * Subagent information
+ */
+static NETXMS_SUBAGENT_INFO m_info =
+{
+   NETXMS_SUBAGENT_INFO_MAGIC,
+   _T("VMGR"), NETXMS_VERSION_STRING,
+   SubagentInit, SubagentShutdown, ProcessCommands,
+       sizeof(s_parameters) / sizeof(NETXMS_SUBAGENT_PARAM),
+       s_parameters,
+       sizeof(s_lists) / sizeof(NETXMS_SUBAGENT_LIST),
+       s_lists,
+       sizeof(m_tables) / sizeof(NETXMS_SUBAGENT_TABLE),
+       m_tables,
+   0, NULL, // actions
+   0, NULL  // push parameters
+};
+
+/**
+ * Entry point for NetXMS agent
+ */
+DECLARE_SUBAGENT_ENTRY_POINT(FILEMGR)
+{
+   *ppInfo = &m_info;
+   return TRUE;
+}
+
+#ifdef _WIN32
+
+/**
+ * DLL entry point
+ */
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+   if (dwReason == DLL_PROCESS_ATTACH)
+      DisableThreadLibraryCalls(hInstance);
+   return TRUE;
+}
+
+#endif
diff --git a/src/agent/subagents/vmgr/vmgr.h b/src/agent/subagents/vmgr/vmgr.h
new file mode 100644 (file)
index 0000000..4593422
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ ** File management subagent
+ ** Copyright (C) 2016 Raden Solutions
+ **
+ ** 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.
+ **
+ **/
+
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include <nms_common.h>
+#include <nms_agent.h>
+#include <nxcpapi.h>
+
+#define NEVER 0
+#define DATA_COLLECTION_CASHE_TIME 10
+
+/**
+ * Parameter, list, table providers
+ */
+LONG H_GetHostList(const TCHAR *cmd, const TCHAR *arg, StringList *value, AbstractCommSession *session);
+LONG H_GetVMList(const TCHAR *cmd, const TCHAR *arg, StringList *value, AbstractCommSession *session);
+
+LONG H_GetFromCapabilities(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session);
+LONG H_GetUIntParam(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session);
+LONG H_GetUInt64Param(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session);
+LONG H_GetStringParam(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session);
+
+LONG H_GetVMTable(const TCHAR *cmd, const TCHAR *arg, Table *value, AbstractCommSession *);
+LONG H_GetIfaceTable(const TCHAR *cmd, const TCHAR *arg, Table *value, AbstractCommSession *);
+
+
+/**
+ * String map template for holding objects as values
+ */
+template <class T> class StringObjectMapC : public StringObjectMap<T>
+{
+private:
+       static void destructorC(void *object) { virDomainFree((virDomainPtr)object); }
+
+public:
+       StringObjectMapC(bool objectOwner) : StringObjectMap<T>(objectOwner) { StringMapBase::m_objectDestructor = destructorC; }
+};
+
+
+/**
+ * Data cashing class
+ */
+template <class StoredData> class XmlCashe
+{
+private:
+   time_t m_lastCollectionTime;
+   StoredData *m_data;
+   RWLOCK m_lock;
+   bool isMallocAlloc;
+public:
+   XmlCashe() { m_lastCollectionTime = NEVER; m_data = NULL; m_lock = RWLockCreate(); isMallocAlloc = true;}
+   ~XmlCashe() { RWLockDestroy(m_lock); if(isMallocAlloc){ free(m_data); } else { delete(m_data); } }
+   //XmlCashe(StoredData *data) { m_lastCollectionTime = time(NULL); m_data = data; }
+   void setMalloc(bool value) { isMallocAlloc = value; }
+   const StoredData *getDataAndLock() { RWLockReadLock(m_lock, 10000); return m_data; }
+   const time_t getLastCollecitonTime() { return m_lastCollectionTime; }
+   void updateChaseAndUnlock(StoredData* data) { m_lastCollectionTime = time(NULL); if(isMallocAlloc){ free(m_data); } else { delete(m_data); } m_data = data; RWLockUnlock(m_lock); }
+   bool shouldUpdate() { return (time(NULL) - m_lastCollectionTime) > DATA_COLLECTION_CASHE_TIME; }
+   void setWriteLock() { RWLockWriteLock(m_lock, INFINITE); }
+   void unlock() { RWLockUnlock(m_lock); }
+};
+
+/**
+ * Class that
+ */
+class HostConnections
+{
+private:
+   virConnectPtr m_connection;
+   char *m_url;
+   TCHAR *m_name;
+   char *m_login;
+   char *m_password;
+
+   XmlCashe<char> m_capabilities;
+   XmlCashe<virNodeInfo> m_nodeInfo;
+   XmlCashe<StringObjectMap<virDomain> > m_domains;
+   XmlCashe<StringList> m_iface;
+   //XmlCashe m_storages;
+
+   static int authCb(virConnectCredentialPtr cred, unsigned int ncred, void *cbdata);
+
+public:
+   HostConnections(const TCHAR *name, const char *url, const char *login, const char *password);
+   ~HostConnections();
+   bool connect();
+   void disconnect();
+
+   const char *getCapabilitiesAndLock();
+   void unlockCapabilities();
+   const virNodeInfo *getNodeInfoAndLock();
+   void unlockNodeInfo();
+   const StringObjectMap<virDomain> *getDomainListAndLock();
+   void unlockDomainList();
+   const StringList *getIfaceListAndLock();
+   void unlockIfaceList();
+   //void getStorages();
+   //void getDomains();
+
+   UINT32 getMaxVCpuCount();
+   UINT64 getHostFreeMemory();
+   const char *getConnectionType();
+   UINT64 getConnectionVersion();
+   UINT64 getLibraryVersion();
+
+   const TCHAR *getName() { return m_name; }
+};
+
+/**
+ * General declarations
+ */
+void InitLibvirt();
+extern StringObjectMap<HostConnections> g_connectionList;