Hi Hans, Anders & Srinivas, Just reminding. Please spend a little time to help me review this patch.
Many thanks, Hieu -----Original Message----- From: Hieu Nguyen [mailto:hieu.t.ngu...@dektech.com.au] Sent: Wednesday, December 6, 2017 2:46 PM To: hans.nordeb...@ericsson.com; anders.wid...@ericsson.com; srinivas.mangip...@oracle.com Cc: opensaf-devel@lists.sourceforge.net; Hieu Nguyen <hieu.t.ngu...@dektech.com.au> Subject: [PATCH 1/1] pyosaf: refactor IMM utils [#2683] + improve OI utils use a separate instance OM agent + refactor OM utils with Ccb inheritace OmAgent, rename some classes... --- python/pyosaf/utils/immoi/__init__.py | 531 +++++++------------------------ python/pyosaf/utils/immoi/agent.py | 473 +++++++++++++++++++++++++++ python/pyosaf/utils/immoi/implementer.py | 141 ++++---- python/pyosaf/utils/immom/__init__.py | 7 +- python/pyosaf/utils/immom/accessor.py | 31 +- python/pyosaf/utils/immom/agent.py | 31 +- python/pyosaf/utils/immom/ccb.py | 71 +---- python/pyosaf/utils/immom/iterator.py | 4 +- python/pyosaf/utils/immom/object.py | 4 +- 9 files changed, 736 insertions(+), 557 deletions(-) create mode 100644 python/pyosaf/utils/immoi/agent.py diff --git a/python/pyosaf/utils/immoi/__init__.py b/python/pyosaf/utils/immoi/__init__.py index 1b4dece..7247b0e 100644 --- a/python/pyosaf/utils/immoi/__init__.py +++ b/python/pyosaf/utils/immoi/__init__.py @@ -22,298 +22,23 @@ Supported functions: - Set/clear/release implementer for class/object - Create/delete/update runtime object - Get class/object attributes -- Get IMM error strings +- Get/set IMM error strings +- Get parent for dn +- Get class for dn +- Get objects for class +- Get available classes of IMM """ from __future__ import print_function -from copy import deepcopy -from ctypes import c_char_p, c_void_p, cast, pointer - -from pyosaf.saAis import SaStringT, SaVersionT, SaNameT, SaSelectionObjectT, \ - unmarshalSaStringTArray, eSaDispatchFlagsT, eSaAisErrorT -from pyosaf import saImm, saImmOi -from pyosaf.saImm import unmarshalSaImmValue, SaImmAttrNameT, \ - SaImmAttrValuesT_2, SaImmClassNameT, SaImmSearchParametersT_2, \ - eSaImmValueTypeT, SaImmAttrDefinitionT_2, SaImmClassCategoryT, \ - SaImmAttrModificationT_2, eSaImmAttrModificationTypeT -from pyosaf.saImmOi import SaImmOiHandleT, SaImmOiImplementerNameT -from pyosaf.utils import immom, log_err, bad_handle_retry, decorate, \ - deprecate, initialize_decorate, SafException + +from pyosaf.saAis import SaSelectionObjectT, eSaAisErrorT +from pyosaf.utils import deprecate, SafException from pyosaf.utils.immom.object import ImmObject -from pyosaf.utils.immom.ccb import marshal_c_array -from pyosaf.utils.immom.iterator import SearchIterator +from pyosaf.utils.immoi.agent import OiAgent -OPENSAF_IMM_OBJECT = "opensafImm=opensafImm,safApp=safImmService" _oi_agent = None -# Decorate pure saImmOi* API's with error-handling retry and exception raising -saImmOiInitialize_2 = initialize_decorate(saImmOi.saImmOiInitialize_2) -saImmOiSelectionObjectGet = decorate(saImmOi.saImmOiSelectionObjectGet) -saImmOiDispatch = decorate(saImmOi.saImmOiDispatch) -saImmOiFinalize = decorate(saImmOi.saImmOiFinalize) -saImmOiImplementerSet = decorate(saImmOi.saImmOiImplementerSet) -saImmOiImplementerClear = decorate(saImmOi.saImmOiImplementerClear) -saImmOiClassImplementerSet = decorate(saImmOi.saImmOiClassImplementerSet) -saImmOiClassImplementerRelease = \ - decorate(saImmOi.saImmOiClassImplementerRelease) -saImmOiObjectImplementerSet = decorate(saImmOi.saImmOiObjectImplementerSet) -saImmOiObjectImplementerRelease = \ - decorate(saImmOi.saImmOiObjectImplementerRelease) -saImmOiRtObjectCreate_2 = decorate(saImmOi.saImmOiRtObjectCreate_2) -saImmOiRtObjectDelete = decorate(saImmOi.saImmOiRtObjectDelete) -saImmOiRtObjectUpdate_2 = decorate(saImmOi.saImmOiRtObjectUpdate_2) -saImmOiAdminOperationResult = decorate(saImmOi.saImmOiAdminOperationResult) -saImmOiAdminOperationResult_o2 = \ - decorate(saImmOi.saImmOiAdminOperationResult_o2) -saImmOiAugmentCcbInitialize = decorate(saImmOi.saImmOiAugmentCcbInitialize) -saImmOiCcbSetErrorString = decorate(saImmOi.saImmOiCcbSetErrorString) - - -class OiAgent(object): - """ This class acts as a high-level OI agent, providing OI functions to - the users as a higher level, and relieving the users of the need to manage - the life cycle of the OI agent and providing general interface for - Implementer or Applier used - """ - def __init__(self, version=None): - """ Constructor for OiAgent class - - Args: - version (SaVersionT): OI API version - """ - self.handle = None - self.init_version = version if version is not None \ - else SaVersionT('A', 2, 15) - self.version = None - self.selection_object = None - self.callbacks = None - global _oi_agent - _oi_agent = self - - def _fetch_sel_obj(self): - """ Obtain a selection object (OS file descriptor) - - Returns: - SaAisErrorT: Return code of the saImmOiSelectionObjectGet() API - """ - rc = saImmOiSelectionObjectGet(self.handle, self.selection_object) - if rc != eSaAisErrorT.SA_AIS_OK: - log_err("saImmOiSelectionObjectGet FAILED - %s" % - eSaAisErrorT.whatis(rc)) - - return rc - - def initialize(self, callbacks=None): - """ Initialize the IMM OI agent - - Args: - callbacks (SaImmOiCallbacksT_2): OI callbacks to register with IMM - - Returns: - SaAisErrorT: Return code of OI initialize - """ - self.handle = SaImmOiHandleT() - self.selection_object = SaSelectionObjectT() - if callbacks is not None: - self.callbacks = callbacks - self.version = deepcopy(self.init_version) - rc = saImmOiInitialize_2(self.handle, self.callbacks, - self.version) - if rc == eSaAisErrorT.SA_AIS_OK: - rc = self._fetch_sel_obj() - if rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE: - rc = self.re_initialize() - else: - log_err("saImmOiInitialize_2 FAILED - %s" % - eSaAisErrorT.whatis(rc)) - - return rc - - @bad_handle_retry - def re_initialize(self): - """ Re-initialize the IMM OI agent - - Returns: - SaAisErrorT: Return code of OI initialize - """ - self.finalize() - rc = self.initialize() - - return rc - - def finalize(self): - """ Finalize IMM OI agent handle - - Returns: - SaAisErrorT: Return code of OI finalize - """ - rc = eSaAisErrorT.SA_AIS_OK - if self.handle is not None: - rc = saImmOiFinalize(self.handle) - if rc != eSaAisErrorT.SA_AIS_OK: - log_err("saImmOiFinalize FAILED - %s" % - eSaAisErrorT.whatis(rc)) - elif rc == eSaAisErrorT.SA_AIS_OK \ - or rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE: - # If the Finalize() call returned BAD_HANDLE, the handle should - # already become stale and invalid, so we reset it anyway. - self.handle = None - return rc - - def get_selection_object(self): - """ Return the selection object associating with the OI handle - - Returns: - SaSelectionObjectT: Selection object associated with the OI handle - """ - return self.selection_object - - def dispatch(self, flags=eSaDispatchFlagsT.SA_DISPATCH_ALL): - """ Dispatch all queued callbacks - - Args: - flags (eSaDispatchFlagsT): Flags specifying dispatch mode - - Returns: - SaAisErrorT: Return code of OI dispatch - """ - rc = saImmOiDispatch(self.handle, flags) - return rc - - def create_runtime_object(self, class_name, parent_name, runtime_obj): - """ Create a runtime object - - Args: - class_name (str): Class name - parent_name (str): Parent name - runtime_obj (ImmObject): Runtime object to create - - Returns: - SaAisErrorT: Return code of OI create runtime object - """ - # Marshall parameters - c_class_name = SaImmClassNameT(class_name) - if parent_name: - c_parent_name = SaNameT(parent_name) - else: - c_parent_name = None - - c_attr_values = [] - - for name, (c_attr_type, values) in runtime_obj.attrs.items(): - if values is None: - values = [] - elif values == [None]: - values = [] - - # Make sure all values are in lists - if not isinstance(values, list): - values = [values] - - # Create the values struct - c_attr = SaImmAttrValuesT_2() - c_attr.attrName = SaImmAttrNameT(name) - c_attr.attrValueType = c_attr_type - c_attr.attrValuesNumber = len(values) - - if not values: - c_attr.attrValues = None - else: - c_attr.attrValues = marshal_c_array(c_attr_type, values) - - c_attr_values.append(c_attr) - - rc = saImmOiRtObjectCreate_2(self.handle, c_class_name, - c_parent_name, c_attr_values) - return rc - - def delete_runtime_object(self, dn): - """ Delete a runtime object - - Args: - dn (str): Runtime object dn - - Returns: - SaAisErrorT: Return code of OI delete runtime object - """ - # Marshall the parameter - c_dn = SaNameT(dn) - rc = saImmOiRtObjectDelete(self.handle, c_dn) - - return rc - - def update_runtime_object(self, dn, attributes): - """ Update the specified object with the requested attribute - modifications - - Args: - dn (str): Object dn - attributes (dict): Dictionary of attribute modifications - - Returns: - SaAisErrorT: Return code of OI update runtime object - """ - # Get the class name for the object - class_name = get_class_name_for_dn(dn) - - # Create and marshall attribute modifications - attr_mods = [] - - for name, values in attributes.items(): - if values is None: - print("WARNING: Received no values for %s in %s" % (name, dn)) - continue - if not isinstance(values, list): - values = [values] - - attr_type = get_attribute_type(name, class_name) - c_attr_mod = SaImmAttrModificationT_2() - c_attr_mod.modType = \ - eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_REPLACE - c_attr_mod.modAttr = SaImmAttrValuesT_2() - c_attr_mod.modAttr.attrName = SaImmAttrNameT(name) - c_attr_mod.modAttr.attrValueType = attr_type - c_attr_mod.modAttr.attrValuesNumber = len(values) - c_attr_mod.modAttr.attrValues = marshal_c_array(attr_type, values) - attr_mods.append(c_attr_mod) - - rc = saImmOiRtObjectUpdate_2(self.handle, SaNameT(dn), attr_mods) - - return rc - - def report_admin_operation_result(self, invocation_id, result): - """ Report the result of an administrative operation - - Args: - invocation_id (SaInvocationT): Invocation id - result (SaAisErrorT): Result of admin operation - - Returns: - SaAisErrorT: Return code of OI admin operation - """ - rc = saImmOiAdminOperationResult(self.handle, invocation_id, - result) - - return rc - - def set_error_string(self, ccb_id, error_string): - """ Set the error string - This can only be called from within OI callbacks of a real implementer. - - Args: - ccb_id (SaImmOiCcbIdT): CCB id - error_string (str): Error string - - Returns: - SaAisErrorT: Return code of OI CCB set error string - """ - c_error_string = SaStringT(error_string) - rc = saImmOiCcbSetErrorString(self.handle, ccb_id, c_error_string) - - return rc - - # Keep old user interfaces of OI pyosaf utils @deprecate def initialize(callbacks=None): @@ -327,8 +52,8 @@ def initialize(callbacks=None): is not SA_AIS_OK """ global _oi_agent - if _oi_agent is None: - _oi_agent = OiAgent() + _oi_agent = OiAgent() + rc = _oi_agent.initialize(callbacks=callbacks) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) @@ -342,10 +67,9 @@ def get_selection_object(): SaSelectionObjectT: Return code of selection object get Raises: - SafException: If the return code of the corresponding OI API call(s) - is not SA_AIS_OK + SafException: If the OI agent is not initialized """ - if _oi_agent is not None: + if _oi_agent is None: # SA_AIS_ERR_INIT is returned if user calls this function without first # calling initialize() raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) @@ -363,11 +87,16 @@ def create_rt_object(class_name, parent_name, runtime_obj): runtime_obj (ImmObject): Runtime object to create Raises: - SafException: If the return code of the corresponding OI API call(s) - is not SA_AIS_OK + SafException: If the OI agent is not initialized """ + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + rc = eSaAisErrorT.SA_AIS_ERR_INIT + else: + rc = _oi_agent.create_runtime_object(class_name, parent_name, + runtime_obj) - rc = _oi_agent.create_runtime_object(class_name, parent_name, runtime_obj) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) @@ -380,10 +109,15 @@ def delete_rt_object(dn): dn (str): Runtime object dn Raises: - SafException: If the return code of the corresponding OI API call(s) - is not SA_AIS_OK + SafException: If the OI agent is not initialized """ - rc = _oi_agent.delete_runtime_object(dn) + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + rc = eSaAisErrorT.SA_AIS_ERR_INIT + else: + rc = _oi_agent.delete_runtime_object(dn) + if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) @@ -398,10 +132,15 @@ def update_rt_object(dn, attributes): attributes (dict): Dictionary of attribute modifications Raises: - SafException: If the return code of the corresponding OI API call(s) - is not SA_AIS_OK + SafException: If the OI agent is not initialized """ - rc = _oi_agent.update_runtime_object(dn, attributes) + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + rc = eSaAisErrorT.SA_AIS_ERR_INIT + else: + rc = _oi_agent.update_runtime_object(dn, attributes) + if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) @@ -415,10 +154,15 @@ def report_admin_operation_result(invocation_id, result): result (SaAisErrorT): Result of admin operation Raises: - SafException: If the return code of the corresponding OI API call(s) - is not SA_AIS_OK + SafException: If the OI agent is not initialized """ - rc = _oi_agent.report_admin_operation_result(invocation_id, result) + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + rc = eSaAisErrorT.SA_AIS_ERR_INIT + else: + rc = _oi_agent.report_admin_operation_result(invocation_id, result) + if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) @@ -433,26 +177,20 @@ def set_error_string(ccb_id, error_string): error_string (str): Error string Raises: - SafException: If the return code of the corresponding OI API call(s) - is not SA_AIS_OK + SafException: If the OI agent is not initialized """ - rc = _oi_agent.set_error_string(ccb_id, error_string) + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + rc = eSaAisErrorT.SA_AIS_ERR_INIT + else: + rc = _oi_agent.set_error_string(ccb_id, error_string) + if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) -def get_class_category(class_name): - """ Return the category of the given class - - Args: - class_name (str): Class name - - Returns: - SaImmClassCategoryT: Class category - """ - return immom.get_class_category(class_name) - - +@deprecate def get_parent_name_for_dn(dn): """ Return the parent's dn of the given object's dn @@ -461,13 +199,19 @@ def get_parent_name_for_dn(dn): Returns: str: DN of the object's parent + + Raises: + SafException: If the OI agent is not initialized """ - if ',' in dn: - return dn.split(',', 1)[1] + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) - return "" + return _oi_agent.get_parent_name_for_dn(dn) +@deprecate def get_object_names_for_class(class_name): """ Return instances of the given class @@ -476,28 +220,19 @@ def get_object_names_for_class(class_name): Returns: list: List of object names + + Raises: + SafException: If the OI agent is not initialized """ - # Marshall the search parameter - c_class_name = c_char_p(class_name) - c_search_param = SaImmSearchParametersT_2() - c_search_param.searchOneAttr.attrName = "SaImmAttrClassName" - c_search_param.searchOneAttr.attrValueType = \ - eSaImmValueTypeT.SA_IMM_ATTR_SASTRINGT - c_search_param.searchOneAttr.attrValue = \ - cast(pointer(c_class_name), c_void_p) - - # Create the search iterator - found_objs = SearchIterator(search_param=c_search_param, - attribute_names=['SaImmAttrClassName']) - found_objs.init() - # Return the dn's of found objects - object_names = [] - for obj in found_objs: - object_names.append(obj.dn) - - return object_names + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) + + return _oi_agent.get_object_names_for_class(class_name) +@deprecate def get_class_name_for_dn(dn): """ Return the class name for an instance with the given dn @@ -506,14 +241,19 @@ def get_class_name_for_dn(dn): Returns: str: Class name + + Raises: + SafException: If the OI agent is not initialized """ - obj = immom.get(dn, ["SaImmAttrClassName"]) - if not obj: - return None + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) - return obj.SaImmAttrClassName + return _oi_agent.get_class_name_for_dn(dn) +@deprecate def get_object_no_runtime(dn): """ Return the IMM object with the given dn @@ -522,10 +262,19 @@ def get_object_no_runtime(dn): Returns: ImmObject: Imm object + + Raises: + SafException: If the OI agent is not initialized """ - return immom.get(dn, ['SA_IMM_SEARCH_GET_CONFIG_ATTR']) + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) + return _oi_agent.get_object_no_runtime(dn) + +@deprecate def get_attribute_type(attribute, class_name): """ Return the type of the attribute in the given class @@ -535,72 +284,37 @@ def get_attribute_type(attribute, class_name): Returns: str: Attribute type - """ - class_desc = immom.class_description_get(class_name) - attr_desc = [attr for attr in class_desc if - attr.attrName == attribute][0] - - return attr_desc.attrValueType - -def get_rdn_attribute_for_class(class_name): - """ Return the RDN attribute for the given class - - Args: - class_name (str): Class name - - Returns: - str: RDN of the class + Raises: + SafException: If the OI agent is not initialized """ - desc = immom.class_description_get(class_name) - - for attr_desc in desc: - if attr_desc.attrFlags & saImm.saImm.SA_IMM_ATTR_RDN: - return attr_desc.attrName - - return None - - -def unmarshal_len_array(c_array, length, value_type): - """ Convert C array with a known length to a Python list - - Args: - c_array (C array): Array in C - length (int): Length of array - value_type (str): Element type in array + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) - Returns: - list: The list converted from c_array - """ - if not c_array: - return [] - ctype = c_array[0].__class__ - if ctype is str: - return unmarshalSaStringTArray(c_array) - val_list = [] - i = 0 - for ptr in c_array: - if i == length: - break - if not ptr: - break - val = unmarshalSaImmValue(ptr, value_type) - val_list.append(val) - i = i + 1 - - return val_list + return _oi_agent.get_attribute_type(attribute, class_name) +@deprecate def get_available_classes_in_imm(): """ Return a list of all available classes in IMM Returns: list: List of available classes + + Raises: + SafException: If the OI agent is not initialized """ - opensaf_imm = immom.get(OPENSAF_IMM_OBJECT) - return opensaf_imm.opensafImmClassNames + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) + return _oi_agent.get_available_classes_in_imm() + +@deprecate def create_non_existing_imm_object(class_name, parent_name, attributes): """ Create an ImmObject instance for an object that has not yet existed @@ -613,21 +327,14 @@ def create_non_existing_imm_object(class_name, parent_name, Returns: ImmObject: Imm object - """ - rdn_attribute = get_rdn_attribute_for_class(class_name) - rdn_value = attributes[rdn_attribute][0] - - if parent_name: - dn = '%s,%s' % (rdn_value, parent_name) - else: - dn = rdn_value - - obj = ImmObject(class_name=class_name, dn=dn) - for name, values in attributes.items(): - obj.__setattr__(name, values) - - obj.__setattr__('SaImmAttrClassName', class_name) - obj.__setattr__('dn', dn) + Raises: + SafException: If the OI agent is not initialized + """ + if _oi_agent is None: + # SA_AIS_ERR_INIT is returned if user calls this function without first + # calling initialize() + raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) - return obj + return _oi_agent.create_non_existing_imm_object(class_name, parent_name, + attributes) diff --git a/python/pyosaf/utils/immoi/agent.py b/python/pyosaf/utils/immoi/agent.py new file mode 100644 index 0000000..1e34b4f --- /dev/null +++ b/python/pyosaf/utils/immoi/agent.py @@ -0,0 +1,473 @@ +########################################################################### # +# +# (C) Copyright 2015 The OpenSAF Foundation +# (C) Copyright 2017 Ericsson AB. All rights reserved. +# +# 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. This file and program are licensed +# under the GNU Lesser General Public License Version 2.1, February 1999. +# The complete license can be accessed from the following location: +# http://opensource.org/licenses/lgpl-license.php +# See the Copying file included with the OpenSAF distribution for full +# licensing terms. +# +# Author(s): Ericsson +# +########################################################################### # +""" +IMM OI common utilities + +Supported functions: +- Set/clear/release implementer for class/object +- Create/delete/update runtime object +- Get class/object attributes +- Get IMM error strings +""" +from __future__ import print_function +from copy import deepcopy +from ctypes import c_char_p, c_void_p, cast, pointer + +from pyosaf.saAis import SaStringT, SaVersionT, SaNameT, SaSelectionObjectT, \ + eSaDispatchFlagsT, eSaAisErrorT +from pyosaf import saImmOi +from pyosaf.saImm import SaImmAttrNameT, SaImmAttrValuesT_2, SaImmClassNameT, \ + SaImmSearchParametersT_2, eSaImmValueTypeT, SaImmAttrModificationT_2, \ + eSaImmAttrModificationTypeT +from pyosaf.saImmOi import SaImmOiHandleT +from pyosaf.utils import log_err, bad_handle_retry, decorate, \ + initialize_decorate +from pyosaf.utils.immom.object import ImmObject +from pyosaf.utils.immom.ccb import marshal_c_array +from pyosaf.utils.immom.iterator import SearchIterator +from pyosaf.utils.immom.agent import OmAgent +from pyosaf.utils.immom.accessor import Accessor + + +OPENSAF_IMM_OBJECT = "opensafImm=opensafImm,safApp=safImmService" + + +# Decorate pure saImmOi* API's with error-handling retry and exception raising +saImmOiInitialize_2 = initialize_decorate(saImmOi.saImmOiInitialize_2) +saImmOiSelectionObjectGet = decorate(saImmOi.saImmOiSelectionObjectGet) +saImmOiDispatch = decorate(saImmOi.saImmOiDispatch) +saImmOiFinalize = decorate(saImmOi.saImmOiFinalize) +saImmOiImplementerSet = decorate(saImmOi.saImmOiImplementerSet) +saImmOiImplementerClear = decorate(saImmOi.saImmOiImplementerClear) +saImmOiClassImplementerSet = decorate(saImmOi.saImmOiClassImplementerSet) +saImmOiClassImplementerRelease = \ + decorate(saImmOi.saImmOiClassImplementerRelease) +saImmOiObjectImplementerSet = decorate(saImmOi.saImmOiObjectImplementerSet) +saImmOiObjectImplementerRelease = \ + decorate(saImmOi.saImmOiObjectImplementerRelease) +saImmOiRtObjectCreate_2 = decorate(saImmOi.saImmOiRtObjectCreate_2) +saImmOiRtObjectDelete = decorate(saImmOi.saImmOiRtObjectDelete) +saImmOiRtObjectUpdate_2 = decorate(saImmOi.saImmOiRtObjectUpdate_2) +saImmOiAdminOperationResult = decorate(saImmOi.saImmOiAdminOperationResult) +saImmOiAdminOperationResult_o2 = \ + decorate(saImmOi.saImmOiAdminOperationResult_o2) +saImmOiAugmentCcbInitialize = decorate(saImmOi.saImmOiAugmentCcbInitialize) +saImmOiCcbSetErrorString = decorate(saImmOi.saImmOiCcbSetErrorString) + + +class OiAgent(object): + """ This class acts as a high-level OI agent, providing OI functions to + the users as a higher level, and relieving the users of the need to manage + the life cycle of the OI agent and providing general interface for + Implementer or Applier used + """ + def __init__(self, version=None): + """ Constructor for OiAgent class + + Args: + version (SaVersionT): OI API version + """ + self.handle = None + self.init_version = version if version is not None \ + else SaVersionT('A', 2, 15) + self.version = None + self.selection_object = None + self.callbacks = None + self.imm_om = None + self.accessor = None + + def _fetch_sel_obj(self): + """ Obtain a selection object (OS file descriptor) + + Returns: + SaAisErrorT: Return code of the saImmOiSelectionObjectGet() API + """ + rc = saImmOiSelectionObjectGet(self.handle, self.selection_object) + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiSelectionObjectGet FAILED - %s" % + eSaAisErrorT.whatis(rc)) + + return rc + + def initialize(self, callbacks=None): + """ Initialize the IMM OI agent + + Args: + callbacks (SaImmOiCallbacksT_2): OI callbacks to register with IMM + + Returns: + SaAisErrorT: Return code of OI initialize + """ + self.imm_om = OmAgent(self.init_version) + rc = self.imm_om.init() + + if rc == eSaAisErrorT.SA_AIS_OK: + if not self.accessor: + self.accessor = Accessor(self.init_version) + rc = self.accessor.init() + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOmAccessorInitialize FAILED - %s" % + eSaAisErrorT.whatis(rc)) + return rc + + self.handle = SaImmOiHandleT() + self.selection_object = SaSelectionObjectT() + if callbacks is not None: + self.callbacks = callbacks + self.version = deepcopy(self.init_version) + rc = saImmOiInitialize_2(self.handle, self.callbacks, + self.version) + if rc == eSaAisErrorT.SA_AIS_OK: + rc = self._fetch_sel_obj() + if rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE: + rc = self.re_initialize() + else: + log_err("saImmOiInitialize_2 FAILED - %s" % + eSaAisErrorT.whatis(rc)) + else: + log_err("saImmOmInitialize FAILED - %s" % eSaAisErrorT.whatis(rc)) + + return rc + + @bad_handle_retry + def re_initialize(self): + """ Re-initialize the IMM OI agent + + Returns: + SaAisErrorT: Return code of OI initialize + """ + self.finalize() + rc = self.initialize() + + return rc + + def finalize(self): + """ Finalize IMM OI agent handle + + Returns: + SaAisErrorT: Return code of OI finalize + """ + rc = eSaAisErrorT.SA_AIS_OK + if self.handle is not None: + rc = saImmOiFinalize(self.handle) + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiFinalize FAILED - %s" % + eSaAisErrorT.whatis(rc)) + + if rc == eSaAisErrorT.SA_AIS_OK \ + or rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE: + # If the Finalize() call returned BAD_HANDLE, the handle should + # already become stale and invalid, so we reset it anyway. + self.handle = None + return rc + + def get_selection_object(self): + """ Return the selection object associating with the OI handle + + Returns: + SaSelectionObjectT: Selection object associated with the OI handle + """ + return self.selection_object + + def dispatch(self, flags=eSaDispatchFlagsT.SA_DISPATCH_ALL): + """ Dispatch all queued callbacks + + Args: + flags (eSaDispatchFlagsT): Flags specifying dispatch mode + + Returns: + SaAisErrorT: Return code of OI dispatch + """ + rc = saImmOiDispatch(self.handle, flags) + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiDispatch FAILED - %s" % eSaAisErrorT.whatis(rc)) + return rc + + def create_runtime_object(self, class_name, parent_name, runtime_obj): + """ Create a runtime object + + Args: + class_name (str): Class name + parent_name (str): Parent name + runtime_obj (ImmObject): Runtime object to create + + Returns: + SaAisErrorT: Return code of OI create runtime object + """ + # Marshall parameters + c_class_name = SaImmClassNameT(class_name) + if parent_name: + c_parent_name = SaNameT(parent_name) + else: + c_parent_name = None + + c_attr_values = [] + + for name, (c_attr_type, values) in runtime_obj.attrs.items(): + if values is None: + values = [] + elif values == [None]: + values = [] + + # Make sure all values are in lists + if not isinstance(values, list): + values = [values] + + # Create the values struct + c_attr = SaImmAttrValuesT_2() + c_attr.attrName = SaImmAttrNameT(name) + c_attr.attrValueType = c_attr_type + c_attr.attrValuesNumber = len(values) + + if not values: + c_attr.attrValues = None + else: + c_attr.attrValues = marshal_c_array(c_attr_type, values) + + c_attr_values.append(c_attr) + + rc = saImmOiRtObjectCreate_2(self.handle, c_class_name, + c_parent_name, c_attr_values) + + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiRtObjectCreate_2 FAILED - %s" % + eSaAisErrorT.whatis(rc)) + return rc + + def delete_runtime_object(self, dn): + """ Delete a runtime object + + Args: + dn (str): Runtime object dn + + Returns: + SaAisErrorT: Return code of OI delete runtime object + """ + # Marshall the parameter + c_dn = SaNameT(dn) + rc = saImmOiRtObjectDelete(self.handle, c_dn) + + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiRtObjectDelete FAILED - %s" % + eSaAisErrorT.whatis(rc)) + return rc + + def update_runtime_object(self, dn, attributes): + """ Update the specified object with the requested attribute + modifications + + Args: + dn (str): Object dn + attributes (dict): Dictionary of attribute modifications + + Returns: + SaAisErrorT: Return code of OI update runtime object + """ + # Get the class name for the object + class_name = self.get_class_name_for_dn(dn) + + # Create and marshall attribute modifications + attr_mods = [] + + for name, values in attributes.items(): + if values is None: + print("WARNING: Received no values for %s in %s" % (name, dn)) + continue + if not isinstance(values, list): + values = [values] + + attr_type = self.get_attribute_type(name, class_name) + c_attr_mod = SaImmAttrModificationT_2() + c_attr_mod.modType = \ + eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_REPLACE + c_attr_mod.modAttr = SaImmAttrValuesT_2() + c_attr_mod.modAttr.attrName = SaImmAttrNameT(name) + c_attr_mod.modAttr.attrValueType = attr_type + c_attr_mod.modAttr.attrValuesNumber = len(values) + c_attr_mod.modAttr.attrValues = marshal_c_array(attr_type, values) + attr_mods.append(c_attr_mod) + + rc = saImmOiRtObjectUpdate_2(self.handle, SaNameT(dn), attr_mods) + + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiRtObjectUpdate_2 FAILED - %s" % + eSaAisErrorT.whatis(rc)) + return rc + + def report_admin_operation_result(self, invocation_id, result): + """ Report the result of an administrative operation + + Args: + invocation_id (SaInvocationT): Invocation id + result (SaAisErrorT): Result of admin operation + + Returns: + SaAisErrorT: Return code of OI admin operation + """ + rc = saImmOiAdminOperationResult(self.handle, invocation_id, result) + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiAdminOperationResult FAILED - %s" % + eSaAisErrorT.whatis(rc)) + return rc + + def set_error_string(self, ccb_id, error_string): + """ Set the error string + This can only be called from within OI callbacks of a real implementer. + + Args: + ccb_id (SaImmOiCcbIdT): CCB id + error_string (str): Error string + + Returns: + SaAisErrorT: Return code of OI CCB set error string + """ + c_error_string = SaStringT(error_string) + rc = saImmOiCcbSetErrorString(self.handle, ccb_id, c_error_string) + + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiCcbSetErrorString FAILED - %s" % + eSaAisErrorT.whatis(rc)) + return rc + + def get_attribute_type(self, attribute, class_name): + """ Return the type of the attribute in the given class + + Args: + attribute (str): Attribute name + class_name (str): Class name + + Returns: + str: Attribute type + """ + _, class_desc = self.imm_om.get_class_description(class_name) + attr_desc = [attr for attr in class_desc if + attr.attrName == attribute][0] + + return attr_desc.attrValueType + + @staticmethod + def get_parent_name_for_dn(dn): + """ Return the parent's dn of the given object's dn + + Args: + dn (str): Object dn + + Returns: + str: DN of the object's parent + """ + if ',' in dn: + return dn.split(',', 1)[1] + + return "" + + @staticmethod + def get_object_names_for_class(class_name): + """ Return instances of the given class + + Args: + class_name (str): Class name + + Returns: + list: List of object names + """ + # Marshall the search parameter + c_class_name = c_char_p(class_name) + c_search_param = SaImmSearchParametersT_2() + c_search_param.searchOneAttr.attrName = "SaImmAttrClassName" + c_search_param.searchOneAttr.attrValueType = \ + eSaImmValueTypeT.SA_IMM_ATTR_SASTRINGT + c_search_param.searchOneAttr.attrValue = \ + cast(pointer(c_class_name), c_void_p) + + # Create the search iterator + found_objs = SearchIterator(search_param=c_search_param, + attribute_names=['SaImmAttrClassName']) + found_objs.init() + # Return the dn's of found objects + object_names = [] + for obj in found_objs: + object_names.append(obj.dn) + + return object_names + + def get_class_name_for_dn(self, dn): + """ Return the class name for an instance with the given dn + + Args: + dn (str): Object dn + + Returns: + str: Class name + """ + _, obj = self.accessor.get(dn, ["SaImmAttrClassName"]) + if not obj: + return None + + return obj.SaImmAttrClassName + + def get_object_no_runtime(self, dn): + """ Return the IMM object with the given dn + + Args: + dn (str): Object dn + + Returns: + ImmObject: Imm object + """ + _, obj = self.accessor.get(dn, ['SA_IMM_SEARCH_GET_CONFIG_ATTR']) + return obj + + def get_available_classes_in_imm(self): + """ Return a list of all available classes in IMM + + Returns: + list: List of available classes + """ + _, opensaf_imm = self.accessor.get(OPENSAF_IMM_OBJECT) + return opensaf_imm.opensafImmClassNames + + def create_non_existing_imm_object(self, class_name, parent_name, + attributes): + """ Create an ImmObject instance for an object that has not yet existed + in IMM + + Args: + class_name (str): Class name + parent_name (str): Parent name + attributes (dict): Dictionary of class attributes + + Returns: + ImmObject: Imm object + """ + rdn_attribute = self.imm_om.get_rdn_attribute_for_class(class_name) + rdn_value = attributes[rdn_attribute][0] + + if parent_name: + dn = '%s,%s' % (rdn_value, parent_name) + else: + dn = rdn_value + + obj = ImmObject(class_name=class_name, dn=dn) + + for name, values in attributes.items(): + obj.__setattr__(name, values) + + obj.__setattr__('SaImmAttrClassName', class_name) + obj.__setattr__('dn', dn) + + return obj diff --git a/python/pyosaf/utils/immoi/implementer.py b/python/pyosaf/utils/immoi/implementer.py index da1d945..1c9f0d8 100755 --- a/python/pyosaf/utils/immoi/implementer.py +++ b/python/pyosaf/utils/immoi/implementer.py @@ -21,12 +21,13 @@ from __future__ import print_function import select import itertools -from pyosaf.saAis import eSaAisErrorT, unmarshalNullArray +from pyosaf.saAis import eSaAisErrorT, unmarshalNullArray, \ + unmarshalSaStringTArray from pyosaf import saImm, saImmOi from pyosaf.saImm import eSaImmValueTypeT, eSaImmAttrModificationTypeT, \ - eSaImmClassCategoryT, SaImmClassNameT + eSaImmClassCategoryT, SaImmClassNameT, unmarshalSaImmValue from pyosaf.saImmOi import SaImmOiImplementerNameT -from pyosaf.utils import immom, immoi, SafException, decorate, bad_handle_retry +from pyosaf.utils import SafException, decorate, bad_handle_retry, log_err from pyosaf.utils.immoi import OiAgent from pyosaf.utils.immom.object import ImmObject @@ -35,9 +36,6 @@ saImmOiClassImplementerSet = decorate(saImmOi.saImmOiClassImplementerSet) saImmOiImplementerSet = decorate(saImmOi.saImmOiImplementerSet) -implementer_instance = None - - class AdminOperationParameter(object): """ This class represents an admin operation parameter """ def __init__(self, name, param_type, value): @@ -101,12 +99,13 @@ class _ContainmentConstraint(object): self.upper = upper -class Constraints(object): +class Constraints(OiAgent): """ Class defining constraints for changes to the instances implemented by the OI """ def __init__(self): """ Create an empty Constraints instance """ + super(Constraints, self).__init__() self.containments = {} self.cardinality = {} @@ -153,7 +152,7 @@ class Constraints(object): if ',' not in child.dn: continue - if immoi.get_parent_name_for_dn(child.dn) == _parent_name \ + if self.get_parent_name_for_dn(child.dn) == _parent_name \ and child.class_name == _class_name: _current_children.append(child) @@ -170,10 +169,10 @@ class Constraints(object): return False # Validate containments affected by create or delete - deleted_objs = [immoi.get_object_no_runtime(dn) for dn in deleted] + deleted_objs = [self.get_object_no_runtime(dn) for dn in deleted] for obj in itertools.chain(created, deleted_objs): - parent_name = immoi.get_parent_name_for_dn(obj.dn) + parent_name = self.get_parent_name_for_dn(obj.dn) # Handle the case where there is no parent if not parent_name: @@ -196,7 +195,7 @@ class Constraints(object): if parent_obj: parent_class = parent_obj[0].class_name else: - parent_class = immoi.get_class_name_for_dn(dn=parent_name) + parent_class = self.get_class_name_for_dn(dn=parent_name) # Ignore children where no constraint is defined for the child or # the parent @@ -263,14 +262,43 @@ class Implementer(OiAgent): self.ccbs = {} self.implemented_names = [] - global implementer_instance - implementer_instance = self - # Register OI callbacks self._register_callbacks() # Initialize OI API and register as implementer for the classes - self._register() + rc = self._register() + if rc != eSaAisErrorT.SA_AIS_OK: + raise Exception("ERROR: Can't register a implementer") + + @staticmethod + def unmarshal_len_array(c_array, length, value_type): + """ Convert C array with a known length to a Python list + + Args: + c_array (C array): Array in C + length (int): Length of array + value_type (str): Element type in array + + Returns: + list: The list converted from c_array + """ + if not c_array: + return [] + ctype = c_array[0].__class__ + if ctype is str: + return unmarshalSaStringTArray(c_array) + val_list = [] + i = 0 + for ptr in c_array: + if i == length: + break + if not ptr: + break + val = unmarshalSaImmValue(ptr, value_type) + val_list.append(val) + i = i + 1 + + return val_list def _register_callbacks(self): """ Register OI callbacks """ @@ -297,8 +325,7 @@ class Implementer(OiAgent): saImmOi.SaImmOiAdminOperationCallbackT_2( self._admin_operation_callback) - @staticmethod - def _admin_operation_callback(oi_handle, c_invocation_id, c_name, + def _admin_operation_callback(self, oi_handle, c_invocation_id, c_name, c_operation_id, c_params): """ Callback for administrative operations @@ -329,12 +356,11 @@ class Implementer(OiAgent): params.append(parameter) # Invoke the operation - result = implementer_instance.admin_operation(operation_id, name, - params) + result = self.admin_operation(operation_id, name, params) # Report the result try: - immoi.report_admin_operation_result(invocation_id, result) + self.report_admin_operation_result(invocation_id, result) except SafException as err: print("ERROR: Failed to report that %s::%s returned %s (%s)" % (name, invocation_id, result, err.msg)) @@ -358,11 +384,10 @@ class Implementer(OiAgent): """ all_instances = [] - for class_name in implementer_instance.class_names: - dns = immoi.get_object_names_for_class(class_name) + for class_name in self.class_names: + dns = self.get_object_names_for_class(class_name) for dn in dns: - dn_in_str = str(dn.value) - obj = immoi.get_object_no_runtime(dn_in_str) + obj = self.get_object_no_runtime(dn) all_instances.append(obj) updated = self.completed_ccbs[ccb_id]['updated'] @@ -374,8 +399,7 @@ class Implementer(OiAgent): del self.completed_ccbs[ccb_id] # Tell the implementer to apply the changes - return implementer_instance.on_apply(all_instances, updated, - created, deleted) + return self.on_apply(all_instances, updated, created, deleted) def _attr_update_callback(self, oi_handle, c_name, c_attr_names): """ Callback for attribute update operation @@ -395,15 +419,13 @@ class Implementer(OiAgent): attr_names = unmarshalNullArray(c_attr_names) # Get the class of the object - class_name = immoi.get_class_name_for_dn(dn=name) + class_name = self.get_class_name_for_dn(dn=name) # Get the values from the user and report back attributes = {} for attr_name in attr_names: - values = implementer_instance.on_runtime_values_get(name, - class_name, - attr_name) + values = self.on_runtime_values_get(name, class_name, attr_name) if values is None: return eSaAisErrorT.SA_AIS_ERR_UNAVAILABLE if not isinstance(values, list): @@ -442,7 +464,7 @@ class Implementer(OiAgent): self.ccbs[ccb_id].append({'type': 'DELETE', 'dn': name}) # Tell the implementer about the operation - return implementer_instance.on_delete_added(name) + return self.on_delete_added(name) def _ccb_modify_callback(self, oi_handle, ccb_id, c_name, c_attr_modification): @@ -470,7 +492,7 @@ class Implementer(OiAgent): attr_name = attr.modAttr.attrName attr_type = attr.modAttr.attrValueType mod_type = attr.modType - attr_values = immoi.unmarshal_len_array( + attr_values = self.unmarshal_len_array( attr.modAttr.attrValues, attr.modAttr.attrValuesNumber, attr.modAttr.attrValueType) attribute_modifications.append({'attribute': attr_name, @@ -479,8 +501,7 @@ class Implementer(OiAgent): 'values': attr_values}) # Tell the implementer about the modification - result = implementer_instance.on_modify_added(attr_name, mod_type, - attr_values) + result = self.on_modify_added(attr_name, mod_type, attr_values) if result != eSaAisErrorT.SA_AIS_OK: implementer_objection = result @@ -524,16 +545,15 @@ class Implementer(OiAgent): attr_type = attr.attrValueType nr_values = attr.attrValuesNumber - attr_values = immoi.unmarshal_len_array(attr.attrValues, - nr_values, - attr_type) + attr_values = self.unmarshal_len_array(attr.attrValues, + nr_values, attr_type) if attr_values: attributes[attr_name] = attr_values else: attributes[attr_name] = None # Fill in any missing attributes - description = immom.class_description_get(class_name) + _, description = self.imm_om.get_class_description(class_name) for attribute in description: if attribute.attrName not in attributes: @@ -550,10 +570,10 @@ class Implementer(OiAgent): 'attributes': attributes}) # Tell the implementer about the operation - obj = immoi.create_non_existing_imm_object(class_name, parent, - attributes) + obj = self.create_non_existing_imm_object(class_name, parent, + attributes) - return implementer_instance.on_create_added(class_name, parent, obj) + return self.on_create_added(class_name, parent, obj) def _ccb_completed_callback(self, oi_handle, ccb_id): """ Callback for completed CCB @@ -581,8 +601,7 @@ class Implementer(OiAgent): 'updated': updated} # Perform validation on the full transaction - return implementer_instance.validate(ccb_id, instances, updated, - created, deleted) + return self.validate(ccb_id, instances, updated, created, deleted) def _collect_full_transaction(self, ccb_id): """ Go through a completed CCB and summarize the full transaction as @@ -605,11 +624,10 @@ class Implementer(OiAgent): updated = [] # Go through current instances - for class_name in implementer_instance.class_names: - dns = immoi.get_object_names_for_class(class_name) + for class_name in self.class_names: + dns = self.get_object_names_for_class(class_name) for dn in dns: - dn_in_str = str(dn.value) - obj = immoi.get_object_no_runtime(dn_in_str) + obj = self.get_object_no_runtime(dn) all_objects_now.append(obj) # Collect proposed state by applying changes on current state @@ -621,7 +639,7 @@ class Implementer(OiAgent): parent = operation['parent'] class_name = operation['className'] attributes = operation['attributes'] - rdn_attr = immoi.get_rdn_attribute_for_class( + rdn_attr = self.imm_om.get_rdn_attribute_for_class( class_name=class_name) rdn_value = attributes[rdn_attr][0] @@ -630,7 +648,7 @@ class Implementer(OiAgent): else: dn = rdn_value - instance = immoi.create_non_existing_imm_object( + instance = self.create_non_existing_imm_object( class_name, parent, attributes) created.append(instance) deleted = [obj for obj in deleted if obj.dn != dn] @@ -725,6 +743,9 @@ class Implementer(OiAgent): rc = saImmOiClassImplementerSet(self.handle, c_class_name) if rc == eSaAisErrorT.SA_AIS_OK: self.implemented_names.append(class_name) + else: + log_err("saImmOiClassImplementerSet FAILED - %s" % + eSaAisErrorT.whatis(rc)) return rc def set_constraints(self, constraints): @@ -862,7 +883,7 @@ class Implementer(OiAgent): # Let the user code validate the CCB (if configured) self.on_validate(instances, updated, created, deleted) except SafException as err: - immoi.set_error_string(ccb_id, err.msg) + self.set_error_string(ccb_id, err.msg) return err.value except Exception: return eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION @@ -887,7 +908,7 @@ class Implementer(OiAgent): SaAisErrorT: Return code of admin operation """ # Get the class name - class_name = immoi.get_class_name_for_dn(object_name) + class_name = self.get_class_name_for_dn(object_name) # Find and execute a matching admin operation if self.admin_operations: @@ -928,13 +949,13 @@ class Implementer(OiAgent): SaAisErrorT: Return code of Implementer register """ # Initialize the OI API - rc = self.initialize() + rc = self.re_initialize() # Ensure that all classes are configuration classes runtime_classes = None if self.class_names is not None: runtime_classes = [item for item in self.class_names - if immoi.get_class_category(item) == + if self.imm_om.get_class_category(item) == eSaImmClassCategoryT.SA_IMM_CLASS_RUNTIME] if runtime_classes: raise Exception("ERROR: Can't be an applier for runtime " @@ -944,7 +965,7 @@ class Implementer(OiAgent): if rc == eSaAisErrorT.SA_AIS_OK: rc = self._register_implementer(self.name) - available_classes = immoi.get_available_classes_in_imm() + available_classes = self.get_available_classes_in_imm() if rc == eSaAisErrorT.SA_AIS_OK: if self.class_names is not None: @@ -969,6 +990,10 @@ class Implementer(OiAgent): """ implementer_name = SaImmOiImplementerNameT(oi_name) rc = saImmOiImplementerSet(self.handle, implementer_name) + + if rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOiClassImplementerSet FAILED - %s" % + eSaAisErrorT.whatis(rc)) return rc def update_runtime_attributes(self, dn, attributes): @@ -995,7 +1020,7 @@ class Implementer(OiAgent): SaAisErrorT: Return code of implementer object create """ # Get the parent name for the object - parent_name = immoi.get_parent_name_for_dn(obj.dn) + parent_name = self.get_parent_name_for_dn(obj.dn) class_name = obj.class_name # Create the object @@ -1062,11 +1087,11 @@ class Applier(Implementer): SaAisErrorT: Return code of applier register """ # Initialize the OI API - rc = self.initialize() + rc = self.re_initialize() # Ensure that all classes are configuration classes runtime_classes = [item for item in self.class_names - if immoi.get_class_category(item) == + if self.imm_om.get_class_category(item) == eSaImmClassCategoryT.SA_IMM_CLASS_RUNTIME] if runtime_classes: raise Exception("ERROR: Can't be an applier for runtime classes %s" @@ -1076,7 +1101,7 @@ class Applier(Implementer): rc = self._register_applier(self.name) # Register as applier for each class - available_classes = immoi.get_available_classes_in_imm() + available_classes = self.get_available_classes_in_imm() for class_name in self.class_names: if class_name in available_classes: diff --git a/python/pyosaf/utils/immom/__init__.py b/python/pyosaf/utils/immom/__init__.py index 57a9692..5706074 100644 --- a/python/pyosaf/utils/immom/__init__.py +++ b/python/pyosaf/utils/immom/__init__.py @@ -21,7 +21,7 @@ from pyosaf.saAis import eSaAisErrorT from pyosaf.utils import deprecate, SafException from pyosaf.utils.immom import agent from pyosaf.utils.immom.object import ImmObject -from pyosaf.utils.immom.accessor import ImmOmAccessor +from pyosaf.utils.immom.accessor import Accessor # Decorate pure saImmOm* API's with error-handling retry and exception raising @@ -70,7 +70,7 @@ def initialize(): SafException: If any IMM OM API call did not return SA_AIS_OK """ global _om_agent - _om_agent = agent.ImmOmAgent() + _om_agent = agent.OmAgent() # Initialize IMM OM handle and return the API return code rc = _om_agent.init() @@ -93,7 +93,7 @@ def get(object_name, attr_name_list=None, class_name=None): Raises: SafException: If any IMM OM API call did not return SA_AIS_OK """ - _accessor = ImmOmAccessor() + _accessor = Accessor() _accessor.init() rc, imm_object = _accessor.get(object_name, attr_name_list, class_name) @@ -173,6 +173,7 @@ def get_rdn_attribute_for_class(class_name): return _om_agent.get_rdn_attribute_for_class(class_name) +@deprecate def get_class_category(class_name): """ Return the category of the given class diff --git a/python/pyosaf/utils/immom/accessor.py b/python/pyosaf/utils/immom/accessor.py index aac0f6d..b411387 100644 --- a/python/pyosaf/utils/immom/accessor.py +++ b/python/pyosaf/utils/immom/accessor.py @@ -28,23 +28,23 @@ from pyosaf.utils.immom import agent from pyosaf.utils.immom.object import ImmObject -class ImmOmAccessor(agent.ImmOmAgentManager): +class Accessor(agent.OmAgentManager): """ This class provides functions of the ImmOm Accessor interface """ def __init__(self, version=None): - """ Constructor for ImmOmAccessor class + """ Constructor for Accessor class Args: version (SaVersionT): IMM OM version """ - super(ImmOmAccessor, self).__init__(version) + super(Accessor, self).__init__(version) self.accessor_handle = None def __enter__(self): - """ Enter method for ImmOmAccessor class """ + """ Enter method for Accessor class """ return self def __exit__(self, exception_type, exception_value, traceback): - """ Exit method for ImmOmAccessor class + """ Exit method for Accessor class Finalize the accessor handle and the IMM OM agent handle """ @@ -56,7 +56,7 @@ class ImmOmAccessor(agent.ImmOmAgentManager): self.handle = None def __del__(self): - """ Destructor for ImmOmAccessor class + """ Destructor for Accessor class Finalize the accessor handle and the IMM OM agent handle """ @@ -115,10 +115,8 @@ class ImmOmAccessor(agent.ImmOmAgentManager): rc = agent.saImmOmAccessorGet_2(self.accessor_handle, SaNameT(object_name), attr_names, attributes) - if rc != eSaAisErrorT.SA_AIS_OK: - log_err("saImmOmAccessorGet_2 FAILED - %s" % - eSaAisErrorT.whatis(rc)) - else: + + if rc == eSaAisErrorT.SA_AIS_OK: attrs = {} attr_list = unmarshalNullArray(attributes) for attr in attr_list: @@ -130,6 +128,17 @@ class ImmOmAccessor(agent.ImmOmAgentManager): for val in attr_range]] if 'SaImmAttrClassName' not in attrs and class_name: attrs['SaImmAttrClassName'] = class_name - imm_obj = ImmObject(object_name, attrs) + imm_obj = ImmObject(dn=object_name, attributes=attrs) + + if rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE: + init_rc = self.init() + # If the re-initialization of agent handle succeeds, we still need + # to return BAD_HANDLE to the users, so that they would re-try the + # failed operation. Otherwise, the true error code is returned + # to the user to decide further actions. + if init_rc != eSaAisErrorT.SA_AIS_OK: + log_err("saImmOmAccessorGet_2 FAILED - %s" % + eSaAisErrorT.whatis(rc)) + rc = init_rc return rc, imm_obj diff --git a/python/pyosaf/utils/immom/agent.py b/python/pyosaf/utils/immom/agent.py index b813055..a313aea 100644 --- a/python/pyosaf/utils/immom/agent.py +++ b/python/pyosaf/utils/immom/agent.py @@ -64,10 +64,10 @@ saImmOmAdminOperationContinuationClear = \ decorate(saImmOm.saImmOmAdminOperationContinuationClear) -class ImmOmAgentManager(object): +class OmAgentManager(object): """ This class manages the life cycle of an IMM OM agent """ def __init__(self, version=None): - """ Constructor for ImmOmAgentManager class + """ Constructor for OmAgentManager class Args: version (SaVersionT): IMM OM API version @@ -79,11 +79,11 @@ class ImmOmAgentManager(object): self.selection_object = None def __enter__(self): - """ Enter method for ImmOmAgentManager class """ + """ Enter method for OmAgentManager class """ return self def __exit__(self, exception_type, exception_value, traceback): - """ Exit method for ImmOmAgentManager class + """ Exit method for OmAgentManager class Finalize the IMM OM agent handle """ @@ -92,7 +92,7 @@ class ImmOmAgentManager(object): self.handle = None def __del__(self): - """ Destructor for ImmOmAgentManager class + """ Destructor for OmAgentManager class Finalize the IMM OM agent handle """ @@ -149,7 +149,8 @@ class ImmOmAgentManager(object): if rc != eSaAisErrorT.SA_AIS_OK: log_err("saImmOmFinalize FAILED - %s" % eSaAisErrorT.whatis(rc)) - elif rc == eSaAisErrorT.SA_AIS_OK \ + + if rc == eSaAisErrorT.SA_AIS_OK \ or rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE: # If the Finalize() call returned BAD_HANDLE, the handle should # already become stale and invalid, so we reset it anyway. @@ -157,7 +158,7 @@ class ImmOmAgentManager(object): return rc -class ImmOmAgent(ImmOmAgentManager): +class OmAgent(OmAgentManager): """ This class acts as a high-level IMM OM agent, providing IMM OM functions to the users at a higher level, and relieving the users of the need to manage the life cycle of the IMM OM agent """ @@ -265,8 +266,8 @@ class ImmOmAgent(ImmOmAgentManager): Returns: SaAisErrorT: Return code of the corresponding IMM API call(s) """ - _owner = ImmOmAdminOwner(self.handle) - rc = _owner.initialize() + _owner = OmAdminOwner(self.handle) + rc = _owner.init() if rc == eSaAisErrorT.SA_AIS_OK: index = dn.rfind(",") object_rdn = dn[index+1:] @@ -314,10 +315,10 @@ class ImmOmAgent(ImmOmAgentManager): return c_category.value -class ImmOmAdminOwner(object): +class OmAdminOwner(object): """ This class encapsulates the ImmOm Admin Owner interface """ def __init__(self, imm_handle, owner_name=""): - """ Constructor for ImmOmAdminOwner class + """ Constructor for OmAdminOwner class Args: imm_handle (SaImmHandleT): IMM OM agent handle @@ -333,11 +334,11 @@ class ImmOmAdminOwner(object): self.owner_handle = None def __enter__(self): - """ Enter method for ImmOmAdminOwner class """ + """ Enter method for OmAdminOwner class """ return self def __exit__(self, exception_type, exception_value, traceback): - """ Exit method for ImmOmAdminOwner class + """ Exit method for OmAdminOwner class Finalize the admin owner handle """ @@ -346,7 +347,7 @@ class ImmOmAdminOwner(object): self.owner_handle = None def __del__(self): - """ Destructor for ImmOmAdminOwner class + """ Destructor for OmAdminOwner class Finalize the admin owner handle """ @@ -354,7 +355,7 @@ class ImmOmAdminOwner(object): saImmOm.saImmOmAdminOwnerFinalize(self.owner_handle) self.owner_handle = None - def initialize(self): + def init(self): """ Initialize the IMM admin owner interface Return: diff --git a/python/pyosaf/utils/immom/ccb.py b/python/pyosaf/utils/immom/ccb.py index 042a726..15b891b 100644 --- a/python/pyosaf/utils/immom/ccb.py +++ b/python/pyosaf/utils/immom/ccb.py @@ -21,12 +21,13 @@ from ctypes import c_void_p, pointer, cast, POINTER from pyosaf.saAis import eSaAisErrorT, SaNameT, SaStringT, SaFloatT, \ unmarshalNullArray, SaDoubleT, SaTimeT, SaUint64T, SaInt64T, SaUint32T, \ - SaInt32T, SaVersionT + SaInt32T from pyosaf.saImm import eSaImmScopeT, eSaImmValueTypeT, SaImmAttrValuesT_2 from pyosaf import saImm from pyosaf import saImmOm from pyosaf.utils.immom import agent -from pyosaf.utils.immom.accessor import ImmOmAccessor +from pyosaf.utils.immom.agent import OmAgent +from pyosaf.utils.immom.accessor import Accessor from pyosaf.utils import log_err, bad_handle_retry @@ -83,12 +84,11 @@ def marshal_c_array(value_type, value_list): return c_array -class Ccb(object): +class Ccb(OmAgent): """ Class representing an ongoing CCB """ def __init__(self, flags=saImm.saImm.SA_IMM_CCB_REGISTERED_OI, version=None): - self.init_version = version if version else SaVersionT('A', 2, 15) - self.imm_om = None + super(Ccb, self).__init__(version=version) self.admin_owner = None self.accessor = None self.ccb_handle = None @@ -123,43 +123,13 @@ class Ccb(object): if self.ccb_handle is not None: saImmOm.saImmOmCcbFinalize(self.ccb_handle) self.ccb_handle = None + if self.admin_owner: del self.admin_owner - if self.imm_om: - del self.imm_om - - def clear_admin_owner(self, obj_name, scope=eSaImmScopeT.SA_IMM_SUBTREE): - """ Clear the admin owner for the set of object identified by the scope - and obj_name parameters - - Args: - obj_name (str): Object name - scope (SaImmScopeT): Scope of the clear operation - - Returns: - SaAisErrorT: Return code of the corresponding IMM API call(s) - """ - return self.imm_om.clear_admin_owner(obj_name, scope) - - def finalize(self): - """ Finalize the CCB handle - - Returns: - SaAisErrorT: Return code of the saImmOmCcbFinalize() API call - """ - rc = eSaAisErrorT.SA_AIS_OK - if self.ccb_handle: - rc = agent.saImmOmCcbFinalize(self.ccb_handle) - if rc != eSaAisErrorT.SA_AIS_OK: - log_err("saImmOmCcbFinalize FAILED - %s" % - eSaAisErrorT.whatis(rc)) - elif rc == eSaAisErrorT.SA_AIS_OK \ - or rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE: - # If the Finalize() call returned BAD_HANDLE, the handle should - # already become stale and invalid, so we reset it anyway. - self.ccb_handle = None - return rc + if self.handle is not None: + saImmOm.saImmOmFinalize(self.handle) + self.handle = None @bad_handle_retry def init(self, owner_name=""): @@ -171,26 +141,22 @@ class Ccb(object): Return: SaAisErrorT: Return code of the corresponding IMM API calls """ - # Clean previous resources if any - self.finalize() - self.imm_om = agent.ImmOmAgent(self.init_version) - rc = self.imm_om.init() + rc = super(Ccb, self).init() if rc == eSaAisErrorT.SA_AIS_OK: - _om_handle = self.imm_om.get_handle() - self.admin_owner = agent.ImmOmAdminOwner(_om_handle, owner_name) - self.admin_owner.initialize() + self.admin_owner = agent.OmAdminOwner(self.handle, owner_name) + rc = self.admin_owner.init() + if rc == eSaAisErrorT.SA_AIS_OK: _owner_handle = self.admin_owner.get_handle() self.ccb_handle = saImmOm.SaImmCcbHandleT() - rc = agent.saImmOmCcbInitialize( - _owner_handle, self.ccb_flags, self.ccb_handle) + rc = agent.saImmOmCcbInitialize(_owner_handle, self.ccb_flags, + self.ccb_handle) if rc != eSaAisErrorT.SA_AIS_OK: log_err("saImmOmCcbInitialize FAILED - %s" % eSaAisErrorT.whatis(rc)) return rc - @bad_handle_retry def create(self, obj, parent_name=None): """ Create the CCB object @@ -237,7 +203,6 @@ class Ccb(object): return rc - @bad_handle_retry def delete(self, object_name): """ Add a delete operation of the object with the given DN to the CCB @@ -269,7 +234,6 @@ class Ccb(object): return rc - @bad_handle_retry def _modify(self, object_name, attr_name, values, mod_type): """ Modify an existing object @@ -285,7 +249,7 @@ class Ccb(object): rc = eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM else: if not self.accessor: - self.accessor = ImmOmAccessor(self.init_version) + self.accessor = Accessor(self.init_version) self.accessor.init() # Get the attribute value type by reading the object's class @@ -293,8 +257,7 @@ class Ccb(object): rc, obj = self.accessor.get(object_name) if rc == eSaAisErrorT.SA_AIS_OK: class_name = obj.SaImmAttrClassName - _, attr_def_list = \ - self.imm_om.get_class_description(class_name) + _, attr_def_list = self.get_class_description(class_name) value_type = None for attr_def in attr_def_list: if attr_def.attrName == attr_name: diff --git a/python/pyosaf/utils/immom/iterator.py b/python/pyosaf/utils/immom/iterator.py index 51f7e95..7402c94 100644 --- a/python/pyosaf/utils/immom/iterator.py +++ b/python/pyosaf/utils/immom/iterator.py @@ -30,7 +30,7 @@ from pyosaf.utils.immom import agent from pyosaf.utils.immom.object import ImmObject -class SearchIterator(agent.ImmOmAgentManager, Iterator): +class SearchIterator(agent.OmAgentManager, Iterator): """ General search iterator """ def __init__(self, root_name=None, scope=eSaImmScopeT.SA_IMM_SUBTREE, attribute_names=None, search_param=None, version=None): @@ -109,7 +109,7 @@ class SearchIterator(agent.ImmOmAgentManager, Iterator): [unmarshalSaImmValue(attr.attrValues[val], attr.attrValueType) for val in attr_range]] - return ImmObject(obj_name, attrs) + return ImmObject(str(obj_name), attrs) @bad_handle_retry def init(self): diff --git a/python/pyosaf/utils/immom/object.py b/python/pyosaf/utils/immom/object.py index 0cef920..435a244 100644 --- a/python/pyosaf/utils/immom/object.py +++ b/python/pyosaf/utils/immom/object.py @@ -20,7 +20,7 @@ from pyosaf.saAis import eSaAisErrorT from pyosaf.saImm import saImm from pyosaf.utils import SafException -from pyosaf.utils.immom.agent import ImmOmAgent +from pyosaf.utils.immom.agent import OmAgent class ImmObject(object): @@ -43,7 +43,7 @@ class ImmObject(object): is not SA_AIS_OK """ self.__dict__["dn"] = dn - _imm_om = ImmOmAgent() + _imm_om = OmAgent() rc = _imm_om.init() if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) -- 2.7.4 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel