# Copyright 2015 Cisco Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License prop
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module contains the ManagedObject and GenericManagedObject Class.
"""
from __future__ import print_function
import logging
import os
from . import ucsgenutils
from . import ucscoreutils
from . import ucscoremeta
try:
import xml.etree.cElementTree as ET
from xml.etree.cElementTree import Element, SubElement
except ImportError:
import cElementTree as ET
from cElementTree import Element, SubElement
from .ucscoremeta import WriteXmlOption
from .ucsexception import UcsValidationException, UcsWarning
from .ucscore import UcsBase
log = logging.getLogger('ucs')
class _GenericProp():
"""
Internal class to handle the unknown property.
"""
def __init__(self, name, value, is_dirty):
self.name = name
self.value = value
self.is_dirty = is_dirty
[docs]class ManagedObject(UcsBase):
"""
This class structures/represents all the managed objects.
"""
DUMMY_DIRTY = "0x1L"
__internal_prop = frozenset(
["_dirty_mask", "_class_id", "_child", "_handle", ''])
def __init__(
self,
class_id,
parent_mo_or_dn=None,
from_xml_response=False,
**kwargs):
self.__parent_mo = None
self.__status = None
self.__parent_dn = None
self.__xtra_props = {}
self.__xtra_props_dirty_mask = 0x1
if parent_mo_or_dn:
if isinstance(parent_mo_or_dn, ManagedObject):
self.__parent_mo = parent_mo_or_dn
self.__parent_dn = self.__parent_mo.dn
elif isinstance(parent_mo_or_dn, str):
self.__parent_dn = parent_mo_or_dn
else:
raise ValueError('parent mo or dn must be specified')
if not from_xml_response:
self._rn_set()
self._dn_set()
xml_attribute = self.mo_meta.xml_attribute
UcsBase.__init__(self, ucsgenutils.word_u(xml_attribute))
# self.mark_dirty()
if self.__parent_mo:
self.__parent_mo.child_add(self)
if kwargs:
for prop_name, prop_value in ucsgenutils.iteritems(kwargs):
if prop_name not in self.prop_meta:
log.debug("Unknown property %s" % prop_name)
self.__set_prop(prop_name, prop_value)
@property
def parent_mo(self):
"""Getter method of ManagedObject Class"""
return self.__parent_mo
def _rn_set(self):
"""
Internal method to set rn
"""
if "prop_meta" in dir(self) and "rn" in self.prop_meta:
self.rn = self.make_rn()
else:
self.rn = ""
def _dn_set(self):
"""
Internal method to set dn
"""
if "prop_meta" in dir(self) and "dn" in self.prop_meta:
if self.__parent_dn:
self.dn = self.__parent_dn + '/' + self.rn
else:
self.dn = self.rn
else:
self.dn = ""
def __setattr__(self, name, value):
"""
overridden setattr method
"""
if "prop_meta" in dir(self) and name in self.prop_meta:
if name in dir(self):
self.__set_prop(name, value)
else:
if value:
if not self.prop_meta[name].validate_property_value(value):
raise ValueError("Invalid Value Exception - "
"[%s]: Prop <%s>, Value<%s>. "
% (self.__class__.__name__,
name,
value))
object.__setattr__(self, name, value)
if self.prop_meta[name].mask is not None:
self._dirty_mask |= self.prop_meta[name].mask
elif name.startswith("_"):
object.__setattr__(self, name, value)
else:
# These are properties which the current version of ucsmsdk
# does not know of.
# The code will come here lot often, when using older version of
# ucsmsdk with newer releases on the UCS.
# This needs to be handled so that the same sdk can work across
# multiple ucs releases
self.__xtra_props[name] = _GenericProp(name, value, True)
self._dirty_mask |= self.__xtra_props_dirty_mask
object.__setattr__(self, name, value)
def __set_prop(self, name, value, mark_dirty=True, forced=False):
"""
Internal method to set the properties after validation
Args:
name (str): property name
value (str): property value
mark_dirty (bool): if True, property will be part of xml request
forced (bool): if True, set the value without validation
Returns:
None
"""
if not forced:
prop_meta = self.prop_meta[name]
if prop_meta.access != ucscoremeta.MoPropertyMeta.READ_WRITE:
if getattr(self, name) is not None or \
prop_meta.access != \
ucscoremeta.MoPropertyMeta.CREATE_ONLY:
raise ValueError("%s is not a read-write property." % name)
if not prop_meta.validate_property_value(value):
raise ValueError("Invalid Value Exception - "
"[%s]: Prop <%s>, Value<%s>. "
% (self.__class__.__name__,
name,
value))
# return False
if prop_meta.mask and mark_dirty:
self._dirty_mask |= prop_meta.mask
object.__setattr__(self, name, value)
def __str__(self):
"""
Method to return string representation of a managed object.
"""
ts = 8
out_str = "\n"
out_str += "Managed Object\t\t\t:\t" + str(self._class_id) + "\n"
out_str += "-" * len("Managed Object") + "\n"
for prop, prop_value in sorted(ucsgenutils.iteritems(self.__dict__)):
if prop in ManagedObject.__internal_prop or prop.startswith(
"_ManagedObject__"):
continue
if prop in self.__xtra_props:
prop = "[X]" + str(prop)
out_str += str(prop).ljust(ts * 4) + ':' + str(
prop_value) + "\n"
# print unknown properties
# for prop, prop_value in self.__xtra_props.iteritems():
# prop = "[X]" + str(prop)
# out_str += str(prop).ljust(ts * 4) + ':' + str(
# prop_value) + "\n"
out_str += "\n"
return out_str
[docs] def mark_dirty(self):
"""
This method marks the managed object dirty.
"""
if self.__class__.__name__ == "ManagedObject" and not self.is_dirty():
self._dirty_mask = ManagedObject.DUMMY_DIRTY
elif "mo_meta" in dir(self):
self._dirty_mask = self.mo_meta.mask
[docs] def is_dirty(self):
"""
This method checks if managed object is dirty.
"""
return self._dirty_mask != 0 or self.child_is_dirty()
# Ideally an rn should never change across ucsm releases.
# but we do have some of these cases
# These cause an issue, because we cannot parse them
# the below is a special case to handle these cases
[docs] def rn_is_special_case(self):
"""
Method to handle if rn pattern is different across UCS Version
"""
if self.__class__.__name__ == "StorageLocalDiskPartition":
return True
return False
[docs] def rn_get_special_case(self):
"""
Method to handle if rn pattern is different across UCS Version
"""
if self.__class__.__name__ == "StorageLocalDiskPartition":
# some version of ucs have rn "partition" instead of "partition-id"
return "partition"
[docs] def make_rn(self):
"""
This method returns the Rn for a managed object.
"""
import re
rn_pattern = self.mo_meta.rn
for prop in re.findall(r"""\[([^\]]*)\]""", rn_pattern):
if prop in self.prop_meta:
if getattr(self, prop):
rn_pattern = re.sub(r"""\[%s\]""" % prop,
'%s' % getattr(self, prop), rn_pattern)
else:
log.debug('Property "%s" was None in make_rn' % prop)
if self.rn_is_special_case():
return self.rn_get_special_case()
raise UcsValidationException(
'Property "%s" was None in make_rn' % prop)
else:
log.debug(
'Property "%s" was not found in make_rn arguments' % prop)
if self.rn_is_special_case():
return self.rn_get_special_case()
raise UcsValidationException(
'Property "%s" was not found in make_rn arguments' % prop)
return rn_pattern
[docs] def to_xml(self, xml_doc=None, option=None, elem_name=None):
"""
Method writes the xml representation of the managed object.
"""
if option == WriteXmlOption.DIRTY and not self.is_dirty():
log.debug("Object is not dirty")
return
xml_obj = self.elem_create(class_tag=self.mo_meta.xml_attribute,
xml_doc=xml_doc,
override_tag=elem_name)
for key in self.__dict__:
if key != 'rn' and key in self.prop_meta:
mo_prop_meta = self.prop_meta[key]
if (option != WriteXmlOption.DIRTY or (
mo_prop_meta.mask is not None and
self._dirty_mask & mo_prop_meta.mask != 0)):
value = getattr(self, key)
if value is not None:
xml_obj.set(mo_prop_meta.xml_attribute, value)
else:
if key not in self.__xtra_props:
# This is an internal property
# This should not be a part of the xml
continue
# This is an unknown property
# This should be a part of the xml
# The server might understand this property, even though
# the sdk does not
if option != WriteXmlOption.DIRTY or \
self.__xtra_props[key].is_dirty:
value = self.__xtra_props[key].value
if value is not None:
xml_obj.set(key, value)
if 'dn' not in xml_obj.attrib:
xml_obj.set('dn', self.dn)
self.child_to_xml(xml_obj, option)
return xml_obj
[docs] def from_xml(self, elem, handle=None):
"""
Method updates the object from the xml representation of the managed
object.
"""
self._handle = handle
if elem.attrib:
if self.__class__.__name__ != "ManagedObject":
for attr_name, attr_value in ucsgenutils.iteritems(
elem.attrib):
if attr_name in self.prop_map:
attr_name = self.prop_map[attr_name]
else:
self.__xtra_props[attr_name] = _GenericProp(
attr_name,
attr_value,
False)
object.__setattr__(self, attr_name, attr_value)
else:
for attr_name, attr_value in ucsgenutils.iteritems(
elem.attrib):
object.__setattr__(self, attr_name, attr_value)
if hasattr(self, 'rn') and not hasattr(self, 'dn'):
self._dn_set()
elif not hasattr(self, 'rn') and hasattr(self, 'dn'):
self.__set_prop("rn", os.path.basename(self.dn), forced=True)
self.mark_clean()
child_elems = elem.getchildren()
if child_elems:
for child_elem in child_elems:
if not ET.iselement(child_elem):
continue
if self.__class__.__name__ != "ManagedObject" and (
child_elem.tag in self.mo_meta.field_names):
pass
class_id = ucsgenutils.word_u(child_elem.tag)
child_obj = ucscoreutils.get_ucs_obj(class_id, child_elem,
self)
self.child_add(child_obj)
child_obj.from_xml(child_elem, handle)
[docs] def sync_mo(self, mo):
"""
Method to return string representation of a managed object.
"""
for prop, prop_value in sorted(ucsgenutils.iteritems(self.__dict__)):
if prop in ManagedObject.__internal_prop or prop.startswith(
"_ManagedObject__"):
continue
mo.__dict__[prop] = prop_value
return None
[docs] def show_tree(self, level=0):
"""
Method to return string representation of a managed object.
"""
indent = " "
level_indent = "%s%s)" % (indent * level, level)
# level_key_dn = "level_%s_dn" % (str(level))
print("%s %s[%s]" % (level_indent, self._class_id, self.dn))
for ch_ in self.children:
level += 1
ch_.show_tree(level)
level -= 1
return None
[docs] def show_hierarchy(self, level=0, depth=None, show_level=[]):
"""
Method to return string representation of a managed object.
"""
from .ucscoreutils import print_mo_hierarchy
print_mo_hierarchy(self._class_id, level, depth,
show_level)
[docs]def generic_mo_from_xml(xml_str):
"""
create GenericMo object from xml string
"""
root_elem = ET.fromstring(xml_str)
class_id = root_elem.tag
gmo = GenericMo(class_id)
gmo.from_xml(root_elem)
return gmo
[docs]def generic_mo_from_xml_elem(elem):
"""
create GenericMo object from xml element
"""
from . import ucsxmlcodec as xc
xml_str = xc.to_xml_str(elem)
gmo = generic_mo_from_xml(xml_str)
return gmo
[docs]class GenericMo(UcsBase):
"""
This class implements a Generic Managed Object.
Args:
class_id (str): class id of managed object
parent_mo_or_dn (ManagedObject or str): parent managed object or dn
"""
# Every variable that should not be a part of the final xml
# should start with a underscore in this class
def __init__(self, class_id, parent_mo_or_dn=None, **kwargs):
self.__properties = {}
if isinstance(parent_mo_or_dn, GenericMo):
self.__parent_mo = parent_mo_or_dn
self.__parent_dn = parent_mo_or_dn.dn
elif isinstance(parent_mo_or_dn, str):
# if (parent_mo_or_dn == "") and ("dn" in kwargs):
# parent_mo_or_dn = kwargs["dn"]
self.__parent_dn = parent_mo_or_dn
self.__parent_mo = None
elif parent_mo_or_dn is None:
self.__parent_dn = ""
self.__parent_mo = None
else:
raise ValueError("parent_mo_or_dn should be an instance of str or "
"GenericMo")
UcsBase.__init__(self, class_id)
if kwargs:
for key, value in ucsgenutils.iteritems(kwargs):
self.__dict__[key] = str(value)
self.__properties[key] = str(value)
if 'rn' in dir(self) and 'dn' in dir(self):
pass
elif 'rn' in dir(self) and 'dn' not in dir(self):
if self.__parent_dn is not None and self.__parent_dn != "":
self.dn = self.__parent_dn + '/' + self.rn
self.__properties['dn'] = self.dn
else:
self.dn = self.rn
self.__properties['dn'] = self.dn
elif 'rn' not in dir(self) and 'dn' in dir(self):
self.rn = os.path.basename(self.dn)
self.__properties['rn'] = self.rn
else:
self.rn = ""
self.dn = ""
if self.__parent_mo:
self.__parent_mo.child_add(self)
[docs] def to_xml(self, xml_doc=None, option=None):
"""
This method returns the xml element node for the current object
with it's hierarchy.
Args:
xml_doc: document to which the Mo attributes are added.
Can be None.
option: not required for Generic Mo class object
Example:
from ucsmsdk.ucsmo import GenericMo\n
args = {"a": 1, "b": 2, "c":3}\n
obj = GenericMo("testLsA", "org-root", **args)\n
obj1 = GenericMo("testLsB", "org-root", **args)\n
obj.add_child(obj1)\n
elem = obj.write_xml()\n
import ucsmsdk.ucsxmlcodec as xc\n
xc.to_xml_str(elem)\n
Output:
'<testLsA a="1" b="2" c="3" dn="org-root/" rn="">\n
<testLsB a="1" b="2" c="3" dn="org-root/" rn="" />\n
</testLsA>'
"""
if xml_doc is None:
xml_obj = Element(ucsgenutils.word_l(self._class_id))
else:
xml_obj = SubElement(xml_doc, ucsgenutils.word_l(self._class_id))
for key in self.__dict__:
if not key.startswith('_'):
xml_obj.set(key, getattr(self, key))
self.child_to_xml(xml_obj)
return xml_obj
@property
def properties(self):
"""Getter Method of GenericMO Class"""
return self.__properties
[docs] def from_xml(self, elem, handle=None):
"""
This method is form objects out of xml element.
This is called internally from ucsxmlcode.from_xml_str
method.
Example:
xml = '<testLsA a="1" b="2" c="3" dn="org-root/" rn="">
<testLsB a="1" b="2" c="3" dn="org-root/" rn="" /></testLsA>'\n
obj = xc.from_xml_str(xml)\n
print type(obj)\n
Outputs:
<class 'ucsmsdk.ucsmo.GenericMo'>
"""
if elem is None:
return None
self._handle = handle
self._class_id = elem.tag
if elem.attrib:
for name, value in ucsgenutils.iteritems(elem.attrib):
self.__dict__[name] = value
self.__properties[name] = str(value)
if self.rn and self.dn:
pass
elif self.rn and not self.dn:
if self.__parent_dn is not None and self.__parent_dn != "":
self.dn = self.__parent_dn + '/' + self.rn
self.__properties['dn'] = self.dn
else:
self.dn = self.rn
self.__properties['dn'] = self.dn
elif not self.rn and self.dn:
self.rn = os.path.basename(self.dn)
self.__properties['rn'] = self.rn
# else:
# raise ValueError("Both rn and dn does not present.")
children = elem.getchildren()
if children:
for child in children:
if not ET.iselement(child):
continue
class_id = ucsgenutils.word_u(child.tag)
# child_obj = ucscoreutils.get_ucs_obj(class_id, child, self)
pdn = None
if 'dn' in dir(self):
pdn = self.dn
child_obj = GenericMo(class_id, parent_mo_or_dn=pdn)
self.child_add(child_obj)
child_obj.from_xml(child, handle)
def __get_mo_obj(self, class_id):
"""
Internal methods to create managed object from class_id
"""
import inspect
mo_class = ucscoreutils.load_class(class_id)
mo_class_params = inspect.getargspec(mo_class.__init__)[0][2:]
mo_class_param_dict = {}
for param in mo_class_params:
mo_param = mo_class.prop_meta[param].xml_attribute
if mo_param not in self.__properties:
if 'rn' in self.__properties:
rn_str = self.__properties['rn']
elif 'dn' in self.__properties:
rn_str = os.path.basename(self.__properties['dn'])
rn_pattern = mo_class.mo_meta.rn
np_dict = ucscoreutils.get_naming_props(rn_str, rn_pattern)
if param not in np_dict:
mo_class_param_dict[param] = ""
else:
mo_class_param_dict[param] = np_dict[param]
else:
mo_class_param_dict[param] = self.__properties[mo_param]
p_dn = ""
if 'topRoot' in mo_class.mo_meta.parents:
mo_obj = mo_class(**mo_class_param_dict)
else:
mo_obj = mo_class(parent_mo_or_dn=p_dn, **mo_class_param_dict)
return mo_obj
[docs] def to_mo(self):
"""
Converts GenericMo to ManagedObject
"""
from . import ucsmeta
class_id = ucsgenutils.word_u(self._class_id)
if class_id not in ucsmeta.MO_CLASS_ID:
return None
mo = self.__get_mo_obj(class_id)
if not mo: # or not isinstance(mo, ManagedObject):
return None
for prop in self.__properties:
if prop in mo.prop_map:
mo.__dict__[mo.prop_map[prop]] = self.__properties[prop]
else:
UcsWarning("Property %s Not Exist in MO %s" % (
ucsgenutils.word_u(prop), class_id))
if len(self.child):
for ch_ in self.child:
mo_ch = ch_.to_mo()
mo.child_add(mo_ch)
return mo
def __str__(self):
ts = 8
if isinstance(self, GenericMo):
out_str = "\n"
out_str += 'GenericMo'.ljust(ts * 4) + ':' + str(
self._class_id) + "\n"
out_str += "-" * len("GenericMo") + "\n"
for prop, prop_val in sorted(ucsgenutils.iteritems(self.__dict__)):
if prop.startswith('_'):
continue
out_str += str(prop).ljust(ts * 4) + ':' + str(prop_val) + "\n"
return out_str