Skip to content

Commit

Permalink
Merge branch 'hotfix/2.0.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
cluther committed Mar 10, 2017
2 parents 4550c8d + c183db9 commit 57fff10
Show file tree
Hide file tree
Showing 16 changed files with 144 additions and 63 deletions.
23 changes: 10 additions & 13 deletions ZenPacks/zenoss/ZenPackLib/lib/base/ZenPack.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def install(self, app):
# load monitoring templates
for dcname, dcspec in self.device_classes.iteritems():
dcspecparam = self._v_specparams.device_classes.get(dcname)
deviceclass = self.dmd.Devices.getOrganizer(dcname)
deviceclass = dcspec.get_organizer(self.dmd)

for mtname, mtspec in dcspec.templates.iteritems():
create_template = False
Expand Down Expand Up @@ -129,9 +129,8 @@ def remove(self, app, leaveObjects=False):
# objects, but we do not have access to that relationship
# at this point in the process.
for dcname, dcspec in self._v_specparams.device_classes.iteritems():
try:
deviceclass = self.dmd.Devices.getOrganizer(dcname)
except KeyError:
deviceclass = dcspec.get_organizer(app.zport.dmd)
if not deviceclass:
self.LOG.warning(
"DeviceClass {} has been removed at some point "
"after the {} ZenPack was installed. It will be "
Expand Down Expand Up @@ -289,9 +288,8 @@ def create_device_classes(self, app):
if dcspec.create:
self.create_device_class(app, dcspec)
else:
try:
self.dmd.Devices.getOrganizer(dcspec.path)
except KeyError:
device_class = dcspec.get_organizer(app.zport.dmd)
if not device_class:
self.LOG.warn(
"Device Class (%s) not found",
dcspec.path)
Expand All @@ -304,18 +302,17 @@ def create_device_class(self, app, dcspec):
customizations on upgrade.
"""
try:
dcObject = app.dmd.Devices.getOrganizer(dcspec.path)
except KeyError:
self.LOG.debug("Creating %s device class", dcspec.path)
dcObject = app.dmd.Devices.createOrganizer(dcspec.path)
else:
dcObject = dcspec.get_organizer(app.dmd)
if dcObject:
self.LOG.debug(
"Existing %s device class - not overwriting properties",
dcspec.path)

return dcObject

self.LOG.debug("Creating %s device class", dcspec.path)
dcObject = app.dmd.Devices.createOrganizer(dcspec.path)

# Set zProperties.
for zprop, value in dcspec.zProperties.iteritems():
if dcObject.getPropertyType(zprop) is None:
Expand Down
2 changes: 1 addition & 1 deletion ZenPacks/zenoss/ZenPackLib/lib/helpers/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def construct_severity(self, node):
def construct_specsparameters(self, node, spectype):
"""constructor for SpecsParameters"""
from ..spec.Spec import Spec
spec_class = {x.__name__: x for x in Spec.__subclasses__()}.get(spectype, None)
spec_class = {x.__name__: x for x in Spec.get_subclasses()}.get(spectype, None)

if not spec_class:
self.yaml_error(yaml.constructor.ConstructorError(
Expand Down
17 changes: 12 additions & 5 deletions ZenPacks/zenoss/ZenPackLib/lib/spec/DeviceClassSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
# License.zenoss under the directory where your Zenoss product is installed.
#
##############################################################################
from .Spec import Spec
from .OrganizerSpec import OrganizerSpec
from .RRDTemplateSpec import RRDTemplateSpec


class DeviceClassSpec(Spec):
class DeviceClassSpec(OrganizerSpec):
"""Initialize a DeviceClass via Python at install time."""

def __init__(
Expand Down Expand Up @@ -41,11 +41,14 @@ def __init__(
:param protocol: Protocol to use for registered devtype
:type protocol: str
"""
super(DeviceClassSpec, self).__init__(_source_location=_source_location)
super(DeviceClassSpec, self).__init__(
zenpack_spec,
path,
_source_location=_source_location)

if zplog:
self.LOG = zplog
self.zenpack_spec = zenpack_spec
self.path = path.lstrip('/')

self.create = bool(create)
self.remove = bool(remove)
self.description = description
Expand All @@ -58,3 +61,7 @@ def __init__(

self.templates = self.specs_from_param(
RRDTemplateSpec, 'templates', templates, zplog=self.LOG)

def get_root(self, dmd):
"""Return the root object for this organizer."""
return dmd.Devices
3 changes: 2 additions & 1 deletion ZenPacks/zenoss/ZenPackLib/lib/spec/EventClassMappingSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,5 @@ def create(self, eventclass):
if getattr(mapping, x) != getattr(self, x):
setattr(mapping, x, getattr(self, x, None))

self.zpl_managed = True
mapping.zpl_managed = True
mapping.index_object()
38 changes: 20 additions & 18 deletions ZenPacks/zenoss/ZenPackLib/lib/spec/EventClassSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
#
##############################################################################

from .Spec import Spec
from .OrganizerSpec import OrganizerSpec
from .EventClassMappingSpec import EventClassMappingSpec


class EventClassSpec(Spec):
class EventClassSpec(OrganizerSpec):
"""Initialize a EventClass via Python at install time."""
def __init__(
self,
Expand All @@ -33,26 +33,26 @@ def __init__(
:param mappings: TODO
:type mappings: SpecsParameter(EventClassMappingSpec)
"""
super(EventClassSpec, self).__init__(_source_location=_source_location)
self.zenpack_spec = zenpack_spec
self.path = path.lstrip('/')
super(EventClassSpec, self).__init__(
zenpack_spec,
path,
_source_location=_source_location)

if zplog:
self.LOG = zplog

self.description = description
self.transform = transform
self.remove = bool(remove)
if zplog:
self.LOG = zplog
self.mappings = self.specs_from_param(
EventClassMappingSpec, 'mappings', mappings, zplog=self.LOG)

def instantiate(self, dmd):
bCreated = False
try:
ecObject = dmd.Events.getOrganizer(self.path)
bCreated = getattr(ecObject, 'zpl_managed', False)
except KeyError:
dmd.Events.createOrganizer(self.path)
ecObject = dmd.Events.getOrganizer(self.path)
bCreated = True
ecObject = self.get_organizer(dmd)
if not ecObject:
ecObject = dmd.Events.createOrganizer(self.path)
ecObject.zpl_managed = True

if self.description != '':
if not ecObject.description == self.description:
self.LOG.debug('Description of Event Class {} has changed from'
Expand All @@ -67,8 +67,10 @@ def instantiate(self, dmd):
ecObject.transform,
self.transform))
ecObject.transform = self.transform
# Flag this as a ZPL managed object, that is, one that should not be
# exported to objects.xml (contained objects will also be excluded)
ecObject.zpl_managed = bCreated

for mapping_id, mapping_spec in self.mappings.items():
mapping_spec.create(ecObject)

def get_root(self, dmd):
"""Return the root object for this organizer."""
return dmd.Events
52 changes: 52 additions & 0 deletions ZenPacks/zenoss/ZenPackLib/lib/spec/OrganizerSpec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
##############################################################################
#
# Copyright (C) Zenoss, Inc. 2017, all rights reserved.
#
# This content is made available according to terms specified in
# License.zenoss under the directory where your Zenoss product is installed.
#
##############################################################################

from .Spec import Spec


class OrganizerSpec(Spec):
"""Abstract base for organizer specifications.
Subclasses:
* DeviceClassSpec
* EventClassSpec
* ProcessClassOrganizerSpec
"""

def __init__(self, zenpack_spec, path, _source_location=None, zplog=None):
"""Create an Organizer specification."""
super(OrganizerSpec, self).__init__(_source_location=_source_location)

if zplog:
self.LOG = zplog

self.zenpack_spec = zenpack_spec
self.path = path.lstrip("/")

def get_root(self, dmd):
"""Return the root for this organizer.
Must be overridden by subclasses. DeviceClassSpec, for example, would
return dmd.Devices.
"""
raise NotImplementedError

def get_organizer(self, dmd):
"""Return organizer object for this specification or None."""
try:
organizer = self.get_root(dmd).getOrganizer(self.path)
except KeyError:
return
else:
# Guard against acquisition returning us the wrong organizer.
if organizer.getOrganizerName().lstrip("/") == self.path:
return organizer
35 changes: 19 additions & 16 deletions ZenPacks/zenoss/ZenPackLib/lib/spec/ProcessClassOrganizerSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
#
##############################################################################

from .Spec import Spec
from .OrganizerSpec import OrganizerSpec
from .ProcessClassSpec import ProcessClassSpec


class ProcessClassOrganizerSpec(Spec):
class ProcessClassOrganizerSpec(OrganizerSpec):
"""Initialize a Process Set via Python at install time."""
def __init__(
self,
Expand All @@ -30,28 +30,31 @@ def __init__(
:param remove: Remove Organizer on ZenPack removal
:type remove: boolean
"""
self.zenpack_spec = zenpack_spec
self.path = path.lstrip('/')
super(ProcessClassOrganizerSpec, self).__init__(
zenpack_spec,
path,
_source_location=_source_location)

if zplog:
self.LOG = zplog

self.description = description
self.remove = remove
self.process_classes = self.specs_from_param(
ProcessClassSpec, 'process_classes', process_classes, zplog=self.LOG)

def create(self, dmd):
# get/create process class organizer
bCreated = False
try:
porg = dmd.Processes.getOrganizer(self.path)
bCreated = getattr(porg, 'zpl_managed', False)
except KeyError:
dmd.Processes.createOrganizer(self.path)
porg = dmd.Processes.getOrganizer(self.path)
bCreated = True
porg = self.get_organizer(dmd)
if not porg:
porg = dmd.Processes.createOrganizer(self.path)
porg.zpl_managed = True

if porg.description != self.description:
porg.description = self.description
# Flag this as a ZPL managed object, that is, one that should not be
# exported to objects.xml (contained objects will also be excluded)
porg.zpl_managed = bCreated

for process_class_id, process_class_spec in self.process_classes.items():
process_class_spec.create(dmd, porg)

def get_root(self, dmd):
"""Return the root object for this organizer."""
return dmd.Processes
6 changes: 3 additions & 3 deletions ZenPacks/zenoss/ZenPackLib/lib/spec/RRDTemplateSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ def create(self, dmd, addToZenPack=True, id=None):
return template

def remove(self, dmd, id=None):
try:
device_class = dmd.Devices.getOrganizer(self.deviceclass_spec.path)
except KeyError:
device_class = self.deviceclass_spec.get_organizer(dmd)
if not device_class:
return

# override object id if provided
t_id = id or self.name
existing_template = device_class.rrdTemplates._getOb(t_id, None)
Expand Down
8 changes: 8 additions & 0 deletions ZenPacks/zenoss/ZenPackLib/lib/spec/Spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,11 @@ def get_class_factory(self, klass):
return InterfaceClass
else:
return type

@classmethod
def get_subclasses(cls):
"""Generate recursive subclasses of this class."""
for subclass in cls.__subclasses__():
yield subclass
for subsubclass in subclass.get_subclasses():
yield subsubclass
3 changes: 2 additions & 1 deletion ZenPacks/zenoss/ZenPackLib/lib/spec/ZenPackSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ def create_dynamicview_nav_js_snippet(self):
if service_view_metatypes:
return (
"Zenoss.nav.appendTo('Component', [{{\n"
" id: 'subcomponent_view',\n"
" id: '{zenpack_id_prefix}_subcomponent_view',\n"
" text: _t('Dynamic View'),\n"
" xtype: 'dynamicview',\n"
" relationshipFilter: 'impacted_by',\n"
Expand All @@ -530,6 +530,7 @@ def create_dynamicview_nav_js_snippet(self):
" }}\n"
"}}]);\n"
).format(
zenpack_id_prefix=self.id_prefix,
cases='\n '.join(
"case '{}': return true;".format(x)
for x in service_view_metatypes))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class TestDeviceClassRemoval(ZPLTestBase):

def test_device_class(self):
# instantiate the ZenPack class
zenpack = ZenPack(self.dmd)
zenpack = ZenPack(self.app)

# create the device class
for dcname, dcspec in self.z.cfg.device_classes.items():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"""


EXPECTED_SUBCOMPONENT_VIEW = "Zenoss.nav.appendTo('Component', [{\n id: 'subcomponent_view',\n text: _t('Dynamic View'),\n xtype: 'dynamicview',\n relationshipFilter: 'impacted_by',\n viewName: 'service_view',\n filterNav: function(navpanel) {\n switch (navpanel.refOwner.componentType) {\n case 'Application': return true;\n case 'Linux': return true;\n default: return false;\n }\n }\n}]);"
EXPECTED_SUBCOMPONENT_VIEW = "Zenoss.nav.appendTo('Component', [{\n id: 'ZenPacks_zenpacklib_TestLinuxStorage_subcomponent_view',\n text: _t('Dynamic View'),\n xtype: 'dynamicview',\n relationshipFilter: 'impacted_by',\n viewName: 'service_view',\n filterNav: function(navpanel) {\n switch (navpanel.refOwner.componentType) {\n case 'Application': return true;\n case 'Linux': return true;\n default: return false;\n }\n }\n}]);"


class TestDynamicViewComponentNav(ZPLTestBase):
Expand Down
10 changes: 10 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ Backwards Incompatible Changes

* zProperties will not be updated automatically on existing device classes. These should be handled on a case basis by using migrate scripts.

Release 2.0.4
-------------

Fixes

* Fix for missing Dynamic View on some components (ZPS-703)
* Fix for failure to create device classes in uncommon case (ZPS-1012)
* Fix event class mappings with mismatched id and eventClassKey (ZPS-1016)


Release 2.0.3
-------------

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
# The short X.Y version.
version = '2.0'
# The full version, including alpha/beta/rc tags.
release = '2.0.3'
release = '2.0.4'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# or saved. Do not modify them directly here.
# NB: PACKAGES is deprecated
NAME = "ZenPacks.zenoss.ZenPackLib"
VERSION = "2.0.3"
VERSION = "2.0.4"
AUTHOR = "Zenoss"
LICENSE = ""
NAMESPACE_PACKAGES = ['ZenPacks', 'ZenPacks.zenoss']
Expand Down
2 changes: 1 addition & 1 deletion tests/test_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

EXPECTED_SUBCOMPONENT_VIEW = """
Zenoss.nav.appendTo('Component', [{
id: 'subcomponent_view',
id: 'ZenPacks_zenpacklib_TestLinuxStorage_subcomponent_view',
text: _t('Dynamic View'),
xtype: 'dynamicview',
relationshipFilter: 'impacted_by',
Expand Down

0 comments on commit 57fff10

Please sign in to comment.