def initialize(notification_callback=None): """ Initialize the NTF library Args: notification_callback (SaNtfNotificationCallbackT): Callback to be invoked by NTF server to deliver a notification to the subscriber Raises: SafException: If any NTF API call did not return SA_AIS_OK """ # Set the NTF API version to initialize version = SaVersionT('A', 1, 1) global _ntf_producer _ntf_producer = NtfProducer(version) global _ntf_subscriber _ntf_subscriber = NtfSubscriber(version) rc = _ntf_producer.init() if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) rc = _ntf_subscriber.init(notification_callback) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def track_stop(): """ Stop cluster membership tracking Raises: SafException: If the return code of the corresponding CLM API call(s) is not SA_AIS_OK """ if _clm_agent is None: # Return SA_AIS_ERR_INIT if user calls this function without first # calling initialize() raise SafException(eSaAisErrorT.SA_AIS_ERR_INIT) rc = _clm_agent.track_stop() if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def admin_op_invoke(dn, op_id, params=None): ''' invokes admin op for dn ''' owner_handle = saImmOm.SaImmAdminOwnerHandleT() owner_name = saImmOm.SaImmAdminOwnerNameT(os.getlogin()) err = saImmOmAdminOwnerInitialize(HANDLE, owner_name, saAis.eSaBoolT.SA_TRUE, owner_handle) idx = dn.rfind(",") parent_name = SaNameT(dn[idx + 1:]) object_names = [parent_name] err = saImmOmAdminOwnerSet(owner_handle, object_names, eSaImmScopeT.SA_IMM_SUBTREE) if params is None: params = [] object_dn = SaNameT(dn) retval = saAis.SaAisErrorT() err = saImmOmAdminOperationInvoke_2(owner_handle, object_dn, 0, op_id, params, retval, saAis.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) error = saImmOmAdminOwnerFinalize(owner_handle)
def send_attribute_change_notification( vendor_id, major_id, minor_id, additional_text="", notification_object="", notifying_object="", event_type=saNtf.eSaNtfEventTypeT.SA_NTF_ATTRIBUTE_ADDED, event_time=saAis.SA_TIME_UNKNOWN, additional_info=None, changed_attributes=None): """ Send notification about an attribute change event Args: vendor_id (SaUint32T): Vendor id major_id (SaUint16T): Major id minor_id (SaUint16T): Minor id additional_text (str): Additional text notification_object (str): Notification object's dn notifying_object (str): Notifying object's dn event_type (SaNtfEventTypeT): Event type event_time (SaTimeT): Event time additional_info (list(AdditionalInfo)): List of AdditionalInfo structures changed_attributes (list(AttributeChange)): List of AttributeChange structures Returns: SaAisErrorT: Return code of the corresponding NTF API call(s) Raises: SafException: If any NTF API call did not return SA_AIS_OK """ ntf_class_id = saNtf.SaNtfClassIdT(vendor_id, major_id, minor_id) if _ntf_producer is None: # SA_AIS_ERR_INIT is returned if user calls this function without first # calling initialize() return eSaAisErrorT.SA_AIS_ERR_INIT _ntf_producer.set_event_type(event_type) _ntf_producer.set_class_id(ntf_class_id) _ntf_producer.set_additional_text(additional_text) _ntf_producer.set_notification_object(notification_object) _ntf_producer.set_notifying_object(notifying_object) _ntf_producer.set_event_time(event_time) if additional_info: _ntf_producer.set_additional_info(additional_info) if changed_attributes: _ntf_producer.set_changed_attributes(changed_attributes) rc = _ntf_producer.send_attribute_change_notification() if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) # Clear the internally saved notification information _ntf_producer.clear_info() return rc
def send_alarm_notification( vendor_id, major_id, minor_id, perceived_severity, additional_text="", notification_object="", notifying_object="", event_type=saNtf.eSaNtfEventTypeT.SA_NTF_ALARM_PROCESSING, event_time=saAis.SA_TIME_UNKNOWN, additional_info=None): """ Send an alarm notification Args: vendor_id (SaUint32T): Vendor id major_id (SaUint16T): Major id minor_id (SaUint16T): Minor id perceived_severity (SaNtfSeverityT): Perceived severity additional_text (str): Additional text notification_object (str): Notification object's dn notifying_object (str): Notifying object's dn event_type (SaNtfEventTypeT): Event type event_time (SaTimeT): Event time additional_info (list(AdditionalInfo)): List of AdditionalInfo structures Returns: SaAisErrorT: Return code of the corresponding NTF API call(s) Raises: SafException: If any NTF API call did not return SA_AIS_OK """ ntf_class_id = saNtf.SaNtfClassIdT(vendor_id, major_id, minor_id) if _ntf_producer is None: # SA_AIS_ERR_INIT is returned if user calls this function without first # calling initialize() return eSaAisErrorT.SA_AIS_ERR_INIT _ntf_producer.set_event_type(event_type) _ntf_producer.set_class_id(ntf_class_id) _ntf_producer.set_additional_text(additional_text) _ntf_producer.set_notification_object(notification_object) _ntf_producer.set_notifying_object(notifying_object) _ntf_producer.set_event_time(event_time) _ntf_producer.set_perceived_severity(perceived_severity) if additional_info: _ntf_producer.set_additional_info(additional_info) rc = _ntf_producer.send_alarm_notification() if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) # Clear the internally saved notification information _ntf_producer.clear_info() return rc
def __init__(self, dn=None, attributes=None, class_name=None): """ Constructor for IMM 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 rc, class_desc = _imm_om.get_class_description(class_name) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) self.class_desc[str(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: rc, class_desc = _imm_om.get_class_description(class_name) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) self.class_desc[str(class_name)] = class_desc else: raise ValueError("Class and attributes are None") self.__dict__["rdn_attribute"] = \ _imm_om.get_rdn_attribute_for_class(class_name)
def initialize(): """ Initialize the IMM OM library Raises: SafException: If any IMM OM API call did not return 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)
def delete(self, _object_name): ''' Adds a delete operation of the object with the given DN to the CCB''' if _object_name is None: raise SafException(eSaAisErrorT.SA_AIS_ERR_NOT_EXIST) 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)
def get_selection_object(): """ Get an selection object for event polling Returns: SaSelectionObjectT: Return code of selection object get 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 _oi_agent.get_selection_object()
def modify_value_add(self, object_name, attr_name, values): ''' add to the CCB an ADD modification of an existing object ''' assert object_name # Make sure the values field is a list if not isinstance(values, list): values = [values] # first get class name to read class description to get value type... try: obj = immom.get(object_name) except SafException as err: print "failed: %s" % err return object_names = [SaNameT(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: # means attribute name is invalid raise SafException(eSaAisErrorT.SA_AIS_ERR_NOT_EXIST, "attribute '%s' does not exist" % attr_name) err = immom.saImmOmAdminOwnerSet(self.owner_handle, object_names, eSaImmScopeT.SA_IMM_ONE) attr_mods = [] attr_mod = saImmOm.SaImmAttrModificationT_2() attr_mod.modType = \ 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) err = immom.saImmOmCcbObjectModify_2(self.ccb_handle, object_names[0], attr_mods)
def initialize(callbacks=None): """ Initialize the IMM OI library Args: callbacks (SaImmOiCallbacksT_2): OI callbacks to register with IMM Raises: SafException: If the return code of the corresponding OI API call(s) is not SA_AIS_OK """ global _oi_agent _oi_agent = OiAgent() rc = _oi_agent.initialize(callbacks=callbacks) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def get_selection_object(): """ Get the selection object associated with this CLM agent Returns: SaSelectionObjectT: Selection object associated with the CLM handle Raises: SafException: If the return code of the corresponding CLM API call(s) is not SA_AIS_OK """ if _clm_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 _clm_agent.get_selection_object()
def delete_rt_object(dn): """ Delete a runtime object Args: dn (str): Runtime object dn Raises: SafException: If the return code of the corresponding OI API call(s) is not SA_AIS_OK """ if _oi_agent is None: initialize() rc = _oi_agent.delete_runtime_object(dn) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def track(flags=saAis.SA_TRACK_CHANGES_ONLY): """ Start cluster membership tracking with specified flags Args: flags (SaUint8T): Type of cluster membership tracking Raises: SafException: If the return code of the corresponding CLM API call(s) is not SA_AIS_OK """ if _clm_agent is None: # Return SA_AIS_ERR_INIT if user calls this function without first # calling initialize() return eSaAisErrorT.SA_AIS_ERR_INIT rc = _clm_agent.track_start(flags) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def initialize(track_func=None, node_get_func=None, version=None): """ Initialize the CLM agent library Args: track_func (callback): Cluster track callback function node_get_func (callback): Cluster node get callback function version (SaVersionT): Clm version being initialized Raises: SafException: If the return code of the corresponding CLM API call(s) is not SA_AIS_OK """ global _clm_agent _clm_agent = ClmAgent(version) rc = _clm_agent.initialize(track_func, node_get_func) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def report_admin_operation_result(invocation_id, result): """ Report the result of an administrative operation Args: invocation_id (SaInvocationT): Invocation id result (SaAisErrorT): Result of admin operation Raises: SafException: If the return code of the corresponding OI API call(s) is not SA_AIS_OK """ if _oi_agent is None: initialize() rc = _oi_agent.report_admin_operation_result(invocation_id, result) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def admin_op_invoke(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 Raises: SafException: If any IMM OM API call did not return SA_AIS_OK """ if _om_agent is None: initialize() rc = _om_agent.invoke_admin_operation(dn, op_id, params) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def dispatch(flags=eSaDispatchFlagsT.SA_DISPATCH_ALL): """ Invoke NTF callbacks for queued events. The default is to dispatch all available events. Args: flags (eSaDispatchFlagsT): Flags specifying dispatch mode Returns: SaAisErrorT: Return code of the corresponding NTF API call(s) Raises: SafException: If any NTF API call did not return SA_AIS_OK """ rc = _ntf_subscriber.dispatch(flags) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) return rc
def response(invocation, result): """ Respond to CLM the result of execution of the requested callback Args: invocation (SaInvocationT): Invocation id associated with the callback result (SaAisErrorT): Result of callback execution Raises: SafException: If the return code of the corresponding CLM API call(s) is not SA_AIS_OK """ if _clm_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 = _clm_agent.response(invocation, result) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def create_rt_object(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 Raises: SafException: If the return code of the corresponding OI API call(s) is not SA_AIS_OK """ if _oi_agent is None: initialize() rc = _oi_agent.create_runtime_object(class_name, parent_name, runtime_obj) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def update_rt_object(dn, attributes): """ Update the specified object with the requested attribute modifications Args: dn (str): Object dn attributes (dict): Dictionary of attribute modifications Raises: SafException: If the return code of the corresponding OI API call(s) is not SA_AIS_OK """ if _oi_agent is None: initialize() rc = _oi_agent.update_runtime_object(dn, attributes) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def set_error_string(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 Raises: SafException: If the return code of the corresponding OI API call(s) is not SA_AIS_OK """ if _oi_agent is None: initialize() rc = _oi_agent.set_error_string(ccb_id, error_string) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def dispatch(flags=eSaDispatchFlagsT.SA_DISPATCH_ALL): """ Invoke CLM callbacks for queued events with the given dispatch flag. If no dispatch flag is specified, the default is to dispatch all available events. Args: flags (eSaDispatchFlagsT): Flags specifying dispatch mode Raises: SafException: If the return code of the corresponding CLM API call(s) is not SA_AIS_OK """ if _clm_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 = _clm_agent.dispatch(flags) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc)
def class_description_get(class_name): """ Get class description as a Python list Args: class_name (str): Class name Returns: list: List of class attributes Raises: SafException: If any IMM OM API call did not return SA_AIS_OK """ if _om_agent is None: initialize() rc, class_attrs = _om_agent.get_class_description(class_name) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) return class_attrs
def get_members(): """ Get member notifications from notification buffer Returns: ClusterNode: The node information Raises: SafException: If the return code of the corresponding CLM API call(s) is not SA_AIS_OK """ if _clm_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, cluster_nodes = _clm_agent.get_members() if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) return cluster_nodes
def subscribe_for_notifications(notification_types=None): """ Subscribe for notifications from NTF with the types specified in the notification_types list If the list is not provided, all types of notification are subscribed to by default. Args: notification_types (list(SaNtfNotificationTypeT)): List of notification types Returns: SaAisErrorT: Return code of the corresponding NTF API call(s) Raises: SafException: If any NTF API call did not return SA_AIS_OK """ rc = _ntf_subscriber.subscribe(1, notification_types) if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) return rc
def get(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 Raises: SafException: If any IMM OM API call did not return SA_AIS_OK """ _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
def send_security_alarm_notification( vendor_id, major_id, minor_id, severity, alarm_detector, user, provider, additional_text="", notification_object="", notifying_object="", event_type=saNtf.eSaNtfEventTypeT.SA_NTF_INTEGRITY_VIOLATION, event_time=saAis.SA_TIME_UNKNOWN, additional_info=None, probable_cause=saNtf.eSaNtfProbableCauseT.SA_NTF_SOFTWARE_ERROR): """ Send a security alarm notification Args: vendor_id (SaUint32T): Vendor id major_id (SaUint16T): Major id minor_id (SaUint16T): Minor id severity (SaNtfSeverityT): Severity alarm_detector (SecurityAlarmDetector): SecurityAlarmDetector information structure user (ServiceUser): ServiceUser information structure provider (ServiceProvider): ServiceProvider information structure additional_text (str): Additional text notification_object (str): Notification object's dn notifying_object (str): Notifying object's dn event_type (SaNtfEventTypeT): Event type event_time (SaTimeT): Event time additional_info (list(AdditionalInfo)): List of AdditionalInfo structures probable_cause (SaNtfProbableCauseT): Probable cause Returns: SaAisErrorT: Return code of the corresponding NTF API call(s) Raises: SafException: If any NTF API call did not return SA_AIS_OK """ ntf_class_id = saNtf.SaNtfClassIdT(vendor_id, major_id, minor_id) if _ntf_producer is None: # SA_AIS_ERR_INIT is returned if user calls this function without first # calling initialize() return eSaAisErrorT.SA_AIS_ERR_INIT _ntf_producer.set_event_type(event_type) _ntf_producer.set_class_id(ntf_class_id) _ntf_producer.set_additional_text(additional_text) _ntf_producer.set_notification_object(notification_object) _ntf_producer.set_notifying_object(notifying_object) _ntf_producer.set_event_time(event_time) if additional_info: _ntf_producer.set_additional_info(additional_info) _ntf_producer.set_severity(severity) _ntf_producer.set_probable_cause(probable_cause) _ntf_producer.set_security_alarm_detector(alarm_detector) _ntf_producer.set_service_user(user) _ntf_producer.set_service_provider(provider) rc = _ntf_producer.send_security_alarm_notification() if rc != eSaAisErrorT.SA_AIS_OK: raise SafException(rc) # Clear the internally saved notification information _ntf_producer.clear_info() return rc
def validate(self, all_instances, updated, created, deleted): ''' Validates the constraints in this Constraints instance ''' def get_children_with_classname(parent_name, all_instances, class_name): ''' Helper method to count the number of children of the given class in the list of all instances ''' current_children = [] for child in all_instances: if not ',' in child.dn: continue if immoi.get_parent_name_for_dn(child.dn) == parent_name and \ child.class_name == class_name: current_children.append(child) return current_children def constraint_exists_for_child(class_name): ''' Returns true if there exists a constraint for the given class as a child ''' for child_classes in self.containments.values(): if class_name in child_classes: return True return False # Validate containments affected by create or delete deleted_mos = [immoi.get_object_no_runtime(deleted_mo) \ for deleted_mo in deleted] for mo in itertools.chain(created, deleted_mos): parent_name = immoi.get_parent_name_for_dn(mo.dn) # Handle the case where there is no parent if not parent_name: if mo in created and \ constraint_exists_for_child(mo.class_name): error_string = ("ERROR: Cannot create %s, %s must have a " "parent") % (mo.dn, mo.SaImmAttrClassName) raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM, error_string) # Allow this operation and check the next one continue # Handle the case where the parent is also deleted if parent_name in deleted: continue # Avoid looking up the parent class in IMM if possible parent_mos = [x for x in all_instances if x.dn == parent_name] if parent_mos: parent_class = parent_mos[0].class_name else: parent_class = immoi.get_class_name_for_dn(parent_name) # Ignore children where no constraint is defined for the child or # the parent if not parent_class in self.containments and not \ constraint_exists_for_child(mo.class_name): continue # Validate the containment if there is a parent child_classes = self.containments[parent_class] # Reject the create if the child's class is not part of the allowed # child classes if not mo.class_name in child_classes and mo in created: error_string = ("ERROR: Cannot create %s as a child under %s. " "Possible children are %s") % \ (mo.dn, parent_class, child_classes) raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM, error_string) # Count current containments current_children = get_children_with_classname(parent_name, all_instances, mo.class_name) # Validate the number of children of the specific class to the given # parent lower, upper = self.cardinality[(parent_class, mo.class_name)] if lower and len(current_children) < lower: error_string = ("ERROR: Must have at least %s instances of %s " "under %s") % \ (lower, mo.class_name, parent_class) raise SafException(eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION, error_string) if upper and len(current_children) > upper: error_string = ("ERROR: Must have at most %s instances of %s " "under %s") % \ (upper, mo.class_name, parent_class) raise SafException(eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION, error_string)
def validate(self, all_instances, updated, created, deleted): """ Validate the constraints in this Constraints instance Args: all_instances (list): List of instances to validate updated (list): List of updated objects created (list): List of created objects deleted (list): List of deleted objects """ def get_children_with_class_name(_parent_name, _all_instances, _class_name): """ Helper method to count the number of children of the given class in the list of all instances """ _current_children = [] for child in _all_instances: if ',' not in child.dn: continue if self.get_parent_name_for_dn(child.dn) == _parent_name \ and child.class_name == _class_name: _current_children.append(child) return _current_children def constraint_exists_for_child(_class_name): """ Return True if there exists a constraint for the given class as a child """ for _child_classes in list(self.containments.values()): if _class_name in _child_classes: return True return False # Validate containments affected by create or delete deleted_objs = [self.get_object_no_runtime(dn) for dn in deleted] for obj in itertools.chain(created, deleted_objs): parent_name = self.get_parent_name_for_dn(obj.dn) # Handle the case where there is no parent if not parent_name: if obj in created \ and constraint_exists_for_child(obj.class_name): error_string = "ERROR: Cannot create %s, %s must have a " \ "parent" % (obj.dn, obj.SaImmAttrClassName) raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM, error_string) # Allow this operation and check the next one continue # Handle the case where the parent is also deleted if parent_name in deleted: continue # Avoid looking up the parent class in IMM if possible parent_obj = [obj for obj in all_instances if obj.dn == parent_name] if parent_obj: parent_class = parent_obj[0].class_name else: parent_class = self.get_class_name_for_dn(dn=parent_name) # Ignore children where no constraint is defined for the child or # the parent if parent_class not in self.containments \ and not constraint_exists_for_child(obj.class_name): continue # Validate the containment if there is a parent child_classes = self.containments[parent_class] # Reject the create if the child's class is not part of the allowed # child classes if obj.class_name not in child_classes and obj in created: error_string = "ERROR: Cannot create %s as a child under %s." \ " Possible children are %s" % \ (obj.dn, parent_class, child_classes) raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM, error_string) # Count current containments current_children = get_children_with_class_name(parent_name, all_instances, obj.class_name) # Validate the number of children of the specific class to the # given parent lower, upper = self.cardinality[(parent_class, obj.class_name)] if lower and len(current_children) < lower: error_string = ("ERROR: Must have at least %s instances of %s " "under %s") % \ (lower, obj.class_name, parent_class) raise SafException(eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION, error_string) if upper and len(current_children) > upper: error_string = ("ERROR: Must have at most %s instances of %s " "under %s") % \ (upper, obj.class_name, parent_class) raise SafException(eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION, error_string)