diff --git a/ZenPacks/zenoss/PostgreSQL/Table.py b/ZenPacks/zenoss/PostgreSQL/Table.py
index 4733463..345ff30 100644
--- a/ZenPacks/zenoss/PostgreSQL/Table.py
+++ b/ZenPacks/zenoss/PostgreSQL/Table.py
@@ -60,5 +60,7 @@ class Table(DeviceComponent, ManagedEntity, CollectedOrModeledMixin):
event_key = "ComponentId"
def device(self):
- return self.database().device()
-
+ db = self.database()
+ if db:
+ return db.device()
+ return None
diff --git a/ZenPacks/zenoss/PostgreSQL/__init__.py b/ZenPacks/zenoss/PostgreSQL/__init__.py
index 5963237..6efd97e 100644
--- a/ZenPacks/zenoss/PostgreSQL/__init__.py
+++ b/ZenPacks/zenoss/PostgreSQL/__init__.py
@@ -12,6 +12,7 @@
###########################################################################
import logging
+
log = logging.getLogger('zen.PostgreSQL')
import os
@@ -22,6 +23,7 @@
from Products.ZenRelations.RelSchema import ToManyCont, ToOne
from Products.ZenUtils.Utils import monkeypatch, zenPath
+
class ZenPack(ZenPackBase):
packZProperties = [
('zPostgreSQLPort', 5432, 'int'),
@@ -29,8 +31,16 @@ class ZenPack(ZenPackBase):
('zPostgreSQLPassword', '', 'password'),
('zPostgreSQLUseSSL', False, 'boolean'),
('zPostgreSQLDefaultDB', 'postgres', 'string'),
+ ('zPostgreSQLTableRegex', [], 'lines'),
]
+ packZProperties_data = {
+ 'zPostgreSQLTableRegex': {
+ 'description': "List of regular expressions (matched against table names) to control which tables are NOT modeled from All databases.",
+ 'label': "Regex Table Filter",
+ 'type': "lines" },
+ }
+
def install(self, app):
super(ZenPack, self).install(app)
self.patchPostgreSQLDriver()
@@ -40,10 +50,10 @@ def remove(self, app, leaveObjects=False):
if not leaveObjects:
# Remove our custom relations addition.
Device._relations = tuple(
- [ x for x in Device._relations if x[0] != 'pgDatabases' ])
+ [x for x in Device._relations if x[0] != 'pgDatabases'])
self.updateExistingRelations(app.zport.dmd)
-
+
# Revert all pg8000 library patches
self.patchPostgreSQLDriver(revert=True)
@@ -57,21 +67,22 @@ def updateExistingRelations(self, dmd):
def patchPostgreSQLDriver(self, revert=False):
log.info('Patching pg8000 core library')
patch_dir = self.path('lib')
-
+
# Getting a list of all patches which will be applied
patches_list = [file for file in os.listdir(patch_dir) if file.endswith('.patch')]
-
- cmd = "patch -p0 -d %s -i %s" if not revert else "patch -p0 -R -d %s -i %s"
+
+ cmd = "patch -p0 -d %s -i %s" if not revert else "patch -p0 -R -d %s -i %s"
for patch in patches_list:
os.system(cmd % (
os.path.join(patch_dir, 'pg8000'),
os.path.join(patch_dir, patch)
))
+
# Allow PostgreSQL databases to be related to any device.
Device._relations += (
('pgDatabases', ToManyCont(ToOne,
- 'ZenPacks.zenoss.PostgreSQL.Database.Database', 'server')),
+ 'ZenPacks.zenoss.PostgreSQL.Database.Database', 'server')),
)
# We need to filter components by id instead of name.
@@ -79,6 +90,7 @@ def patchPostgreSQLDriver(self, revert=False):
"\"(device = '%s' and component = '%s')\""
" % (me.device().getDmdKey(), me.id)")
+
@monkeypatch('Products.ZenModel.Device.Device')
def setPostgreSQL(self, active=True):
if not active:
@@ -96,11 +108,12 @@ def setPostgreSQL(self, active=True):
if device.zCommandCommandTimeout < 180:
device.setZenProperty('zCommandCommandTimeout', 180)
+
@monkeypatch('Products.ZenModel.Device.Device')
def getPostgreSQL(self):
device = self.primaryAq()
if 'PostgreSQLServer' in device.zDeviceTemplates \
- and device.zCommandCommandTimeout >= 180:
+ and device.zCommandCommandTimeout >= 180:
return True
return False
diff --git a/ZenPacks/zenoss/PostgreSQL/modeler/plugins/zenoss/PostgreSQL.py b/ZenPacks/zenoss/PostgreSQL/modeler/plugins/zenoss/PostgreSQL.py
index 1a872df..66f7c7c 100644
--- a/ZenPacks/zenoss/PostgreSQL/modeler/plugins/zenoss/PostgreSQL.py
+++ b/ZenPacks/zenoss/PostgreSQL/modeler/plugins/zenoss/PostgreSQL.py
@@ -12,13 +12,16 @@
###########################################################################
import logging
+import re
+
log = logging.getLogger('zen.PostgreSQL')
from Products.DataCollector.plugins.CollectorPlugin import PythonPlugin
from Products.DataCollector.plugins.DataMaps import ObjectMap, RelationshipMap
from Products.ZenUtils.Utils import prepId
-from ZenPacks.zenoss.PostgreSQL.util import PgHelper
+from ZenPacks.zenoss.PostgreSQL.util import PgHelper, exclude_patterns_list, is_suppressed
+
class PostgreSQL(PythonPlugin):
deviceProperties = PythonPlugin.deviceProperties + (
@@ -27,6 +30,7 @@ class PostgreSQL(PythonPlugin):
'zPostgreSQLPassword',
'zPostgreSQLUseSSL',
'zPostgreSQLDefaultDB',
+ 'zPostgreSQLTableRegex',
)
def collect(self, device, unused):
@@ -39,6 +43,7 @@ def collect(self, device, unused):
device.zPostgreSQLDefaultDB)
results = {}
+ exclude_patterns = exclude_patterns_list(getattr(device, 'zPostgreSQLTableRegex', []))
log.info("Getting database list")
try:
@@ -55,7 +60,14 @@ def collect(self, device, unused):
log.info("Getting tables list for {0}".format(dbName))
try:
- results['databases'][dbName]['tables'] = pg.getTablesInDatabase(dbName)
+ tables = pg.getTablesInDatabase(dbName)
+ if exclude_patterns:
+ for key in tables.keys():
+ if is_suppressed(key, exclude_patterns):
+ del tables[key]
+
+ results['databases'][dbName]['tables'] = tables
+
except Exception, ex:
log.warn("Error getting tables list for {0}: {1}".format(
dbName, ex))
@@ -68,7 +80,7 @@ def process(self, devices, results, unused):
if results is None:
return None
- maps = [ self.objectMap(dict(setPostgreSQL=True)) ]
+ maps = [self.objectMap(dict(setPostgreSQL=True))]
databases = []
for dbName, dbDetail in results['databases'].items():
diff --git a/ZenPacks/zenoss/PostgreSQL/util.py b/ZenPacks/zenoss/PostgreSQL/util.py
index d701d2e..8a5823c 100644
--- a/ZenPacks/zenoss/PostgreSQL/util.py
+++ b/ZenPacks/zenoss/PostgreSQL/util.py
@@ -15,7 +15,9 @@
import math
import sys
import time
-
+import re
+import logging
+LOG = logging.getLogger('zen.PostgreSQL.utils')
def addLocalLibPath():
"""
@@ -545,3 +547,28 @@ def getTableStatsForDatabase(self, db):
cursor.close()
return tableStats
+
+def exclude_patterns_list(excludes):
+ exclude_patterns = []
+
+ for exclude in excludes:
+ exclude = exclude.strip()
+ if exclude == "" or exclude.startswith("#"):
+ continue
+
+ try:
+ exclude_patterns.append(re.compile(exclude))
+ except Exception:
+ LOG.warn("Invalid zPostgreSQLTableRegex value: '%s', this modeling filter will not be applied.", exclude)
+ continue
+
+ return exclude_patterns
+
+
+def is_suppressed(item, exclude_patterns):
+
+ for exclude_pattern in exclude_patterns:
+ if exclude_pattern.search(item):
+ return True
+
+ return False
diff --git a/docs/body.md b/docs/body.md
index 2e54c86..84ffdba 100644
--- a/docs/body.md
+++ b/docs/body.md
@@ -82,6 +82,7 @@ individual devices.
- *zPostgreSQLUsername* - Must be a superuser. Default: postgres
- *zPostgreSQLPassword* - Password for user. No default.
- *zPostgreSQLDefaultDB* - Default database. Default: postgres
+ - *zPostgreSQLTableRegex* - Filter tables of all databases with Regex. Default: ""
In addition to setting these properties you must add the ''zenoss.PostgreSQL''
modeler plugin to a device class or individual device. This modeler plugin will
@@ -164,6 +165,11 @@ zSnmpMonitorIgnore property to True and remodel.
Changes
---------------
+1.0.13
+
+* Make PostgreSQL table modeling optional (ZPS-8554)
+* Tested with Zenoss Cloud, Zenoss 6.7.0 and Service Impact 5.6.1
+
1.0.12
* Resolved isuue with error in pg8000 library on Ubuntu OS (ZPS-7424)
diff --git a/docs/releases.md b/docs/releases.md
index e9a3fce..03599f0 100644
--- a/docs/releases.md
+++ b/docs/releases.md
@@ -1,6 +1,10 @@
Releases
--------
+Version 1.0.13-Download
+Released on 2023/9/12
+Compatible with Zenoss 6.x, Zenoss Cloud and Service Impact 5.6.1
+
Version 1.0.12-Download
Released on 2021/1/14
Compatible with Zenoss 6.4.1 - 6.5.0, Zenoss Cloud and Service Impact 5.5.3
diff --git a/setup.py b/setup.py
index fc4241c..56dab97 100644
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,7 @@
# or saved. Do not modify them directly here.
# NB: PACKAGES is deprecated
NAME = "ZenPacks.zenoss.PostgreSQL"
-VERSION = "1.1.0"
+VERSION = "1.0.13"
AUTHOR = "Zenoss"
LICENSE = "GPLv2"
NAMESPACE_PACKAGES = ['ZenPacks', 'ZenPacks.zenoss']