@@ -231,11 +356,15 @@ def set_error_string(ccb_id, error_string):
Args:
ccb_id (SaImmOiCcbIdT): CCB id
error_string (str): Error string
- """
+ Raises:
+ SafException: If the return code of the corresponding OI API call(s)
+ is not SA_AIS_OK
+ """
c_error_string = SaStringT(error_string)
-
- saImmOiCcbSetErrorString(handle, ccb_id, c_error_string)
+ rc = saImmOiCcbSetErrorString(_oi_agent.handle, ccb_id, c_error_string)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
def get_class_category(class_name):
@@ -245,15 +374,9 @@ def get_class_category(class_name):
class_name (str): Class name
Returns:
- SaAisErrorT: Return code of class category get
+ SaImmClassCategoryT: Class category
"""
- c_attr_defs = pointer(pointer(SaImmAttrDefinitionT_2()))
- c_category = SaImmClassCategoryT()
- c_class_name = SaImmClassNameT(class_name)
-
- immom.saImmOmClassDescriptionGet_2(immom.handle, c_class_name, c_category,
- c_attr_defs)
- return c_category.value
+ return immom.get_class_category(class_name)
def get_parent_name_for_dn(dn):
@@ -273,7 +396,6 @@ def get_parent_name_for_dn(dn):
def get_object_names_for_class(class_name):
""" Return instances of the given class
- This is safe to call from OI callbacks.
Args:
class_name (str): Class name
@@ -293,9 +415,14 @@ def get_object_names_for_class(class_name):
# 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
- return [obj.dn for obj in found_objs]
+ object_names = []
+ for obj in found_objs:
+ object_names.append(obj.dn)
+ print(obj.dn.value)
+
+ return object_names
def get_class_name_for_dn(dn):
@@ -317,12 +444,6 @@ def get_class_name_for_dn(dn):
def get_object_no_runtime(dn):
""" Return the IMM object with the given dn
- This is safe to call from OI callbacks as only the config attributes will
- be read.
- The function needs to query the class to find config attributes. If the
- class name is known by the caller it can be passed in. Otherwise, it will
- be looked up.
-
Args:
dn (str): Object dn
@@ -334,7 +455,6 @@ def get_object_no_runtime(dn):
def get_attribute_type(attribute, class_name):
""" Return the type of the attribute in the given class
- This is safe to use from OI callbacks.
Args:
attribute (str): Attribute name
@@ -344,14 +464,14 @@ def get_attribute_type(attribute, class_name):
str: Attribute type
"""
class_desc = immom.class_description_get(class_name)
- attr_desc = [attr for attr in class_desc if attr.attrName == attribute][0]
+ 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
- This is safe to call from OI callbacks.
Args:
class_name (str): Class name
@@ -400,17 +520,16 @@ def unmarshal_len_array(c_array, length, value_type):
def get_available_classes_in_imm():
""" Return a list of all available classes in IMM
- This is safe to call from OI callbacks.
Returns:
list: List of available classes
"""
opensaf_imm = immom.get(OPENSAF_IMM_OBJECT)
-
return opensaf_imm.opensafImmClassNames
-def create_non_existing_imm_object(class_name, parent_name, attributes):
+def create_non_existing_imm_object(class_name, parent_name,
+ attributes):
""" Create an ImmObject instance for an object that has not yet existed
in IMM
diff --git a/python/pyosaf/utils/immoi/implementer.py b/python/pyosaf/utils/immoi/implementer.py
index 3d44c9a..f57e326 100755
--- a/python/pyosaf/utils/immoi/implementer.py
+++ b/python/pyosaf/utils/immoi/implementer.py
@@ -21,133 +21,20 @@ from __future__ import print_function
import select
import itertools
-from pyosaf.saAis import eSaAisErrorT, unmarshalNullArray
+from pyosaf.saAis import eSaAisErrorT, unmarshalNullArray, SaVersionT
from pyosaf import saImm, saImmOi
from pyosaf.saImm import eSaImmValueTypeT, eSaImmAttrModificationTypeT, \
- eSaImmClassCategoryT
-from pyosaf.utils import immom, immoi, SafException
+ eSaImmClassCategoryT, SaImmClassNameT
+from pyosaf.saImmOi import SaImmOiImplementerNameT
+from pyosaf.utils import immom, immoi, SafException, decorate, bad_handle_retry
+from pyosaf.utils.immoi import OiAgent
+from pyosaf.utils.immom.object import ImmObject
-implementer_instance = None
-completed_ccbs = {}
-ccbs = {}
-
-
-def _collect_full_transaction(ccb_id):
- """ Go through a completed CCB and summarize the full transaction as seen
- by the OI
-
- Args:
- ccb_id (str): CCB id
-
- Returns:
- {'instances_after' : instances,
- 'created': created,
- 'deleted': deleted,
- 'updated': updated}
- """
- # Collect current state
- all_objects_now = []
-
- created = []
- deleted = []
- updated = []
-
- # Go through current instances
- for class_name in implementer_instance.class_names:
- dns = immoi.get_object_names_for_class(class_name)
- for dn in dns:
- obj = immoi.get_object_no_runtime(dn)
-
- all_objects_now.append(obj)
-
- # Collect proposed state by applying changes on current state
- for operation in ccbs[ccb_id]:
- operation_type = operation['type']
-
- # Handle object create operation
- if operation_type == 'CREATE':
- parent = operation['parent']
- class_name = operation['className']
- attributes = operation['attributes']
- rdn_attr = immoi.get_rdn_attribute_for_class(class_name)
- rdn_value = attributes[rdn_attr][0]
-
- if parent:
- dn = '%s,%s' % (rdn_value, parent)
- else:
- dn = rdn_value
-
- instance = immoi.create_non_existing_imm_object(class_name, parent,
- attributes)
- created.append(instance)
- deleted = [obj for obj in deleted if obj.dn != dn]
-
- # Handle object delete operation
- elif operation_type == 'DELETE':
- dn = operation['dn']
- deleted.append(immom.get(dn))
- created = [obj for obj in created if obj.dn != dn]
- updated = [obj for obj in updated if obj.dn != dn]
-
- # Handle object modify operation
- elif operation_type == 'MODIFY':
- dn = operation['dn']
- modifications = operation['modification']
-
- for attr_modification in modifications:
- mod_type = attr_modification['modification']
- attribute = attr_modification['attribute']
- values = attr_modification['values']
-
- # Find affected object
- affected_instance = None
- affected_instances = [obj for obj in all_objects_now
- if obj.dn == dn]
-
- if not affected_instances:
- print('ERROR: Failed to find object %s affected by modify '
- 'operation' % dn)
- else:
- affected_instance = affected_instances[0]
- if affected_instance not in updated:
- updated.append(affected_instance)
-
- if mod_type == \
- eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_ADD:
- curr_value = affected_instance.__getattr__(attribute)
- curr_value.append(values)
- affected_instance.__setattr__(attribute, curr_value)
-
- elif mod_type == \
- eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_DELETE:
- for value in values:
- curr_value = affected_instance.__getattr__(attribute)
- curr_value.remove(value)
- affected_instance.__setattr__(attribute, curr_value)
-
- elif mod_type == \
- eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_REPLACE:
- affected_instance.__setattr__(attribute, values)
+saImmOiClassImplementerSet = decorate(saImmOi.saImmOiClassImplementerSet)
- # Return the summary
- instances_after = []
- for modify_obj in itertools.chain(all_objects_now, created):
- is_deleted = False
- for obj in deleted:
- if obj.dn == modify_obj.dn:
- is_deleted = True
-
- if not is_deleted:
- instances_after.append(modify_obj)
-
- out = {'instances_after': instances_after,
- 'created': created,
- 'deleted': deleted,
- 'updated': updated}
-
- return out
+implementer_instance = None
class AdminOperationParameter(object):
@@ -159,312 +46,6 @@ class AdminOperationParameter(object):
self.value = value
-# Set up callbacks
-def admin_operation_callback(oi_handle, c_invocation_id, c_name,
- c_operation_id, c_params):
- """ Callback for administrative operations
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- c_invocation_id (SaInvocationT): Invocation id
- c_name (SaNameT): Pointer to object name
- c_operation_id (SaImmAdminOperationIdT): Operation id
- c_params (SaImmAdminOperationParamsT_2): Pointer to an array of
- pointers to parameter descriptors
- """
- # Unmarshal parameters
- invocation_id = c_invocation_id
- name = \
- saImm.unmarshalSaImmValue(c_name, eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
- operation_id = c_operation_id
-
- params = []
-
- for param in unmarshalNullArray(c_params):
- param_name = param.paramName
- param_type = param.paramType
- param_buffer = param.paramBuffer
-
- value = saImm.unmarshalSaImmValue(param_buffer, param_type)
- parameter = AdminOperationParameter(param_name, param_type, value)
- params.append(parameter)
-
- # Invoke the operation
- result = implementer_instance.admin_operation(operation_id, name, params)
-
- # Report the result
- try:
- immoi.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))
-
-
-def ccb_abort_callback(oi_handle, ccb_id):
- """ Callback for aborted CCB
- The aborted CCB will be removed from the cache.
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- ccb_id (SaImmOiCcbIdT): CCB id
- """
- del ccbs[ccb_id]
-
-
-def ccb_apply_callback(oi_handle, ccb_id):
- """ Callback for apply of CCBs
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- ccb_id (SaImmOiCcbIdT): CCB id
- """
- all_instances = []
-
- for class_name in implementer_instance.class_names:
- dns = immoi.get_object_names_for_class(class_name)
- for dn in dns:
- obj = immoi.get_object_no_runtime(dn)
- all_instances.append(obj)
-
- updated = completed_ccbs[ccb_id]['updated']
- created = completed_ccbs[ccb_id]['added']
- deleted = completed_ccbs[ccb_id]['removed']
-
- # Remove the CCB from the caches
- del ccbs[ccb_id]
- del completed_ccbs[ccb_id]
-
- # Tell the implementer to apply the changes
- return implementer_instance.on_apply(all_instances, updated,
- created, deleted)
-
-
-def attr_update_callback(oi_handle, c_name, c_attr_names):
- """ Callback for attribute update operation
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- c_name (SaNameT): Pointer to object name
- c_attr_names (SaImmAttrNameT): Pointer to array of attribute names
-
- Returns:
- SaAisErrorT: Return code of the attribute update callback
- """
- # Unmarshal parameters
- name = \
- saImm.unmarshalSaImmValue(c_name, eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
- attr_names = unmarshalNullArray(c_attr_names)
-
- # Get the class of the object
- class_name = immoi.get_class_name_for_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)
- if values is None:
- return eSaAisErrorT.SA_AIS_ERR_UNAVAILABLE
- if not isinstance(values, list):
- values = [values]
-
- attributes[attr_name] = values
-
- # Report the updated values for the attributes
- try:
- immoi.update_rt_object(name, attributes)
- return eSaAisErrorT.SA_AIS_OK
- except SafException:
- return eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION
-
-
-def ccb_delete_callback(oi_handle, ccb_id, c_name):
- """ Callback for object delete operation
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- ccb_id (SaImmOiCcbIdT): CCB id
- c_name (SaNameT): Pointer to object name
-
- Returns:
- SaAisErrorT: Return code of the object delete callback
- """
- # Unmarshal the parameters
- name = \
- saImm.unmarshalSaImmValue(c_name, eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
-
- # Create a new CCB in the cache if needed
- if ccb_id not in list(ccbs.keys()):
- ccbs[ccb_id] = []
-
- # Cache the operation
- ccbs[ccb_id].append({'type': 'DELETE',
- 'dn': name})
-
- # Tell the implementer about the operation
- return implementer_instance.on_delete_added(name)
-
-
-def ccb_modify_callback(oi_handle, ccb_id, c_name, c_attr_modification):
- """ Callback for object modify operation
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- ccb_id (SaImmOiCcbIdT): CCB id
- c_name (SaNameT): Pointer to object name
- c_attr_modification (SaImmAttrModificationT_2): Pointer to an array of
- pointers to descriptors of the modifications to perform
-
- Returns:
- SaAisErrorT: Return code of the object modify callback
- """
- # Unmarshal the parameters
- name = \
- saImm.unmarshalSaImmValue(c_name, eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
-
- attribute_modifications = []
- implementer_objection = None
-
- for attr in unmarshalNullArray(c_attr_modification):
- attr_name = attr.modAttr.attrName
- attr_type = attr.modAttr.attrValueType
- mod_type = attr.modType
- attr_values = immoi.unmarshal_len_array(attr.modAttr.attrValues,
- attr.modAttr.attrValuesNumber,
- attr.modAttr.attrValueType)
- attribute_modifications.append({'attribute': attr_name,
- 'type': attr_type,
- 'modification': mod_type,
- 'values': attr_values})
-
- # Tell the implementer about the modification
- result = implementer_instance.on_modify_added(attr_name, mod_type,
- attr_values)
- if result != eSaAisErrorT.SA_AIS_OK:
- implementer_objection = result
-
- # Create a new CCB in the cache if needed
- if ccb_id not in list(ccbs.keys()):
- ccbs[ccb_id] = []
-
- # Store the modifications in the cache
- ccbs[ccb_id].append({'type': 'MODIFY',
- 'dn': name,
- 'modification': attribute_modifications})
-
- # Respond and say if this is accepted by the implementer
- if implementer_objection:
- return implementer_objection
-
- return eSaAisErrorT.SA_AIS_OK
-
-
-def ccb_create_callback(oi_handle, ccb_id, class_name,
- c_parent, c_attr_values):
- """ Callback for object create operation
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- ccb_id (SaImmOiCcbIdT): CCB id
- class_name (SaImmClassNameT): Class name
- c_parent (SaNameT): Pointer to name of object's parent
- c_attr_values (SaImmAttrValuesT_2): Pointer to an array of pointers to
- attribute descriptors
-
- Returns:
- SaAisErrorT: Return code of the object create callback
- """
- # Unmarshal parameters
- parent = saImm.unmarshalSaImmValue(c_parent,
- eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
- attributes = {}
-
- for attr in unmarshalNullArray(c_attr_values):
- attr_name = attr.attrName
- attr_type = attr.attrValueType
- nr_values = attr.attrValuesNumber
-
- attr_values = immoi.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)
-
- for attribute in description:
- if attribute.attrName not in attributes:
- attributes[attribute.attrName] = None
-
- # Create a new CCB in the cache if needed
- if ccb_id not in list(ccbs.keys()):
- ccbs[ccb_id] = []
-
- # Cache the create operation
- ccbs[ccb_id].append({'type': 'CREATE',
- 'parent': parent,
- 'className': class_name,
- 'attributes': attributes})
-
- # Tell the implementer about the operation
- obj = immoi.create_non_existing_imm_object(class_name, parent, attributes)
-
- return implementer_instance.on_create_added(class_name, parent, obj)
-
-
-def ccb_completed_callback(oi_handle, ccb_id):
- """ Callback for completed CCB
- Validate any configured containments and call the configured on_validate
- function
-
- Args:
- oi_handle (SaImmOiHandleT): OI handle
- ccb_id (SaImmOiCcbIdT): CCB id
-
- Returns:
- SaAisErrorT: Return code of the CCB-completed validation
- """
- # Get a summary of the changes in the CCB
- summary = _collect_full_transaction(ccb_id)
- instances = summary['instances_after']
- created = summary['created']
- deleted = summary['deleted']
- updated = summary['updated']
-
- # Store added, removed, updated for apply
- completed_ccbs[ccb_id] = {'added': created,
- 'removed': deleted,
- 'updated': updated}
-
- # Perform validation on the full transaction
- return implementer_instance.validate(ccb_id, instances, updated,
- created, deleted)
-
-
-# OI callbacks
-callbacks = saImmOi.SaImmOiCallbacksT_2()
-
-callbacks.saImmOiCcbAbortCallback = \
- saImmOi.SaImmOiCcbAbortCallbackT(ccb_abort_callback)
-callbacks.saImmOiCcbApplyCallback = \
- saImmOi.SaImmOiCcbApplyCallbackT(ccb_apply_callback)
-callbacks.saImmOiCcbCompletedCallback = \
- saImmOi.SaImmOiCcbCompletedCallbackT(ccb_completed_callback)
-callbacks.saImmOiCcbObjectCreateCallback = \
- saImmOi.SaImmOiCcbObjectCreateCallbackT_2(ccb_create_callback)
-callbacks.saImmOiCcbObjectDeleteCallback = \
- saImmOi.SaImmOiCcbObjectDeleteCallbackT(ccb_delete_callback)
-callbacks.saImmOiCcbObjectModifyCallback = \
- saImmOi.SaImmOiCcbObjectModifyCallbackT_2(ccb_modify_callback)
-callbacks.saImmOiRtAttrUpdateCallback = \
- saImmOi.SaImmOiRtAttrUpdateCallbackT(attr_update_callback)
-callbacks.saImmOiAdminOperationCallback = \
- saImmOi.SaImmOiAdminOperationCallbackT_2(admin_operation_callback)
-
-
def admin_operation_decorate(class_name, op_id):
""" Admin operation decorator
Decorate the specified function with the provided class name and admin
@@ -588,7 +169,7 @@ class Constraints(object):
return False
# Validate containments affected by create or delete
- deleted_objs = [immoi.get_object_no_runtime(obj) for obj in deleted]
+ deleted_objs = [immoi.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)
@@ -614,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(parent_name)
+ parent_class = immoi.get_class_name_for_dn(dn=parent_name)
# Ignore children where no constraint is defined for the child or
# the parent
@@ -657,7 +238,7 @@ class Constraints(object):
error_string)
-class Implementer(object):
+class Implementer(OiAgent):
""" Class representing an object implementer """
def __init__(self, class_names=None, name="wrapper", on_create=None,
on_delete=None, on_modify=None, on_validate=None,
@@ -674,30 +255,477 @@ class Implementer(object):
self.on_runtime_values_get_cb = on_runtime_values_get
self.admin_operations = admin_operations
self.constraints = constraints
+ self.callbacks = None
+ self.completed_ccbs = {}
+ self.ccbs = {}
+ self.implemented_names = []
global implementer_instance
implementer_instance = self
+ # Register OI callbacks
+ self._register_callbacks()
+
+ # Initialize OI agent
+ self.version = SaVersionT('A', 2, 15)
+ super(Implementer, self).__init__(callbacks=self.callbacks,
+ version=self.version)
+
# Initialize OI API and register as implementer for the classes
self._register()
+ def _register_callbacks(self):
+ """ Register OI callbacks """
+ # OI callbacks
+ self.callbacks = saImmOi.SaImmOiCallbacksT_2()
+
+ self.callbacks.saImmOiCcbAbortCallback = \
+ saImmOi.SaImmOiCcbAbortCallbackT(self._ccb_abort_callback)
+ self.callbacks.saImmOiCcbApplyCallback = \
+ saImmOi.SaImmOiCcbApplyCallbackT(self._ccb_apply_callback)
+ self.callbacks.saImmOiCcbCompletedCallback = \
+ saImmOi.SaImmOiCcbCompletedCallbackT(self._ccb_completed_callback)
+ self.callbacks.saImmOiCcbObjectCreateCallback = \
+ saImmOi.SaImmOiCcbObjectCreateCallbackT_2(
+ self._ccb_create_callback)
+ self.callbacks.saImmOiCcbObjectDeleteCallback = \
+ saImmOi.SaImmOiCcbObjectDeleteCallbackT(self._ccb_delete_callback)
+ self.callbacks.saImmOiCcbObjectModifyCallback = \
+ saImmOi.SaImmOiCcbObjectModifyCallbackT_2(
+ self._ccb_modify_callback)
+ self.callbacks.saImmOiRtAttrUpdateCallback = \
+ saImmOi.SaImmOiRtAttrUpdateCallbackT(self._attr_update_callback)
+ self.callbacks.saImmOiAdminOperationCallback = \
+ saImmOi.SaImmOiAdminOperationCallbackT_2(
+ self._admin_operation_callback)
+
+ @staticmethod
+ def _admin_operation_callback(oi_handle, c_invocation_id, c_name,
+ c_operation_id, c_params):
+ """ Callback for administrative operations
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ c_invocation_id (SaInvocationT): Invocation id
+ c_name (SaNameT): Pointer to object name
+ c_operation_id (SaImmAdminOperationIdT): Operation id
+ c_params (SaImmAdminOperationParamsT_2): Pointer to an array of
+ pointers to parameter descriptors
+ """
+ # Unmarshal parameters
+ invocation_id = c_invocation_id
+ name = \
+ saImm.unmarshalSaImmValue(c_name,
+ eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
+ operation_id = c_operation_id
+
+ params = []
+
+ for param in unmarshalNullArray(c_params):
+ param_name = param.paramName
+ param_type = param.paramType
+ param_buffer = param.paramBuffer
+
+ value = saImm.unmarshalSaImmValue(param_buffer, param_type)
+ parameter = AdminOperationParameter(param_name, param_type, value)
+ params.append(parameter)
+
+ # Invoke the operation
+ result = implementer_instance.admin_operation(operation_id, name,
+ params)
+
+ # Report the result
+ try:
+ immoi.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))
+
+ def _ccb_abort_callback(self, oi_handle, ccb_id):
+ """ Callback for aborted CCB
+ The aborted CCB will be removed from the cache.
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ ccb_id (SaImmOiCcbIdT): CCB id
+ """
+ del self.ccbs[ccb_id]
+
+ def _ccb_apply_callback(self, oi_handle, ccb_id):
+ """ Callback for apply of CCBs
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ ccb_id (SaImmOiCcbIdT): CCB id
+ """
+ all_instances = []
+
+ for class_name in implementer_instance.class_names:
+ dns = immoi.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)
+ all_instances.append(obj)
+
+ updated = self.completed_ccbs[ccb_id]['updated']
+ created = self.completed_ccbs[ccb_id]['added']
+ deleted = self.completed_ccbs[ccb_id]['removed']
+
+ # Remove the CCB from the caches
+ del self.ccbs[ccb_id]
+ del self.completed_ccbs[ccb_id]
+
+ # Tell the implementer to apply the changes
+ return implementer_instance.on_apply(all_instances, updated,
+ created, deleted)
+
+ @staticmethod
+ def _attr_update_callback(oi_handle, c_name, c_attr_names):
+ """ Callback for attribute update operation
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ c_name (SaNameT): Pointer to object name
+ c_attr_names (SaImmAttrNameT): Pointer to array of attribute names
+
+ Returns:
+ SaAisErrorT: Return code of the attribute update callback
+ """
+ # Unmarshal parameters
+ name = \
+ saImm.unmarshalSaImmValue(c_name,
+ eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
+ attr_names = unmarshalNullArray(c_attr_names)
+
+ # Get the class of the object
+ class_name = immoi.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)
+ if values is None:
+ return eSaAisErrorT.SA_AIS_ERR_UNAVAILABLE
+ if not isinstance(values, list):
+ values = [values]
+
+ attributes[attr_name] = values
+
+ # Report the updated values for the attributes
+ try:
+ immoi.update_runtime_object(name, attributes)
+ return eSaAisErrorT.SA_AIS_OK
+ except SafException:
+ return eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION
+
+ def _ccb_delete_callback(self, oi_handle, ccb_id, c_name):
+ """ Callback for object delete operation
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ ccb_id (SaImmOiCcbIdT): CCB id
+ c_name (SaNameT): Pointer to object name
+
+ Returns:
+ SaAisErrorT: Return code of the object delete callback
+ """
+ # Unmarshal the parameters
+ name = \
+ saImm.unmarshalSaImmValue(c_name,
+ eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
+
+ # Create a new CCB in the cache if needed
+ if ccb_id not in list(self.ccbs.keys()):
+ self.ccbs[ccb_id] = []
+
+ # Cache the operation
+ self.ccbs[ccb_id].append({'type': 'DELETE', 'dn': name})
+
+ # Tell the implementer about the operation
+ return implementer_instance.on_delete_added(name)
+
+ def _ccb_modify_callback(self, oi_handle, ccb_id, c_name,
+ c_attr_modification):
+ """ Callback for object modify operation
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ ccb_id (SaImmOiCcbIdT): CCB id
+ c_name (SaNameT): Pointer to object name
+ c_attr_modification (SaImmAttrModificationT_2): Pointer to an array
+ of pointers to descriptors of the modifications to perform
+
+ Returns:
+ SaAisErrorT: Return code of the object modify callback
+ """
+ # Unmarshal the parameters
+ name = \
+ saImm.unmarshalSaImmValue(c_name,
+ eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
+
+ attribute_modifications = []
+ implementer_objection = None
+
+ for attr in unmarshalNullArray(c_attr_modification):
+ attr_name = attr.modAttr.attrName
+ attr_type = attr.modAttr.attrValueType
+ mod_type = attr.modType
+ attr_values = immoi.unmarshal_len_array(
+ attr.modAttr.attrValues, attr.modAttr.attrValuesNumber,
+ attr.modAttr.attrValueType)
+ attribute_modifications.append({'attribute': attr_name,
+ 'type': attr_type,
+ 'modification': mod_type,
+ 'values': attr_values})
+
+ # Tell the implementer about the modification
+ result = implementer_instance.on_modify_added(attr_name, mod_type,
+ attr_values)
+ if result != eSaAisErrorT.SA_AIS_OK:
+ implementer_objection = result
+
+ # Create a new CCB in the cache if needed
+ if ccb_id not in list(self.ccbs.keys()):
+ self.ccbs[ccb_id] = []
+
+ # Store the modifications in the cache
+ self.ccbs[ccb_id].append({'type': 'MODIFY',
+ 'dn': name,
+ 'modification': attribute_modifications})
+
+ # Respond and say if this is accepted by the implementer
+ if implementer_objection:
+ return implementer_objection
+
+ return eSaAisErrorT.SA_AIS_OK
+
+ def _ccb_create_callback(self, oi_handle, ccb_id, class_name,
+ c_parent, c_attr_values):
+ """ Callback for object create operation
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ ccb_id (SaImmOiCcbIdT): CCB id
+ class_name (SaImmClassNameT): Class name
+ c_parent (SaNameT): Pointer to name of object's parent
+ c_attr_values (SaImmAttrValuesT_2): Pointer to an array of pointers
+ to attribute descriptors
+
+ Returns:
+ SaAisErrorT: Return code of the object create callback
+ """
+ # Unmarshal parameters
+ parent = saImm.unmarshalSaImmValue(
+ c_parent, eSaImmValueTypeT.SA_IMM_ATTR_SANAMET)
+ attributes = {}
+
+ for attr in unmarshalNullArray(c_attr_values):
+ attr_name = attr.attrName
+ attr_type = attr.attrValueType
+ nr_values = attr.attrValuesNumber
+
+ attr_values = immoi.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)
+
+ for attribute in description:
+ if attribute.attrName not in attributes:
+ attributes[attribute.attrName] = None
+
+ # Create a new CCB in the cache if needed
+ if ccb_id not in list(self.ccbs.keys()):
+ self.ccbs[ccb_id] = []
+
+ # Cache the create operation
+ self.ccbs[ccb_id].append({'type': 'CREATE',
+ 'parent': parent,
+ 'className': class_name,
+ 'attributes': attributes})
+
+ # Tell the implementer about the operation
+ obj = immoi.create_non_existing_imm_object(class_name, parent,
+ attributes)
+
+ return implementer_instance.on_create_added(class_name, parent, obj)
+
+ def _ccb_completed_callback(self, oi_handle, ccb_id):
+ """ Callback for completed CCB
+
+ Validate any configured containments and call the configured
+ on_validate function
+
+ Args:
+ oi_handle (SaImmOiHandleT): OI handle
+ ccb_id (SaImmOiCcbIdT): CCB id
+
+ Returns:
+ SaAisErrorT: Return code of the CCB-completed validation
+ """
+ # Get a summary of the changes in the CCB
+ summary = self._collect_full_transaction(ccb_id)
+ instances = summary['instances_after']
+ created = summary['created']
+ deleted = summary['deleted']
+ updated = summary['updated']
+
+ # Store added, removed, updated for apply
+ self.completed_ccbs[ccb_id] = {'added': created,
+ 'removed': deleted,
+ 'updated': updated}
+
+ # Perform validation on the full transaction
+ return implementer_instance.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
+ seen by the OI
+
+ Args:
+ ccb_id (str): CCB id
+
+ Returns:
+ {'instances_after' : instances,
+ 'created': created,
+ 'deleted': deleted,
+ 'updated': updated}
+ """
+ # Collect current state
+ all_objects_now = []
+
+ created = []
+ deleted = []
+ updated = []
+
+ # Go through current instances
+ for class_name in implementer_instance.class_names:
+ dns = immoi.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)
+ all_objects_now.append(obj)
+
+ # Collect proposed state by applying changes on current state
+ for operation in self.ccbs[ccb_id]:
+ operation_type = operation['type']
+
+ # Handle object create operation
+ if operation_type == 'CREATE':
+ parent = operation['parent']
+ class_name = operation['className']
+ attributes = operation['attributes']
+ rdn_attr = immoi.get_rdn_attribute_for_class(
+ class_name=class_name)
+ rdn_value = attributes[rdn_attr][0]
+
+ if parent:
+ dn = '%s,%s' % (rdn_value, parent)
+ else:
+ dn = rdn_value
+
+ instance = immoi.create_non_existing_imm_object(
+ class_name, parent, attributes)
+ created.append(instance)
+ deleted = [obj for obj in deleted if obj.dn != dn]
+
+ # Handle object delete operation
+ elif operation_type == 'DELETE':
+ dn = operation['dn']
+ deleted.append(ImmObject(class_name=class_name, dn=dn))
+ created = [obj for obj in created if obj.dn != dn]
+ updated = [obj for obj in updated if obj.dn != dn]
+
+ # Handle object modify operation
+ elif operation_type == 'MODIFY':
+ dn = operation['dn']
+ modifications = operation['modification']
+
+ for attr_modification in modifications:
+ mod_type = attr_modification['modification']
+ attribute = attr_modification['attribute']
+ values = attr_modification['values']
+
+ # Find affected object
+ affected_instance = None
+ affected_instances = [obj for obj in all_objects_now
+ if obj.dn == dn]
+
+ if not affected_instances:
+ print('ERROR: Failed to find object %s affected by '
+ 'modify operation' % dn)
+ else:
+ affected_instance = affected_instances[0]
+ if affected_instance not in updated:
+ updated.append(affected_instance)
+
+ if mod_type == \
+ eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_ADD:
+ curr_value = affected_instance.__getattr__(attribute)
+ curr_value.append(values)
+ affected_instance.__setattr__(attribute, curr_value)
+
+ elif mod_type == eSaImmAttrModificationTypeT.\
+ SA_IMM_ATTR_VALUES_DELETE:
+ for value in values:
+ curr_value = affected_instance.__getattr__(
+ attribute)
+ curr_value.remove(value)
+ affected_instance.__setattr__(
+ attribute, curr_value)
+
+ elif mod_type == eSaImmAttrModificationTypeT.\
+ SA_IMM_ATTR_VALUES_REPLACE:
+ affected_instance.__setattr__(attribute, values)
+
+ # Return the summary
+ instances_after = []
+
+ for modify_obj in itertools.chain(all_objects_now, created):
+ is_deleted = False
+ for obj in deleted:
+ if obj.dn == modify_obj.dn:
+ is_deleted = True
+
+ if not is_deleted:
+ instances_after.append(modify_obj)
+
+ out = {'instances_after': instances_after,
+ 'created': created,
+ 'deleted': deleted,
+ 'updated': updated}
+
+ return out
+
def get_implemented_classes(self):
""" Return a list of the classes this implementer implements
Returns:
list: List of class name
"""
- return self.class_names
+ return self.implemented_names
- def implement_class(self, class_name):
+ def set_class_implementer(self, class_name):
""" Add the given class_name to the list of classes this implementer
implements
Args:
class_name (str): Class name
"""
- immoi.implement_class(class_name)
- self.class_names.append(class_name)
+ c_class_name = SaImmClassNameT(class_name)
+ rc = saImmOi.saImmOiClassImplementerSet(self.handle, c_class_name)
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ self.implemented_names.append(class_name)
+ return rc
def set_constraints(self, constraints):
""" Set constraints to be verified by the OI """
@@ -891,43 +919,60 @@ class Implementer(object):
# Report that the operation is not supported
return eSaAisErrorT.SA_AIS_ERR_NOT_SUPPORTED
+ @bad_handle_retry
def _register(self):
""" Initialize IMM OI and register as an OI for the configured classes
+
+ Returns:
+ SaAisErrorT: Return code of Implementer register
"""
# Initialize the OI API
- immoi.initialize(callbacks)
+ rc = self.initialize(callbacks=self.callbacks)
# Ensure that all classes are configuration classes
- runtime_classes = [item for item in self.class_names
- if immoi.get_class_category(item) ==
- eSaImmClassCategoryT.SA_IMM_CLASS_RUNTIME]
+ # print("self.class_names")
+ # print(self.class_names)
+ 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) ==
+ eSaImmClassCategoryT.SA_IMM_CLASS_RUNTIME]
if runtime_classes:
raise Exception("ERROR: Can't be an applier for runtime "
"classes %s" % runtime_classes)
# Become an implementer
- immoi.register_implementer(self.name)
-
- # Get the selection objects
- immoi.get_selection_object()
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ rc = self._register_implementer(self.name)
available_classes = immoi.get_available_classes_in_imm()
- for class_name in self.class_names:
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ if self.class_names is not None:
+ for class_name in self.class_names:
+ if class_name in available_classes:
+ rc = self.set_class_implementer(class_name)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ break
+ else:
+ print("WARNING: %s is missing in IMM. Not becoming "
+ "implementer." % class_name)
+ return rc
+
+ def _register_implementer(self, oi_name):
+ """ Register as an implementer
- if class_name in available_classes:
- immoi.implement_class(class_name)
- else:
- print("WARNING: %s is missing in IMM. Not becoming "
- "implementer." % class_name)
+ Args:
+ oi_name (str): Implementer name
- @staticmethod
- def get_selection_object():
- """ Return the selection object """
- return immoi.selection_object.value
+ Returns:
+ SaAisErrorT: Return code of implementer set
+ """
+ implementer_name = SaImmOiImplementerNameT(oi_name)
+ rc = saImmOi.saImmOiImplementerSet(self.handle, implementer_name)
+ return rc
- @staticmethod
- def update_runtime_attributes(dn, attributes):
+ def update_runtime_attributes(self, dn, attributes):
""" Update the given runtime attributes for the specified dn
Args:
@@ -936,44 +981,47 @@ class Implementer(object):
"""
# Report the updates
try:
- immoi.update_rt_object(dn, attributes)
+ immoi.update_runtime_object(dn, attributes)
except SafException as err:
print("ERROR: Failed to update runtime attributes of %s: %s" %
(dn, err))
- @staticmethod
- def create(obj):
+ def create(self, obj):
""" Create the runtime object with provided information
Args:
obj (ImmObject): Object to create
+
+ Returns:
+ SaAisErrorT: Return code of implementer object create
"""
# Get the parent name for the object
parent_name = immoi.get_parent_name_for_dn(obj.dn)
class_name = obj.class_name
# Create the object
- immoi.create_rt_object(class_name, parent_name, obj)
+ return immoi.create_runtime_object(class_name, parent_name, obj)
- @staticmethod
- def delete(dn):
+ def delete(self, dn):
""" Delete a runtime object with the given dn
Args:
dn (str): Object dn
+
+ Returns:
+ SaAisErrorT: Return code of implementer object delete
"""
- immoi.delete_rt_object(dn)
+ return immoi.delete_runtime_object(dn)
- @staticmethod
- def _start_dispatch_loop():
+ def _start_dispatch_loop(self):
""" Start an infinite dispatch loop """
- read_fds = [immoi.selection_object.value]
+ read_fds = [self.selection_object.value]
# Handle updates
while read_fds:
read_evt, _, _ = select.select(read_fds, [], read_fds)
if read_evt:
- immoi.dispatch()
+ self.dispatch()
def _validate_constraints(self, all_instances, updated, created, deleted):
""" Validate configured constraints
@@ -1006,12 +1054,16 @@ class Applier(Implementer):
""" Empty validate handler as appliers cannot validate """
return eSaAisErrorT.SA_AIS_OK
+ @bad_handle_retry
def _register(self):
""" Initialize IMM-OI interface and register as an applier for the
configured classes
+
+ Returns:
+ SaAisErrorT: Return code of applier register
"""
# Initialize the OI API
- immoi.initialize(callbacks)
+ rc = self.initialize(callbacks=self.callbacks)
# Ensure that all classes are configuration classes
runtime_classes = [item for item in self.class_names
@@ -1021,17 +1073,29 @@ class Applier(Implementer):
raise Exception("ERROR: Can't be an applier for runtime classes
%s"
% runtime_classes)
# Become an applier
- immoi.register_applier(self.name)
-
- # Get the selection object
- immoi.get_selection_object()
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ rc = self._register_applier(self.name)
# Register as applier for each class
available_classes = immoi.get_available_classes_in_imm()
for class_name in self.class_names:
if class_name in available_classes:
- immoi.implement_class(class_name)
+ self.set_class_implementer(class_name)
else:
print("WARNING: %s is missing in IMM. Not becoming applier." %
class_name)
+ return rc
+
+ def _register_applier(self, app_name):
+ """ Register as an applier OI
+
+ Args:
+ app_name (str): Applier name
+
+ Returns:
+ SaAisErrorT: Return code of applier set
+ """
+ applier_name = "@" + app_name
+ rc = self._register_implementer(applier_name)
+ return rc
diff --git a/python/pyosaf/utils/immom/__init__.py
b/python/pyosaf/utils/immom/__init__.py
index 922ce7a..646e935 100644
--- a/python/pyosaf/utils/immom/__init__.py
+++ b/python/pyosaf/utils/immom/__init__.py
@@ -16,70 +16,69 @@
#
############################################################################
""" IMM OM common utilities """
-import os
-from ctypes import pointer, POINTER
-
-from pyosaf.saAis import saAis, SaVersionT, SaNameT, SaStringT, SaAisErrorT, \
- eSaAisErrorT, eSaBoolT, unmarshalNullArray
-from pyosaf import saImmOm, saImm
-from pyosaf.saImm import eSaImmScopeT, unmarshalSaImmValue, SaImmAttrNameT, \
- SaImmAttrValuesT_2
-from pyosaf.saImmOm import SaImmAccessorHandleT
-from pyosaf.utils import decorate, initialize_decorate
-from pyosaf.utils import SafException
-from pyosaf.utils.immom.object import ImmObject
+from pyosaf.saAis import SaAisErrorT, 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
-handle = saImmOm.SaImmHandleT()
-accessor_handle = SaImmAccessorHandleT()
# Decorate pure saImmOm* API's with error-handling retry and exception raising
-saImmOmInitialize = initialize_decorate(saImmOm.saImmOmInitialize)
-saImmOmSelectionObjectGet = decorate(saImmOm.saImmOmSelectionObjectGet)
-saImmOmDispatch = decorate(saImmOm.saImmOmDispatch)
-saImmOmFinalize = decorate(saImmOm.saImmOmFinalize)
-saImmOmClassCreate_2 = decorate(saImmOm.saImmOmClassCreate_2)
-saImmOmClassDescriptionGet_2 = decorate(saImmOm.saImmOmClassDescriptionGet_2)
+saImmOmInitialize = agent.saImmOmInitialize
+saImmOmSelectionObjectGet = agent.saImmOmSelectionObjectGet
+saImmOmDispatch = agent.saImmOmDispatch
+saImmOmFinalize = agent.saImmOmFinalize
+saImmOmClassCreate_2 = agent.saImmOmClassCreate_2
+saImmOmClassDescriptionGet_2 = agent.saImmOmClassDescriptionGet_2
saImmOmClassDescriptionMemoryFree_2 = \
- decorate(saImmOm.saImmOmClassDescriptionMemoryFree_2)
-saImmOmClassDelete = decorate(saImmOm.saImmOmClassDelete)
-saImmOmSearchInitialize_2 = decorate(saImmOm.saImmOmSearchInitialize_2)
-saImmOmSearchNext_2 = decorate(saImmOm.saImmOmSearchNext_2)
-saImmOmSearchFinalize = decorate(saImmOm.saImmOmSearchFinalize)
-saImmOmAccessorInitialize = decorate(saImmOm.saImmOmAccessorInitialize)
-saImmOmAccessorGet_2 = decorate(saImmOm.saImmOmAccessorGet_2)
-saImmOmAccessorFinalize = decorate(saImmOm.saImmOmAccessorFinalize)
-saImmOmAdminOwnerInitialize = decorate(saImmOm.saImmOmAdminOwnerInitialize)
-saImmOmAdminOwnerSet = decorate(saImmOm.saImmOmAdminOwnerSet)
-saImmOmAdminOwnerRelease = decorate(saImmOm.saImmOmAdminOwnerRelease)
-saImmOmAdminOwnerFinalize = decorate(saImmOm.saImmOmAdminOwnerFinalize)
-saImmOmAdminOwnerClear = decorate(saImmOm.saImmOmAdminOwnerClear)
-saImmOmCcbInitialize = decorate(saImmOm.saImmOmCcbInitialize)
-saImmOmCcbObjectCreate_2 = decorate(saImmOm.saImmOmCcbObjectCreate_2)
-saImmOmCcbObjectDelete = decorate(saImmOm.saImmOmCcbObjectDelete)
-saImmOmCcbObjectModify_2 = decorate(saImmOm.saImmOmCcbObjectModify_2)
-saImmOmCcbApply = decorate(saImmOm.saImmOmCcbApply)
-saImmOmCcbFinalize = decorate(saImmOm.saImmOmCcbFinalize)
-saImmOmCcbGetErrorStrings = decorate(saImmOm.saImmOmCcbGetErrorStrings)
-saImmOmAdminOperationInvoke_2 = decorate(saImmOm.saImmOmAdminOperationInvoke_2)
-saImmOmAdminOperationInvokeAsync_2 = \
- decorate(saImmOm.saImmOmAdminOperationInvokeAsync_2)
-saImmOmAdminOperationContinue = decorate(saImmOm.saImmOmAdminOperationContinue)
-saImmOmAdminOperationContinueAsync = \
- decorate(saImmOm.saImmOmAdminOperationContinueAsync)
+ agent.saImmOmClassDescriptionMemoryFree_2
+saImmOmClassDelete = agent.saImmOmClassDelete
+saImmOmSearchInitialize_2 = agent.saImmOmSearchInitialize_2
+saImmOmSearchNext_2 = agent.saImmOmSearchNext_2
+saImmOmSearchFinalize = agent.saImmOmSearchFinalize
+saImmOmAccessorInitialize = agent.saImmOmAccessorInitialize
+saImmOmAccessorGet_2 = agent.saImmOmAccessorGet_2
+saImmOmAccessorFinalize = agent.saImmOmAccessorFinalize
+saImmOmAdminOwnerInitialize = agent.saImmOmAdminOwnerInitialize
+saImmOmAdminOwnerSet = agent.saImmOmAdminOwnerSet
+saImmOmAdminOwnerRelease = agent.saImmOmAdminOwnerRelease
+saImmOmAdminOwnerFinalize = agent.saImmOmAdminOwnerFinalize
+saImmOmAdminOwnerClear = agent.saImmOmAdminOwnerClear
+saImmOmCcbInitialize = agent.saImmOmCcbInitialize
+saImmOmCcbObjectCreate_2 = agent.saImmOmCcbObjectCreate_2
+saImmOmCcbObjectDelete = agent.saImmOmCcbObjectDelete
+saImmOmCcbObjectModify_2 = agent.saImmOmCcbObjectModify_2
+saImmOmCcbApply = agent.saImmOmCcbApply
+saImmOmCcbFinalize = agent.saImmOmCcbFinalize
+saImmOmCcbGetErrorStrings = agent.saImmOmCcbGetErrorStrings
+saImmOmAdminOperationInvoke_2 = agent.saImmOmAdminOperationInvoke_2
+saImmOmAdminOperationInvokeAsync_2 = agent.saImmOmAdminOperationInvokeAsync_2
+saImmOmAdminOperationContinue = agent.saImmOmAdminOperationContinue
+saImmOmAdminOperationContinueAsync = agent.saImmOmAdminOperationContinueAsync
saImmOmAdminOperationContinuationClear = \
- decorate(saImmOm.saImmOmAdminOperationContinuationClear)
+ agent.saImmOmAdminOperationContinuationClear
+_om_agent = None
+
+@deprecate
def initialize():
- """ Initialize the IMM OM library """
- version = SaVersionT('A', 2, 15)
- # Initialize IMM OM handle
- saImmOmInitialize(handle, None, version)
- # Initialize Accessor Handle
- saImmOmAccessorInitialize(handle, accessor_handle)
+ """ Initialize the IMM OM library
+ Raises:
+ SafException: If the return code of the corresponding CLM API call(s)
+ is not SA_AIS_OK
+ """
+ global _om_agent
+ _om_agent = agent.ImmOmAgent()
+ # Initialize IMM OM handle and return the API return code
+ rc = _om_agent.init()
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
+
+@deprecate
def get(object_name, attr_name_list=None, class_name=None):
""" Obtain values of some attributes of the specified object
@@ -90,41 +89,22 @@ def get(object_name, attr_name_list=None, class_name=None):
Returns:
ImmObject: Imm object
+
+ Raises:
+ SafException: If the return code of the corresponding CLM API call(s)
+ is not SA_AIS_OK
"""
- # Always request the SaImmAttrClassName attribute if needed
- if attr_name_list and not class_name \
- and 'SaImmAttrClassName' not in attr_name_list \
- and not attr_name_list == ['SA_IMM_SEARCH_GET_CONFIG_ATTR']:
- attr_name_list.append('SaImmAttrClassName')
-
- attr_names = [SaImmAttrNameT(attr) for attr in attr_name_list] \
- if attr_name_list else None
-
- attributes = pointer(pointer(SaImmAttrValuesT_2()))
-
- try:
- saImmOmAccessorGet_2(accessor_handle, SaNameT(object_name),
- attr_names, attributes)
- except SafException as err:
- if err.value == eSaAisErrorT.SA_AIS_ERR_NOT_EXIST:
- return None
- else:
- raise err
-
- attrs = {}
- attr_list = unmarshalNullArray(attributes)
- for attr in attr_list:
- attr_range = list(range(attr.attrValuesNumber))
- attrs[attr.attrName] = [attr.attrValueType,
- [unmarshalSaImmValue(attr.attrValues[val],
- attr.attrValueType)
- for val in attr_range]]
- if 'SaImmAttrClassName' not in attrs and class_name:
- attrs['SaImmAttrClassName'] = class_name
-
- return ImmObject(object_name, attrs)
+ _accessor = ImmOmAccessor()
+ _accessor.init()
+ rc, imm_object = _accessor.get(object_name, attr_name_list, class_name)
+
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
+ return imm_object
+
+@deprecate
def class_description_get(class_name):
""" Get class description as a Python list
@@ -133,14 +113,26 @@ def class_description_get(class_name):
Returns:
list: List of class attributes
+
+ Raises:
+ SafException: If the return code of the corresponding CLM API call(s)
+ is not SA_AIS_OK
"""
- attr_defs = pointer(pointer(saImm.SaImmAttrDefinitionT_2()))
- category = saImm.SaImmClassCategoryT()
- saImmOmClassDescriptionGet_2(handle, class_name, category, attr_defs)
+ class_attrs = []
+ if not _om_agent:
+ # SA_AIS_ERR_INIT is returned if user calls this function without first
+ # calling initialize()
+ rc = eSaAisErrorT.SA_AIS_ERR_INIT
+ else:
+ rc, class_attrs = _om_agent.get_class_description(class_name)
+
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
- return unmarshalNullArray(attr_defs)
+ return class_attrs
+@deprecate
def admin_op_invoke(dn, op_id, params=None):
""" Invoke admin op for dn
@@ -148,61 +140,53 @@ def admin_op_invoke(dn, op_id, params=None):
dn (str): Object dn
op_id (str): Operation id
params (list): List of parameters
- """
- owner_handle = saImmOm.SaImmAdminOwnerHandleT()
- owner_name = saImmOm.SaImmAdminOwnerNameT(os.getlogin())
- saImmOmAdminOwnerInitialize(handle, owner_name, eSaBoolT.SA_TRUE,
- owner_handle)
- index = dn.rfind(",")
- parent_name = SaNameT(dn[index+1:])
- object_names = [parent_name]
- saImmOmAdminOwnerSet(owner_handle, object_names,
- eSaImmScopeT.SA_IMM_SUBTREE)
- if params is None:
- params = []
-
- object_dn = SaNameT(dn)
- retval = SaAisErrorT()
-
- saImmOmAdminOperationInvoke_2(owner_handle, object_dn, 0, op_id, params,
- retval, saAis.SA_TIME_ONE_SECOND * 10)
- if retval.value != eSaAisErrorT.SA_AIS_OK:
- print("saImmOmAdminOperationInvoke_2: %s" %
- eSaAisErrorT.whatis(retval.value))
- raise SafException(retval.value)
+ Raises:
+ SafException: If the return code of the corresponding CLM API call(s)
+ is not SA_AIS_OK
+ """
+ if not _om_agent:
+ # SA_AIS_ERR_INIT is returned if user calls this function without first
+ # calling initialize()
+ rc = eSaAisErrorT.SA_AIS_ERR_INIT
+ else:
+ rc = _om_agent.invoke_admin_operation(dn, op_id, params)
- saImmOmAdminOwnerFinalize(owner_handle)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
-def get_error_strings(ccb_handle):
- """ Return the current CCB error strings
+@deprecate
+def get_rdn_attribute_for_class(class_name):
+ """ Return the RDN attribute for the given class
+ This is safe to call from OI callbacks.
Args:
- ccb_handle (str): CCB handle
+ class_name (str): Class name
Returns:
- list: List of error strings
+ str: RDN attribute of the class
"""
- c_strings = POINTER(SaStringT)()
+ if not _om_agent:
+ # SA_AIS_ERR_INIT is returned if user calls this function without first
+ # calling initialize()
+ return None
- saImmOmCcbGetErrorStrings(ccb_handle, c_strings)
+ return _om_agent.get_rdn_attribute_for_class(class_name)
- return unmarshalNullArray(c_strings)
-
-def get_rdn_attribute_for_class(class_name):
- """ Return the RDN attribute for the given class
- This is safe to call from OI callbacks.
+def get_class_category(class_name):
+ """ Return the category of the given class
Args:
class_name (str): Class name
Returns:
- str: RDN attribute of the class
+ SaImmClassCategoryT: Class category
"""
- desc = 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
+ if not _om_agent:
+ # SA_AIS_ERR_INIT is returned if user calls this function without first
+ # calling initialize()
+ return ""
+
+ return _om_agent.get_class_category(class_name)
diff --git a/python/pyosaf/utils/immom/accessor.py
b/python/pyosaf/utils/immom/accessor.py
new file mode 100644
index 0000000..51bfd52
--- /dev/null
+++ b/python/pyosaf/utils/immom/accessor.py
@@ -0,0 +1,112 @@
+############################################################################
+#
+# (C) Copyright 2014 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 OM common utilities """
+from ctypes import pointer
+
+from pyosaf.saAis import SaNameT, eSaAisErrorT, unmarshalNullArray
+from pyosaf.saImm import unmarshalSaImmValue, SaImmAttrNameT, \
+ SaImmAttrValuesT_2
+from pyosaf.saImmOm import SaImmAccessorHandleT
+
+from pyosaf.utils import bad_handle_retry, log_err
+from pyosaf.utils.immom import agent
+from pyosaf.utils.immom.object import ImmObject
+
+
+class ImmOmAccessor(agent.ImmOmAgentManager):
+ """ ImmOmAccessor class """
+ def __init__(self, version=None):
+ """ Constructor for ImmOmAdminOwner class
+
+ Args:
+ version (SaVersionT): IMM OM version
+ """
+ super(ImmOmAccessor, self).__init__(version)
+ self.accessor_handle = None
+
+ def __exit__(self, exception_type, exception_value, traceback):
+ """ Destructor for ImmOmAccessor class
+
+ Finalize the Accessor handle and the IMM OM handle
+ """
+ if self.accessor_handle:
+ agent.saImmOmAccessorFinalize(self.accessor_handle)
+ if self.handle:
+ agent.saImmOmFinalize(self.handle)
+
+ @bad_handle_retry
+ def init(self):
+ """ Initialize Accessor """
+ self.finalize()
+ rc = self.initialize()
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ self.accessor_handle = SaImmAccessorHandleT()
+ # Initialize Accessor Handle
+ rc = agent.saImmOmAccessorInitialize(self.handle,
+ self.accessor_handle)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmAccessorInitialize FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+ return rc
+
+ @bad_handle_retry
+ def get(self, object_name, attr_name_list=None, class_name=None):
+ """ Obtain values of some attributes of the specified object
+
+ Args:
+ object_name (str): Object name
+ attr_name_list (list): List of attributes
+ class_name (str): Class name
+
+ Returns:
+ ImmObject: Imm object
+ """
+ imm_obj = None
+ # Always request the SaImmAttrClassName attribute if needed
+ if attr_name_list and not class_name \
+ and 'SaImmAttrClassName' not in attr_name_list \
+ and not attr_name_list == \
+ ['SA_IMM_SEARCH_GET_CONFIG_ATTR']:
+ attr_name_list.append('SaImmAttrClassName')
+
+ attr_names = [SaImmAttrNameT(attr) for attr in attr_name_list] \
+ if attr_name_list else None
+
+ attributes = pointer(pointer(SaImmAttrValuesT_2()))
+
+ 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:
+ attrs = {}
+ attr_list = unmarshalNullArray(attributes)
+ for attr in attr_list:
+ attr_range = list(range(attr.attrValuesNumber))
+ attrs[attr.attrName] = [attr.attrValueType,
+ [unmarshalSaImmValue(
+ attr.attrValues[val],
+ attr.attrValueType)
+ for val in attr_range]]
+ if 'SaImmAttrClassName' not in attrs and class_name:
+ attrs['SaImmAttrClassName'] = class_name
+ imm_obj = ImmObject(object_name, attrs)
+
+ return rc, imm_obj
diff --git a/python/pyosaf/utils/immom/agent.py
b/python/pyosaf/utils/immom/agent.py
new file mode 100644
index 0000000..6422f01
--- /dev/null
+++ b/python/pyosaf/utils/immom/agent.py
@@ -0,0 +1,404 @@
+############################################################################
+#
+# (C) Copyright 2014 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 OM common utilities """
+import uuid
+from copy import deepcopy
+from ctypes import pointer
+
+from pyosaf import saImmOm, saImm
+from pyosaf.saAis import saAis, SaVersionT, SaNameT, SaAisErrorT, \
+ eSaAisErrorT, eSaBoolT, unmarshalNullArray
+from pyosaf.saImm import eSaImmScopeT
+from pyosaf.utils import decorate, initialize_decorate, log_err
+
+# Decorate pure saImmOm* API's with error-handling retry and exception raising
+saImmOmInitialize = initialize_decorate(saImmOm.saImmOmInitialize)
+saImmOmSelectionObjectGet = decorate(saImmOm.saImmOmSelectionObjectGet)
+saImmOmDispatch = decorate(saImmOm.saImmOmDispatch)
+saImmOmFinalize = decorate(saImmOm.saImmOmFinalize)
+saImmOmClassCreate_2 = decorate(saImmOm.saImmOmClassCreate_2)
+saImmOmClassDescriptionGet_2 = decorate(saImmOm.saImmOmClassDescriptionGet_2)
+saImmOmClassDescriptionMemoryFree_2 = \
+ decorate(saImmOm.saImmOmClassDescriptionMemoryFree_2)
+saImmOmClassDelete = decorate(saImmOm.saImmOmClassDelete)
+saImmOmSearchInitialize_2 = decorate(saImmOm.saImmOmSearchInitialize_2)
+saImmOmSearchNext_2 = decorate(saImmOm.saImmOmSearchNext_2)
+saImmOmSearchFinalize = decorate(saImmOm.saImmOmSearchFinalize)
+saImmOmAccessorInitialize = decorate(saImmOm.saImmOmAccessorInitialize)
+saImmOmAccessorGet_2 = decorate(saImmOm.saImmOmAccessorGet_2)
+saImmOmAccessorFinalize = decorate(saImmOm.saImmOmAccessorFinalize)
+saImmOmAdminOwnerInitialize = decorate(saImmOm.saImmOmAdminOwnerInitialize)
+saImmOmAdminOwnerSet = decorate(saImmOm.saImmOmAdminOwnerSet)
+saImmOmAdminOwnerRelease = decorate(saImmOm.saImmOmAdminOwnerRelease)
+saImmOmAdminOwnerFinalize = decorate(saImmOm.saImmOmAdminOwnerFinalize)
+saImmOmAdminOwnerClear = decorate(saImmOm.saImmOmAdminOwnerClear)
+saImmOmCcbInitialize = decorate(saImmOm.saImmOmCcbInitialize)
+saImmOmCcbObjectCreate_2 = decorate(saImmOm.saImmOmCcbObjectCreate_2)
+saImmOmCcbObjectDelete = decorate(saImmOm.saImmOmCcbObjectDelete)
+saImmOmCcbObjectModify_2 = decorate(saImmOm.saImmOmCcbObjectModify_2)
+saImmOmCcbApply = decorate(saImmOm.saImmOmCcbApply)
+saImmOmCcbFinalize = decorate(saImmOm.saImmOmCcbFinalize)
+saImmOmCcbGetErrorStrings = decorate(saImmOm.saImmOmCcbGetErrorStrings)
+saImmOmAdminOperationInvoke_2 = decorate(saImmOm.saImmOmAdminOperationInvoke_2)
+saImmOmAdminOperationInvokeAsync_2 = \
+ decorate(saImmOm.saImmOmAdminOperationInvokeAsync_2)
+saImmOmAdminOperationContinue = decorate(saImmOm.saImmOmAdminOperationContinue)
+saImmOmAdminOperationContinueAsync = \
+ decorate(saImmOm.saImmOmAdminOperationContinueAsync)
+saImmOmAdminOperationContinuationClear = \
+ decorate(saImmOm.saImmOmAdminOperationContinuationClear)
+
+
+class ImmOmAgentManager(object):
+ """ This class manages the life cycle of an IMM OM agent
+ """
+ def __init__(self, version=None):
+ """ Constructor for ImmOmAgentManager class
+
+ Args:
+ version (SaVersionT): IMM OM API version
+ """
+ self.init_version = version if version else SaVersionT('A', 2, 15)
+ self.version = None
+ self.handle = None
+ self.callbacks = None
+ self.selection_object = None
+
+ def __exit__(self, exception_type, exception_value, traceback):
+ """ Destructor for ImmOmAgent class
+
+ Finalize the IMM OM agent handle
+ """
+ if self.handle:
+ saImmOmFinalize(self.handle)
+
+ def __del__(self):
+ """ Destructor for ImmOmAgent class
+
+ Finalize the IMM OM agent handle
+ """
+ if self.handle:
+ saImmOmFinalize(self.handle)
+
+ def initialize(self):
+ """ Initialize the IMM OM library
+
+ Returns:
+ SaAisErrorT: Return code of OM initialize
+ """
+ self.handle = saImmOm.SaImmHandleT()
+ self.version = deepcopy(self.init_version)
+ rc = saImmOmInitialize(self.handle, None, self.version)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmInitialize FAILED - %s" % eSaAisErrorT.whatis(rc))
+ return rc
+
+ def get_handle(self):
+ """ Return the IMM OM agent handle successfully initialized
+
+ Returns:
+ SaImmHandleT: IMM OM agent handle
+ """
+ return self.handle
+
+ def dispatch(self, flags):
+ """ Invoke IMM callbacks for queued events
+
+ Args:
+ flags (eSaDispatchFlagsT): Flags specifying dispatch mode
+
+ Returns:
+ SaAisErrorT: Return code of the saImmOmDispatch() API call
+ """
+ rc = saImmOmDispatch(self.handle, flags)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmDispatch FAILED - %s" % eSaAisErrorT.whatis(rc))
+
+ return rc
+
+ def finalize(self):
+ """ Finalize the IMM OM agent handle
+
+ Returns:
+ SaAisErrorT: Return code of the saImmOmFinalize() API call
+ """
+ rc = eSaAisErrorT.SA_AIS_OK
+ if self.handle:
+ rc = saImmOmFinalize(self.handle)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmFinalize 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
+
+
+class ImmOmAgent(ImmOmAgentManager):
+ """ 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 """
+
+ def init(self):
+ """ Initialize the IMM OM agent
+
+ Returns:
+ SaAisErrorT: Return code of the corresponding CLM API call(s)
+ """
+ # Clean previous resource if any
+ self.finalize()
+ return self.initialize()
+
+ def clear_admin_owner(self, obj_name, scope=eSaImmScopeT.SA_IMM_SUBTREE):
+ """ Clear the administrative 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 API call(s)
+ """
+ if not obj_name:
+ rc = eSaAisErrorT.SA_AIS_ERR_NOT_EXIST
+ else:
+ obj_name = SaNameT(obj_name)
+ obj_name = [obj_name]
+
+ rc = saImmOmAdminOwnerClear(self.handle, obj_name, scope)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmAdminOwnerClear FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+
+ return rc
+
+ def get_class_description(self, class_name):
+ """ Get class description as a Python list
+
+ Args:
+ class_name (str): Class name
+
+ Returns:
+ SaAisErrorT: Return code of the corresponding API call(s)
+ list: List of class attributes
+ """
+ # Perform a deep copy
+ def attr_def_copy(attr_def):
+ """ Deep copy attributes """
+ attr_def_cpy = saImm.SaImmAttrDefinitionT_2()
+ attr_def_cpy.attrName = attr_def.attrName[:]
+ attr_def_cpy.attrValueType = attr_def.attrValueType
+ attr_def_cpy.attrFlags = attr_def.attrFlags
+
+ return attr_def_cpy
+
+ class_attrs = []
+ attr_defs = pointer(pointer(saImm.SaImmAttrDefinitionT_2()))
+ category = saImm.SaImmClassCategoryT()
+ rc = saImmOmClassDescriptionGet_2(self.handle, class_name, category,
+ attr_defs)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmClassDescriptionGet_2 FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+ else:
+ _class_attrs = unmarshalNullArray(attr_defs)
+
+ # Make copy of attr_defs list
+ class_attrs = [attr_def_copy(item) for item in _class_attrs]
+
+ # Free the original memory
+ saImmOmClassDescriptionMemoryFree_2(self.handle,
attr_defs.contents)
+
+ return rc, class_attrs
+
+ def get_rdn_attribute_for_class(self, class_name):
+ """ Return the RDN attribute for the given class
+ This is safe to call from OI callbacks.
+
+ Args:
+ class_name (str): Class name
+
+ Returns:
+ str: RDN attribute of the class
+ """
+ rc, class_attrs = self.get_class_description(class_name)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ return ""
+ else:
+ for attr_desc in class_attrs:
+ if attr_desc.attrFlags & saImm.saImm.SA_IMM_ATTR_RDN:
+ return attr_desc.attrName
+
+ def invoke_admin_operation(self, dn, op_id, params=None):
+ """ Invoke admin op for dn
+
+ Args:
+ dn (str): Object dn
+ op_id (str): Operation id
+ params (list): List of parameters
+
+ Returns:
+ SaAisErrorT: Return code of admin operation invoke
+ """
+ _owner = ImmOmAdminOwner(self.handle)
+ rc = _owner.initialize()
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ index = dn.rfind(",")
+ object_rdn = dn[index+1:]
+ rc = _owner.set_owner(object_rdn)
+
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ owner_handle = _owner.get_handle()
+ if params is None:
+ params = []
+
+ object_dn = SaNameT(dn)
+ operation_rc = SaAisErrorT()
+
+ rc = saImmOmAdminOperationInvoke_2(owner_handle, object_dn, 0,
+ op_id, params, operation_rc,
+ saAis.SA_TIME_ONE_SECOND * 10)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmAdminOperationInvoke_2 FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+ elif operation_rc.value != eSaAisErrorT.SA_AIS_OK:
+ log_err("Administrative operation(%s) on %s FAILED - %s" %
+ (op_id, object_dn, eSaAisErrorT.whatis(operation_rc)))
+
+ return rc
+
+ def get_class_category(self, class_name):
+ """ Return the category of the given class
+
+ Args:
+ class_name (str): Class name
+
+ Returns:
+ SaImmClassCategoryT: Class category
+ """
+ c_attr_defs = pointer(pointer(saImmOm.SaImmAttrDefinitionT_2()))
+ c_category = saImmOm.SaImmClassCategoryT()
+ c_class_name = saImmOm.SaImmClassNameT(class_name)
+
+ rc = saImmOmClassDescriptionGet_2(self.handle, c_class_name,
+ c_category, c_attr_defs)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmClassDescriptionGet_2 FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+ return ""
+ return c_category.value
+
+
+class ImmOmAdminOwner(object):
+ """ ImmOmAdminOwner class """
+ def __init__(self, imm_handle, owner_name=""):
+ """ Constructor for ImmOmAdminOwner class
+
+ Args:
+ imm_handle (SaImmHandleT): IMM OM agent handle
+ owner_name (str): Name of the administrative owner
+ """
+ self.imm_handle = imm_handle
+ if owner_name:
+ self.owner_name = owner_name
+ else:
+ self.owner_name = "pyosaf_" + str(uuid.uuid4())
+
+ self.owner_name = saImmOm.SaImmAdminOwnerNameT(self.owner_name)
+ self.owner_handle = None
+
+ def __exit__(self, exception_type, exception_value, traceback):
+ """ Destructor for ImmOmAdminOwner class
+
+ Finalize the administrative owner handle
+ """
+ if self.owner_handle:
+ saImmOm.saImmOmAdminOwnerFinalize(self.owner_handle)
+
+ def __del__(self):
+ if self.owner_handle:
+ saImmOm.saImmOmAdminOwnerFinalize(self.owner_handle)
+
+ def initialize(self):
+ """ Initialize the administrative owner.
+
+ Return:
+ SaAisErrorT: Return code of admin operation invoke
+ """
+ self.owner_handle = saImmOm.SaImmAdminOwnerHandleT()
+ rc = saImmOmAdminOwnerInitialize(self.imm_handle, self.owner_name,
+ eSaBoolT.SA_TRUE, self.owner_handle)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmAdminOwnerInitialize FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+ return rc
+
+ def get_handle(self):
+ """ Return the administrative owner handle successfully initialized """
+ return self.owner_handle
+
+ def set_owner(self, obj_name, scope=eSaImmScopeT.SA_IMM_SUBTREE):
+ """ Set the administrative owner to the set of objects identified by
+ the scope and the obj_name parameters.
+
+ Args:
+ obj_name (str): Object name
+ scope (SaImmScopeT): Scope of the admin owner set operation
+
+ Return:
+ SaAisErrorT: Return code of admin operation invoke
+ """
+ if not obj_name:
+ rc = eSaAisErrorT.SA_AIS_ERR_NOT_EXIST
+ else:
+ obj_name = SaNameT(obj_name)
+ obj_name = [obj_name]
+
+ rc = saImmOmAdminOwnerSet(self.owner_handle, obj_name, scope)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmAdminOwnerSet FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+
+ return rc
+
+ def release_owner(self, obj_name, scope=eSaImmScopeT.SA_IMM_SUBTREE):
+ """ Release the administrative owner of the set of objects
+ identified by the scope and obj_name parameters
+
+ Args:
+ obj_name (str): Object name
+ scope (SaImmScopeT): Scope of the admin owner release operation
+
+ Return:
+ SaAisErrorT: Return code of admin operation invoke
+ """
+ if not obj_name:
+ rc = eSaAisErrorT.SA_AIS_ERR_NOT_EXIST
+ else:
+ obj_name = SaNameT(obj_name)
+ obj_name = [obj_name]
+
+ rc = saImmOmAdminOwnerRelease(self.owner_handle, obj_name, scope)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmAdminOwnerRelease FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+
+ return rc
diff --git a/python/pyosaf/utils/immom/ccb.py b/python/pyosaf/utils/immom/ccb.py
index e5e8de5..6b8373d 100644
--- a/python/pyosaf/utils/immom/ccb.py
+++ b/python/pyosaf/utils/immom/ccb.py
@@ -17,16 +17,17 @@
############################################################################
""" Class representing an IMM CCB """
from __future__ import print_function
-import sys
-from ctypes import c_void_p, pointer, cast
+from ctypes import c_void_p, pointer, cast, POINTER
-from pyosaf.saAis import eSaAisErrorT, eSaBoolT, SaNameT, SaStringT, \
- SaDoubleT, SaTimeT, SaUint64T, SaInt64T, SaUint32T, SaInt32T, SaFloatT
+from pyosaf.saAis import eSaAisErrorT, SaNameT, SaStringT, SaFloatT, \
+ unmarshalNullArray, SaDoubleT, SaTimeT, SaUint64T, SaInt64T, SaUint32T, \
+ SaInt32T, SaVersionT
from pyosaf.saImm import eSaImmScopeT, eSaImmValueTypeT, SaImmAttrValuesT_2
from pyosaf import saImm
from pyosaf import saImmOm
-from pyosaf.utils import immom
-from pyosaf.utils import SafException
+from pyosaf.utils.immom import agent
+from pyosaf.utils.immom.accessor import ImmOmAccessor
+from pyosaf.utils import log_err, bad_handle_retry
def _value_to_ctype_ptr(value_type, value):
@@ -39,8 +40,6 @@ def _value_to_ctype_ptr(value_type, value):
Returns:
c_void_p: ctype pointer which points to value
"""
- if sys.version_info > (3,):
- long = int
if value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAINT32T:
ctypeptr = cast(pointer(SaInt32T(value)), c_void_p)
elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAUINT32T:
@@ -86,21 +85,15 @@ def marshal_c_array(value_type, value_list):
class Ccb(object):
""" Class representing an ongoing CCB """
- def __init__(self, flags=saImm.saImm.SA_IMM_CCB_REGISTERED_OI):
- self.owner_handle = saImmOm.SaImmAdminOwnerHandleT()
- owner_name = saImmOm.SaImmAdminOwnerNameT("DummyName")
-
- immom.saImmOmAdminOwnerInitialize(immom.handle, owner_name,
- eSaBoolT.SA_TRUE, self.owner_handle)
- self.ccb_handle = saImmOm.SaImmCcbHandleT()
-
- if flags:
- ccb_flags = saImmOm.SaImmCcbFlagsT(flags)
- else:
- ccb_flags = saImmOm.SaImmCcbFlagsT(0)
-
- immom.saImmOmCcbInitialize(self.owner_handle, ccb_flags,
- self.ccb_handle)
+ 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
+ self.admin_owner = None
+ self.accessor = None
+ self.ccb_handle = None
+ self.ccb_flags = saImmOm.SaImmCcbFlagsT(flags) if flags else \
+ saImmOm.SaImmCcbFlagsT(0)
def __enter__(self):
""" Called when Ccb is used in a 'with' statement as follows:
@@ -123,54 +116,226 @@ class Ccb(object):
self.__del__()
def __del__(self):
- """ Finalize the CCB """
- immom.saImmOmAdminOwnerFinalize(self.owner_handle)
+ """ Destructor for CBB class
+
+ Finalize the the CCB
+ """
+ if self.ccb_handle:
+ agent.saImmOmCcbFinalize(self.ccb_handle)
+ 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 administrative 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 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 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
+
+ @bad_handle_retry
+ def init(self, owner_name=""):
+ """ Initialize the IMM OM, administrative owner, and CCB handles
+
+ Args:
+ owner_name (str): Name of the administrative owner
+
+ Return:
+ SaAisErrorT: Return code of the APIs
+ """
+ # Clean previous resources if any
+ self.finalize()
+ self.imm_om = agent.ImmOmAgent(self.init_version)
+ rc = self.imm_om.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()
+ 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)
+ 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
Args:
obj (ImmObject): Imm object
parent_name (str): Parent name
+
+ Return:
+ SaAisErrorT: Return code of the APIs
"""
+ rc = eSaAisErrorT.SA_AIS_OK
if parent_name is not None:
+ rc = self.admin_owner.set_owner(parent_name)
parent_name = SaNameT(parent_name)
- object_names = [parent_name]
- immom.saImmOmAdminOwnerSet(self.owner_handle, object_names,
- eSaImmScopeT.SA_IMM_SUBTREE)
- else:
- parent_name = None
-
- attr_values = []
- for attr_name, type_values in obj.attrs.items():
- values = type_values[1]
- attr = SaImmAttrValuesT_2()
- attr.attrName = attr_name
- attr.attrValueType = type_values[0]
- attr.attrValuesNumber = len(values)
- attr.attrValues = marshal_c_array(attr.attrValueType, values)
- attr_values.append(attr)
-
- immom.saImmOmCcbObjectCreate_2(self.ccb_handle,
- obj.class_name,
- parent_name,
- attr_values)
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ attr_values = []
+ for attr_name, type_values in obj.attrs.items():
+ values = type_values[1]
+ attr = SaImmAttrValuesT_2()
+ attr.attrName = attr_name
+ attr.attrValueType = type_values[0]
+
+ attr.attrValuesNumber = len(values)
+ attr.attrValues = marshal_c_array(attr.attrValueType, values)
+ attr_values.append(attr)
+
+ rc = agent.saImmOmCcbObjectCreate_2(self.ccb_handle,
+ obj.class_name,
+ parent_name,
+ attr_values)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmCcbObjectCreate_2 FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+
+ 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:
+ rc = init_rc
+
+ return rc
+
+ @bad_handle_retry
def delete(self, object_name):
""" Add a delete operation of the object with the given DN to the CCB
Args:
object_name (str): Object name
+
+ Return:
+ SaAisErrorT: Return code of the APIs
"""
if object_name is None:
- raise SafException(eSaAisErrorT.SA_AIS_ERR_NOT_EXIST)
+ return eSaAisErrorT.SA_AIS_ERR_NOT_EXIST
+
+ rc = self.admin_owner.set_owner(object_name)
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ obj_name = SaNameT(object_name)
+ rc = agent.saImmOmCcbObjectDelete(self.ccb_handle, obj_name)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmCcbObjectDelete FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+
+ 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:
+ rc = init_rc
+
+ return rc
+
+ @bad_handle_retry
+ def _modify(self, object_name, attr_name, values, mod_type):
+ """ Modify an existing object
- object_name = SaNameT(object_name)
- object_names = [object_name]
-
- immom.saImmOmAdminOwnerSet(self.owner_handle, object_names,
- eSaImmScopeT.SA_IMM_SUBTREE)
- immom.saImmOmCcbObjectDelete(self.ccb_handle, object_name)
+ Args:
+ object_name (str): Object name
+ attr_name (str): Attribute name
+ values (list): List of attribute values
+ mod_type (eSaImmAttrModificationTypeT): Modification type
+ Return:
+ SaAisErrorT: Return code of the APIs
+ """
+ if object_name is None:
+ rc = eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM
+ else:
+ if not self.accessor:
+ self.accessor = ImmOmAccessor(self.init_version)
+ self.accessor.init()
+
+ # Get the attribute value type by reading the object's class
+ # description
+ 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)
+ value_type = None
+ for attr_def in attr_def_list:
+ if attr_def.attrName == attr_name:
+ value_type = attr_def.attrValueType
+ break
+ if value_type:
+ rc = self.admin_owner.set_owner(object_name,
+ eSaImmScopeT.SA_IMM_ONE)
+
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ # Make sure the values field is a list
+ if not isinstance(values, list):
+ values = [values]
+
+ attr_mods = []
+ attr_mod = saImmOm.SaImmAttrModificationT_2()
+ attr_mod.modType = mod_type
+ attr_mod.modAttr = SaImmAttrValuesT_2()
+ attr_mod.modAttr.attrName = attr_name
+ attr_mod.modAttr.attrValueType = value_type
+ attr_mod.modAttr.attrValuesNumber = len(values)
+ attr_mod.modAttr.attrValues = marshal_c_array(value_type,
+ values)
+ attr_mods.append(attr_mod)
+ object_name = SaNameT(object_name)
+ rc = agent.saImmOmCcbObjectModify_2(self.ccb_handle,
+ object_name, attr_mods)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmCcbObjectModify_2 FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+
+ 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:
+ rc = init_rc
+
+ return rc
def modify_value_add(self, object_name, attr_name, values):
""" Add to the CCB an ADD modification of an existing object
@@ -179,51 +344,13 @@ class Ccb(object):
object_name (str): Object name
attr_name (str): Attribute name
values (list): List of attribute values
+
+ Return:
+ SaAisErrorT: Return code of the APIs
"""
- assert object_name
-
- # Make sure the values field is a list
- if not isinstance(values, list):
- values = [values]
-
- # First try to get the attribute value type by reading
- # the object's class description
- try:
- obj = immom.get(object_name)
- except SafException as err:
- print("failed: %s" % err)
- return
-
- object_name = SaNameT(object_name)
- object_names = [object_name]
- class_name = obj.SaImmAttrClassName
- value_type = None
- attr_def_list = immom.class_description_get(class_name)
- for attr_def in attr_def_list:
- if attr_def.attrName == attr_name:
- value_type = attr_def.attrValueType
- break
-
- if value_type is None:
- raise SafException(eSaAisErrorT.SA_AIS_ERR_NOT_EXIST,
- "attribute '%s' does not exist" % attr_name)
-
- immom.saImmOmAdminOwnerSet(self.owner_handle, object_names,
- eSaImmScopeT.SA_IMM_ONE)
- attr_mods = []
-
- attr_mod = saImmOm.SaImmAttrModificationT_2()
- attr_mod.modType = \
+ mod_type = \
saImm.eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_ADD
- attr_mod.modAttr = SaImmAttrValuesT_2()
- attr_mod.modAttr.attrName = attr_name
- attr_mod.modAttr.attrValueType = value_type
- attr_mod.modAttr.attrValuesNumber = len(values)
- attr_mod.modAttr.attrValues = marshal_c_array(value_type, values)
-
- attr_mods.append(attr_mod)
-
- immom.saImmOmCcbObjectModify_2(self.ccb_handle, object_name, attr_mods)
+ return self._modify(object_name, attr_name, values, mod_type)
def modify_value_replace(self, object_name, attr_name, values):
""" Add to the CCB an REPLACE modification of an existing object
@@ -232,51 +359,13 @@ class Ccb(object):
object_name (str): Object name
attr_name (str): Attribute name
values (list): List of attribute values
+
+ Return:
+ SaAisErrorT: Return code of the APIs
"""
- assert object_name
-
- # Make sure the values field is a list
- if not isinstance(values, list):
- values = [values]
-
- # First try to get the attribute value type by reading
- # the object's class description
- try:
- obj = immom.get(object_name)
- except SafException as err:
- print("failed: %s" % err)
- return
-
- object_name = SaNameT(object_name)
- object_names = [object_name]
- class_name = obj.SaImmAttrClassName
- value_type = None
- attr_def_list = immom.class_description_get(class_name)
- for attr_def in attr_def_list:
- if attr_def.attrName == attr_name:
- value_type = attr_def.attrValueType
- break
-
- if value_type is None:
- raise SafException(eSaAisErrorT.SA_AIS_ERR_NOT_EXIST,
- "attribute '%s' does not exist" % attr_name)
-
- immom.saImmOmAdminOwnerSet(self.owner_handle, object_names,
- eSaImmScopeT.SA_IMM_ONE)
- attr_mods = []
-
- attr_mod = saImmOm.SaImmAttrModificationT_2()
- attr_mod.modType = \
+ mod_type = \
saImm.eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_REPLACE
- attr_mod.modAttr = SaImmAttrValuesT_2()
- attr_mod.modAttr.attrName = attr_name
- attr_mod.modAttr.attrValueType = value_type
- attr_mod.modAttr.attrValuesNumber = len(values)
- attr_mod.modAttr.attrValues = marshal_c_array(value_type, values)
-
- attr_mods.append(attr_mod)
-
- immom.saImmOmCcbObjectModify_2(self.ccb_handle, object_name, attr_mods)
+ return self._modify(object_name, attr_name, values, mod_type)
def modify_value_delete(self, object_name, attr_name, values):
""" Add to the CCB an DELETE modification of an existing object
@@ -285,66 +374,44 @@ class Ccb(object):
object_name (str): Object name
attr_name (str): Attribute name
values (list): List of attribute values
+
+ Return:
+ SaAisErrorT: Return code of the APIs
"""
- assert object_name
-
- # Make sure the values field is a list
- if not isinstance(values, list):
- values = [values]
-
- # First try to get the attribute value type by reading
- # the object's class description
- try:
- obj = immom.get(object_name)
- except SafException as err:
- print("failed: %s" % err)
- return
-
- object_name = SaNameT(object_name)
- object_names = [object_name]
- class_name = obj.SaImmAttrClassName
- value_type = None
- attr_def_list = immom.class_description_get(class_name)
- for attr_def in attr_def_list:
- if attr_def.attrName == attr_name:
- value_type = attr_def.attrValueType
- break
-
- if value_type is None:
- raise SafException(eSaAisErrorT.SA_AIS_ERR_NOT_EXIST,
- "attribute '%s' does not exist" % attr_name)
-
- immom.saImmOmAdminOwnerSet(self.owner_handle, object_names,
- eSaImmScopeT.SA_IMM_ONE)
- attr_mods = []
-
- attr_mod = saImmOm.SaImmAttrModificationT_2()
- attr_mod.modType = \
+ mod_type = \
saImm.eSaImmAttrModificationTypeT.SA_IMM_ATTR_VALUES_DELETE
- attr_mod.modAttr = SaImmAttrValuesT_2()
- attr_mod.modAttr.attrName = attr_name
- attr_mod.modAttr.attrValueType = value_type
- attr_mod.modAttr.attrValuesNumber = len(values)
- attr_mod.modAttr.attrValues = marshal_c_array(value_type, values)
-
- attr_mods.append(attr_mod)
-
- immom.saImmOmCcbObjectModify_2(self.ccb_handle, object_name, attr_mods)
+ return self._modify(object_name, attr_name, values, mod_type)
def apply(self):
- """ Apply the CCB """
- immom.saImmOmCcbApply(self.ccb_handle)
-
+ """ Apply the CCB
-def test():
- """ A simple function to test the usage of Ccb class """
- ccb = Ccb()
- ccb.modify_value_replace("safAmfCluster=myAmfCluster",
- "saAmfClusterStartupTimeout",
- [10000000000])
- ccb.apply()
- del ccb
+ Return:
+ SaAisErrorT: Return code of the APIs
+ """
+ rc = agent.saImmOmCcbApply(self.ccb_handle)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmCcbApply FAILED - %s" % eSaAisErrorT.whatis(rc))
+
+ 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:
+ rc = init_rc
+
+ return rc
+
+ def get_error_strings(self):
+ """ Return the current CCB error strings
+
+ Returns:
+ SaAisErrorT: Return code of the APIs
+ list: List of error strings
+ """
+ c_strings = POINTER(SaStringT)()
+ rc = agent.saImmOmCcbGetErrorStrings(self.ccb_handle, c_strings)
-if __name__ == '__main__':
- test()
+ return rc, unmarshalNullArray(c_strings)
diff --git a/python/pyosaf/utils/immom/iterator.py
b/python/pyosaf/utils/immom/iterator.py
index 75bd004..ea9a4be 100644
--- a/python/pyosaf/utils/immom/iterator.py
+++ b/python/pyosaf/utils/immom/iterator.py
@@ -17,7 +17,6 @@
############################################################################
""" IMM Search iterators """
from __future__ import print_function
-import sys
from collections import Iterator
from ctypes import pointer, c_char_p, cast, c_void_p
@@ -26,16 +25,17 @@ from pyosaf.saImm import saImm, eSaImmScopeT, eSaImmValueTypeT, \
unmarshalSaImmValue, SaImmAttrNameT, SaImmSearchParametersT_2, \
SaImmAttrValuesT_2
from pyosaf import saImmOm
-from pyosaf.utils import immom
-from pyosaf.utils import SafException
+from pyosaf.utils import log_err, bad_handle_retry
+from pyosaf.utils.immom import agent
from pyosaf.utils.immom.object import ImmObject
-class SearchIterator(Iterator):
+class SearchIterator(agent.ImmOmAgentManager, Iterator):
""" General search iterator """
def __init__(self, root_name=None, scope=eSaImmScopeT.SA_IMM_SUBTREE,
- attribute_names=None, search_param=None):
- self.search_handle = saImmOm.SaImmSearchHandleT()
+ attribute_names=None, search_param=None, version=None):
+ super(SearchIterator, self).__init__(version)
+ self.search_handle = None
if root_name is not None:
self.root_name = SaNameT(root_name)
else:
@@ -45,32 +45,28 @@ class SearchIterator(Iterator):
for attr_name in attribute_names] \
if attribute_names else None
- search_options = saImm.SA_IMM_SEARCH_ONE_ATTR
+ self.search_options = saImm.SA_IMM_SEARCH_ONE_ATTR
if attribute_names is None:
- search_options |= saImm.SA_IMM_SEARCH_GET_ALL_ATTR
+ self.search_options |= saImm.SA_IMM_SEARCH_GET_ALL_ATTR
else:
- search_options |= saImm.SA_IMM_SEARCH_GET_SOME_ATTR
+ self.search_options |= saImm.SA_IMM_SEARCH_GET_SOME_ATTR
if search_param is None:
- search_param = SaImmSearchParametersT_2()
+ self.search_param = SaImmSearchParametersT_2()
else:
- search_param = search_param
+ self.search_param = search_param
- try:
- immom.saImmOmSearchInitialize_2(immom.handle, self.root_name,
- self.scope, search_options,
- search_param, self.attribute_names,
- self.search_handle)
- except SafException as err:
- if err.value == eSaAisErrorT.SA_AIS_ERR_NOT_EXIST:
- self.search_handle = None
- raise err
- else:
- raise err
+ def __exit__(self, exit_type, value, traceback):
+ """ Called when Iterator is used in a 'with' statement
+ just before it exits
- def __del__(self):
- if self.search_handle is not None:
- immom.saImmOmSearchFinalize(self.search_handle)
+ exit_type, value and traceback are only set if the with statement was
+ left via an exception
+ """
+ if self.search_handle:
+ agent.saImmOmSearchFinalize(self.search_handle)
+ if self.handle:
+ agent.saImmOmFinalize(self.handle)
def __iter__(self):
return self
@@ -82,14 +78,13 @@ class SearchIterator(Iterator):
def __next__(self):
obj_name = SaNameT()
attributes = pointer(pointer(SaImmAttrValuesT_2()))
- try:
- immom.saImmOmSearchNext_2(self.search_handle, obj_name, attributes)
- except SafException as err:
- if err.value == eSaAisErrorT.SA_AIS_ERR_NOT_EXIST:
- raise StopIteration
- else:
- raise err
-
+ rc = agent.saImmOmSearchNext_2(self.search_handle, obj_name,
+ attributes)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ if rc != eSaAisErrorT.SA_AIS_ERR_NOT_EXIST:
+ log_err("saImmOmSearchNext_2 FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+ raise StopIteration
attrs = {}
attr_list = unmarshalNullArray(attributes)
for attr in attr_list:
@@ -100,6 +95,28 @@ class SearchIterator(Iterator):
for val in attr_range]]
return ImmObject(obj_name, attrs)
+ @bad_handle_retry
+ def init(self):
+ """ Initialize the IMM OM search iterator
+
+ Returns:
+ SaAisErrorT: Return code of the IMM OM APIs
+ """
+ # Cleanup previous resources if any
+ self.finalize()
+ rc = self.initialize()
+
+ self.search_handle = saImmOm.SaImmSearchHandleT()
+ if rc == eSaAisErrorT.SA_AIS_OK:
+ rc = agent.saImmOmSearchInitialize_2(
+ self.handle, self.root_name, self.scope, self.search_options,
+ self.search_param, self.attribute_names, self.search_handle)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ log_err("saImmOmSearchInitialize_2 FAILED - %s" %
+ eSaAisErrorT.whatis(rc))
+ self.search_handle = None
+ return rc
+
class InstanceIterator(SearchIterator):
""" Iterator over instances of a class """
@@ -111,15 +128,3 @@ class InstanceIterator(SearchIterator):
eSaImmValueTypeT.SA_IMM_ATTR_SASTRINGT
search_param.searchOneAttr.attrValue = cast(pointer(name), c_void_p)
SearchIterator.__init__(self, root_name, search_param=search_param)
-
-
-def test():
- """ A simple function to test the usage of InstanceIterator class """
- instance_iter = InstanceIterator(sys.argv[1])
- for dn, attr in instance_iter:
- print(dn.split("=")[1])
- print(attr, "\n")
-
-
-if __name__ == '__main__':
- test()
diff --git a/python/pyosaf/utils/immom/object.py
b/python/pyosaf/utils/immom/object.py
index 24fd485..0cef920 100644
--- a/python/pyosaf/utils/immom/object.py
+++ b/python/pyosaf/utils/immom/object.py
@@ -16,8 +16,11 @@
#
############################################################################
""" IMM Object representation """
+from pyosaf.saAis import eSaAisErrorT
from pyosaf.saImm import saImm
-import pyosaf.utils.immom
+
+from pyosaf.utils import SafException
+from pyosaf.utils.immom.agent import ImmOmAgent
class ImmObject(object):
@@ -34,29 +37,40 @@ class ImmObject(object):
Attributes is a map where attribute name is key, value is a tuple of
(valueType, values), values is a list.
class_name and attributes are mutually exclusive.
+
+ Raises:
+ SafException: If the return code of the corresponding API call(s)
+ is not SA_AIS_OK
"""
self.__dict__["dn"] = dn
-
+ _imm_om = ImmOmAgent()
+ rc = _imm_om.init()
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
# mutually exclusive for read vs create
if class_name is not None:
assert attributes is None
self.__dict__["attrs"] = {}
self.__dict__["class_name"] = class_name
- self.class_desc[class_name] = \
- pyosaf.utils.immom.class_description_get(class_name)
+ rc, class_desc = _imm_om.get_class_description(class_name)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
+ self.class_desc[class_name] = class_desc
elif attributes is not None:
assert class_name is None
self.__dict__["attrs"] = attributes
class_name = attributes["SaImmAttrClassName"][1][0]
self.__dict__["class_name"] = class_name
if class_name not in self.class_desc:
- self.class_desc[class_name] = \
- pyosaf.utils.immom.class_description_get(class_name)
+ rc, class_desc = _imm_om.get_class_description(class_name)
+ if rc != eSaAisErrorT.SA_AIS_OK:
+ raise SafException(rc)
+ self.class_desc[class_name] = class_desc
else:
raise ValueError("Class and attributes are None")
self.__dict__["rdn_attribute"] = \
- pyosaf.utils.immom.get_rdn_attribute_for_class(class_name)
+ _imm_om.get_rdn_attribute_for_class(class_name)
def get_value_type(self, attr_name):
""" Return IMM value type of the named attribute
@@ -108,8 +122,10 @@ class ImmObject(object):
def __setattr__(self, key, value):
# Correct RDN assignments missing the RDN attribute name in value
- if key == self.rdn_attribute and value.find(self.rdn_attribute) != 0:
- value = '%s=%s' % (self.rdn_attribute, value)
+
+ if key == self.rdn_attribute:
+ if str(value).find(self.rdn_attribute) != 0:
+ value = '%s=%s' % (self.rdn_attribute, value)
value_type = self.get_value_type(key)
if isinstance(value, list):