opensaf.spec.in | 3 + python/pyosaf/saNtf.py | 27 + python/pyosaf/utils/Makefile.am | 3 +- python/pyosaf/utils/ntf/Makefile.am | 22 + python/pyosaf/utils/ntf/__init__.py | 657 ++++++++++++++++++++++++++++++++++++ python/samples/README | 11 + python/samples/ntfsend | 251 +++++++++++++ python/samples/ntfsubscribe | 307 ++++++++++++++++ 8 files changed, 1280 insertions(+), 1 deletions(-)
Add high-level bindings and sample applications for NTF. A known issue is that the assignment of additionalText is not working. Verify by using the ntfsend and ntfsubscribe sample applications. diff --git a/opensaf.spec.in b/opensaf.spec.in --- a/opensaf.spec.in +++ b/opensaf.spec.in @@ -1524,6 +1524,9 @@ fi %{python_sitelib}/pyosaf/utils/log/*.py %{python_sitelib}/pyosaf/utils/log/*.pyc %{python_sitelib}/pyosaf/utils/log/*.pyo +%{python_sitelib}/pyosaf/utils/ntf/*.py +%{python_sitelib}/pyosaf/utils/ntf/*.pyc +%{python_sitelib}/pyosaf/utils/ntf/*.pyo %{python_sitelib}/pyosaf/utils/immoi/*.py %{python_sitelib}/pyosaf/utils/immoi/*.pyc %{python_sitelib}/pyosaf/utils/immoi/*.pyo diff --git a/python/pyosaf/saNtf.py b/python/pyosaf/saNtf.py --- a/python/pyosaf/saNtf.py +++ b/python/pyosaf/saNtf.py @@ -176,6 +176,33 @@ eSaNtfValueTypeT = Enumeration(( 'SA_NTF_VALUE_ARRAY', )) +SaNtfValueTypeMap = { + eSaNtfValueTypeT.SA_NTF_VALUE_UINT8: SaUint8T, + eSaNtfValueTypeT.SA_NTF_VALUE_INT8: SaInt8T, + eSaNtfValueTypeT.SA_NTF_VALUE_UINT16: SaUint16T, + eSaNtfValueTypeT.SA_NTF_VALUE_INT16: SaInt16T, + eSaNtfValueTypeT.SA_NTF_VALUE_UINT32: SaUint32T, + eSaNtfValueTypeT.SA_NTF_VALUE_INT32: SaInt32T, + eSaNtfValueTypeT.SA_NTF_VALUE_FLOAT: SaFloatT, + eSaNtfValueTypeT.SA_NTF_VALUE_UINT64: SaUint64T, + eSaNtfValueTypeT.SA_NTF_VALUE_INT64: SaInt64T, + eSaNtfValueTypeT.SA_NTF_VALUE_DOUBLE: SaDoubleT, + eSaNtfValueTypeT.SA_NTF_VALUE_LDAP_NAME: SaStringT, + eSaNtfValueTypeT.SA_NTF_VALUE_STRING: SaStringT, + eSaNtfValueTypeT.SA_NTF_VALUE_IPADDRESS: SaStringT, + eSaNtfValueTypeT.SA_NTF_VALUE_BINARY: SaAnyT, + eSaNtfValueTypeT.SA_NTF_VALUE_ARRAY: SaAnyT +} + +def unmarshalSaNtfValue(void_ptr, value_type): + """Convert void pointer to an instance of value type. + """ + val_ptr = SaNtfValueTypeMap.get(value_type) + if val_ptr and void_ptr: + if val_ptr == SaNameT: + return cast(void_ptr, POINTER(val_ptr))[0].value + return cast(void_ptr, POINTER(val_ptr))[0] + return None class _ptrVal(Structure): _fields_ = [('dataOffset', SaUint16T), ('dataSize', SaUint16T)] diff --git a/python/pyosaf/utils/Makefile.am b/python/pyosaf/utils/Makefile.am --- a/python/pyosaf/utils/Makefile.am +++ b/python/pyosaf/utils/Makefile.am @@ -25,4 +25,5 @@ SUBDIRS = \ immom \ clm \ log \ - immoi + immoi \ + ntf diff --git a/python/pyosaf/utils/ntf/Makefile.am b/python/pyosaf/utils/ntf/Makefile.am new file mode 100644 --- /dev/null +++ b/python/pyosaf/utils/ntf/Makefile.am @@ -0,0 +1,22 @@ +# -*- OpenSAF -*- +# +# (C) Copyright 2011 The OpenSAF Foundation +# +# 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): Oracle +# + +include $(top_srcdir)/Makefile.common + +MAINTAINERCLEANFILES = Makefile.in + +pkgpyosafutilsntf_PYTHON = \ + __init__.py diff --git a/python/pyosaf/utils/ntf/__init__.py b/python/pyosaf/utils/ntf/__init__.py new file mode 100644 --- /dev/null +++ b/python/pyosaf/utils/ntf/__init__.py @@ -0,0 +1,657 @@ +############################################################################ +# +# (C) Copyright 2015 The OpenSAF Foundation +# +# 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 +# +############################################################################ + +''' + NTF common utilities +''' + +from pyosaf import saNtf, saAis +import ctypes + +from pyosaf.utils import decorate + +saNtfInitialize = decorate(saNtf.saNtfInitialize) +saNtfLocalizedMessageFree = decorate(saNtf.saNtfLocalizedMessageFree) +saNtfStateChangeNotificationFilterAllocate = decorate(saNtf.saNtfStateChangeNotificationFilterAllocate) +saNtfNotificationUnsubscribe = decorate(saNtf.saNtfNotificationUnsubscribe) +saNtfNotificationReadInitialize = decorate(saNtf.saNtfNotificationReadInitialize) +saNtfInitialize_2 = decorate(saNtf.saNtfInitialize_2) +saNtfNotificationReadInitialize_2 = decorate(saNtf.saNtfNotificationReadInitialize_2) +saNtfNotificationSubscribe = decorate(saNtf.saNtfNotificationSubscribe) +saNtfInitialize_3 = decorate(saNtf.saNtfInitialize_3) +saNtfSelectionObjectGet = decorate(saNtf.saNtfSelectionObjectGet) +saNtfDispatch = decorate(saNtf.saNtfDispatch) +saNtfFinalize = decorate(saNtf.saNtfFinalize) +saNtfObjectCreateDeleteNotificationAllocate = decorate(saNtf.saNtfObjectCreateDeleteNotificationAllocate) +saNtfAttributeChangeNotificationAllocate = decorate(saNtf.saNtfAttributeChangeNotificationAllocate) +saNtfStateChangeNotificationAllocate = decorate(saNtf.saNtfStateChangeNotificationAllocate) +saNtfStateChangeNotificationAllocate_3 = decorate(saNtf.saNtfStateChangeNotificationAllocate_3) +saNtfAlarmNotificationAllocate = decorate(saNtf.saNtfAlarmNotificationAllocate) +saNtfSecurityAlarmNotificationAllocate = decorate(saNtf.saNtfSecurityAlarmNotificationAllocate) +saNtfMiscellaneousNotificationAllocate = decorate(saNtf.saNtfMiscellaneousNotificationAllocate) +saNtfPtrValAllocate = decorate(saNtf.saNtfPtrValAllocate) +saNtfArrayValAllocate = decorate(saNtf.saNtfArrayValAllocate) +saNtfIdentifierAllocate = decorate(saNtf.saNtfIdentifierAllocate) +saNtfNotificationSend = decorate(saNtf.saNtfNotificationSend) +saNtfNotificationSendWithId = decorate(saNtf.saNtfNotificationSendWithId) +saNtfNotificationFree = decorate(saNtf.saNtfNotificationFree) +saNtfVariableDataSizeGet = decorate(saNtf.saNtfVariableDataSizeGet) +saNtfLocalizedMessageGet = decorate(saNtf.saNtfLocalizedMessageGet) +saNtfLocalizedMessageFree_2 = decorate(saNtf.saNtfLocalizedMessageFree_2) +saNtfPtrValGet = decorate(saNtf.saNtfPtrValGet) +saNtfArrayValGet = decorate(saNtf.saNtfArrayValGet) +saNtfObjectCreateDeleteNotificationFilterAllocate = decorate(saNtf.saNtfObjectCreateDeleteNotificationFilterAllocate) +saNtfAttributeChangeNotificationFilterAllocate = decorate(saNtf.saNtfAttributeChangeNotificationFilterAllocate) +saNtfStateChangeNotificationFilterAllocate_2 = decorate(saNtf.saNtfStateChangeNotificationFilterAllocate_2) +saNtfAlarmNotificationFilterAllocate = decorate(saNtf.saNtfAlarmNotificationFilterAllocate) +saNtfSecurityAlarmNotificationFilterAllocate = decorate(saNtf.saNtfSecurityAlarmNotificationFilterAllocate) +saNtfNotificationFilterFree = decorate(saNtf.saNtfNotificationFilterFree) +saNtfNotificationSubscribe_3 = decorate(saNtf.saNtfNotificationSubscribe_3) +saNtfNotificationReadInitialize_3 = decorate(saNtf.saNtfNotificationReadInitialize_3) +saNtfNotificationUnsubscribe_2 = decorate(saNtf.saNtfNotificationUnsubscribe_2) +saNtfNotificationReadNext = decorate(saNtf.saNtfNotificationReadNext) +saNtfNotificationReadNext_3 = decorate(saNtf.saNtfNotificationReadNext_3) +saNtfNotificationReadFinalize = decorate(saNtf.saNtfNotificationReadFinalize) + + +HANDLE = saNtf.SaNtfHandleT() +SELECTION_OBJECT = saAis.SaSelectionObjectT() +CALLBACKS = saNtf.SaNtfCallbacksT() + + +class AdditionalInfo(object): + ''' Represents a piece of additional info to be included in a + notification + ''' + + def __init__(self, info_id, info_type, info_value): + self.info_id = info_id + self.info_type = info_type + self.info_value = info_value + + +class StateChange(object): + ''' Contains information about a state change event''' + + def __init__(self): + pass + + +class AttributeChange(object): + ''' Contains information about a change in an attribute''' + + def __init__(self): + pass + + +class Attribute(object): + ''' Contains information about the value and value type of an attribute''' + + def __init__(self): + pass + + +class SecurityAlarmDetector(object): + ''' Represents an instance of a security alarm detector''' + + def __init__(self, value=None, value_type=None): + self.value = value + self.value_type = value_type + + +class ServiceUser(object): + ''' Represents a service user''' + + def __init__(self, value=None, value_type=None): + self.value = value + self.value_type = value_type + + +class ServiceProvider(object): + ''' Represents a service provider''' + + def __init__(self, value=None, value_type=None): + self.value = value + self.value_type = value_type + + +def dummy_func(*args): + ''' Dummy function used as a callback when no proper callbacks are set''' + pass + +def initialize(notification_callback=None): + ''' Initializes the NTF library''' + + # Initialize the NTF API + version = saAis.SaVersionT('A', 1, 1) + + # Assign default values for callbacks + CALLBACKS.saNtfNotificationCallback = \ + saNtf.SaNtfNotificationCallbackT(dummy_func) + CALLBACKS.saNtfNotificationDiscardedCallback = \ + saNtf.SaNtfNotificationDiscardedCallbackT(dummy_func) + + # Override the notification subscribe callback if it's passed + if notification_callback: + CALLBACKS.saNtfNotificationCallback = \ + saNtf.SaNtfNotificationCallbackT(notification_callback) + + # Initialize the API + saNtfInitialize(HANDLE, CALLBACKS, version) + + # Get the selection object + saNtfSelectionObjectGet(HANDLE, SELECTION_OBJECT) + + +def assign_ntf_value_to_attribute(attr_value_field, value, value_type): + ''' Assigns the correct sub-field in the given attribute + + e.g. attr_value_field.uint8Val = ... + + ''' + + if value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_UINT8: + attr_value_field.uint8Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT8: + attr_value_field.int8Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_UINT16: + attr_value_field.uint16Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT16: + attr_value_field.int16Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_UINT32: + attr_value_field.uint32Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT32: + attr_value_field.int32Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_FLOAT: + attr_value_field.floatVal = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_UINT64: + attr_value_field.uint64Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT64: + attr_value_field.int64Val = value + + elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_DOUBLE: + attr_value_field.doubleVal = value + + +def fill_in_header(notification_handle, + header, notification_object, notifying_object, vendor_id, + major_id, minor_id, additional_text, event_type, event_time, + additional_info): + ''' Fills in the given notification header with the provided values''' + + header.eventType.contents.value = event_type + header.notificationObject.contents.value = notification_object + header.notificationObject.contents.length = len(notification_object) + header.notifyingObject.contents.value = notifying_object + header.notifyingObject.contents.length = len(notifying_object) + header.notificationClassId.contents.vendorId = vendor_id + header.notificationClassId.contents.majorId = major_id + header.notificationClassId.contents.minorId = minor_id + header.eventTime.contents.value = event_time + header.numCorrelatedNotifications = 0 + header.lengthAdditionalText = len(additional_text) + + ## + ## FIXME: this fails to copy the value of the additional_text variable into + ## header.additionalText. + + ctypes.memmove(header.additionalText, + additional_text, + len(additional_text)) + + header.numAdditionalInfo = len(additional_info) + header.thresholdInformation = None + + # Fill in additional info + if additional_info != []: + for i in range(0, len(additional_info)): + + header.additionalInfo[i].infoId = additional_info[i].info_id + header.additionalInfo[i].infoType = additional_info[i].info_type + + dest_ptr = (ctypes.c_char * len(additional_info[i].info_value))() + + saNtf.saNtfPtrValAllocate(notification_handle, + len(additional_info[i].info_value) + 1, + dest_ptr, + header.additionalInfo[i].infoValue) + + ctypes.memmove(ctypes.addressof(dest_ptr), + additional_info[i].info_value, + len(additional_info[i].info_value) + 1) + + else: + header.additionalInfo = None + + +def send_object_create_notification(vendor_id, major_id, minor_id, + additional_text="", + notification_object="", + notifying_object="", + attributes=[], + event_time=saAis.saAis.SA_TIME_UNKNOWN, + additional_info=[]): + ''' Sends a notification for a created object''' + + _send_object_create_delete_notification( + saNtf.eSaNtfEventTypeT.SA_NTF_OBJECT_CREATION, + vendor_id, major_id, minor_id, + additional_text=additional_text, + notification_object=notification_object, + notifying_object=notifying_object, + attributes=attributes, + event_time=event_time, + additional_info=additional_info) + + +def send_object_delete_notification(vendor_id, + major_id, + minor_id, + additional_text="", + notification_object="", + notifying_object="", + attributes=[], + event_time=saAis.saAis.SA_TIME_UNKNOWN, + additional_info=[]): + ''' Sends a notification for a deleted object''' + + _send_object_create_delete_notification( + saNtf.eSaNtfEventTypeT.SA_NTF_OBJECT_DELETION, + vendor_id, major_id, minor_id, + additional_text=additional_text, + notification_object=notification_object, + notifying_object=notifying_object, + attributes=attributes, + event_time=event_time, + additional_info=additional_info) + + +def _send_object_create_delete_notification( + event_type, + vendor_id, + major_id, + minor_id, + additional_text="", + notification_object="", + notifying_object="", + attributes=[], + event_time=saAis.saAis.SA_TIME_UNKNOWN, + additional_info=[]): + ''' Sends an object create delete notification''' + + # Create the notification + notification = saNtf.SaNtfObjectCreateDeleteNotificationT() + + saNtfObjectCreateDeleteNotificationAllocate( + HANDLE, + notification, + 0, + len(additional_text) + 1, + len(additional_info), + len(attributes), + 0) + + # Fill in the header + fill_in_header(notification.notificationHandle, + notification.notificationHeader, + notification_object, notifying_object, vendor_id, + major_id, minor_id, additional_text, + event_type, event_time, additional_info) + + # Fill in attributes + for i in range(0, notification.numAttributes): + + ptr = notification.objectAttributes[i] + + ptr.attributeId = attributes[i].attribute_id + ptr.attributeType = attributes[i].attribute_type + + assign_ntf_value_to_attribute(ptr.attributeValue, + attributes[i].attribute_value, + attributes[i].attribute_type) + + + # Send the notification + saNtfNotificationSend(notification.notificationHandle) + + # Free the notification + saNtfNotificationFree(notification.notificationHandle) + + +def send_state_change_notification(vendor_id, + major_id, + minor_id, + additional_text="", + notification_object="", + notifying_object="", + event_time=saAis.saAis.SA_TIME_UNKNOWN, + additional_info=[], + state_changes=[]): + ''' Sends a state change notification''' + + event_type = saNtf.eSaNtfEventTypeT.SA_NTF_OBJECT_STATE_CHANGE + + # Create the notification + notification = saNtf.SaNtfStateChangeNotificationT() + + saNtfStateChangeNotificationAllocate( + HANDLE, + notification, + 0, + len(additional_text) + 1, + len(additional_info), + len(state_changes), + 0) + + # Fill in the header + fill_in_header(notification.notificationHandle, + notification.notificationHeader, + notification_object, notifying_object, vendor_id, + major_id, minor_id, additional_text, event_type, + event_time, additional_info) + + # Fill in state changes + + for i in range(0, len(state_changes)): + + notification.changedStates[i].stateId = state_changes[i].state_id + + if state_changes[i].old_state_present: + notification.changedStates[i].oldStatePresent = saAis.eSaBoolT.SA_TRUE + notification.changedStates[i].oldState = state_changes[i].old_state + + else: + notification.changedStates[i].oldStatePresent = saAis.eSaBoolT.SA_FALSE + + notification.changedStates[i].newState = state_changes[i].new_state + + # Send the alarm notification + saNtfNotificationSend(notification.notificationHandle) + + # Free the alarm notification + saNtfNotificationFree(notification.notificationHandle) + + +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.saAis.SA_TIME_UNKNOWN, + additional_info=[], + changed_attributes=[]): + ''' Sends an attribute_change notification''' + + # Create the notification + notification = saNtf.SaNtfAttributeChangeNotificationT() + + saNtfAttributeChangeNotificationAllocate( + HANDLE, + notification, + 0, + len(additional_text) + 1, + len(additional_info), + len(changed_attributes), + 0) + + # Fill in the header + fill_in_header(notification.notificationHandle, + notification.notificationHeader, + notification_object, notifying_object, vendor_id, + major_id, minor_id, additional_text, event_type, + event_time, additional_info) + + + # Fill in attributes + for i in range(0, len(changed_attributes)): + + ptr = notification.changedAttributes[i] + + ptr.attributeId = changed_attributes[i].attribute_id + ptr.attributeType = changed_attributes[i].attribute_type + + if changed_attributes[i].old_attribute_present: + ptr.oldAttributePresent = saAis.eSaBoolT.SA_TRUE + + assign_ntf_value_to_attribute(ptr.oldAttributeValue, + changed_attributes[i].old_attribute_value, + changed_attributes[i].attribute_type) + + else: + ptr.oldAttributePresent = saAis.eSaBoolT.SA_FALSE + + assign_ntf_value_to_attribute(ptr.newAttributeValue, + changed_attributes[i].new_attribute_value, + changed_attributes[i].attribute_type) + + # Send the alarm notification + saNtfNotificationSend(notification.notificationHandle) + + # Free the alarm notification + saNtfNotificationFree(notification.notificationHandle) + + +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.saAis.SA_TIME_UNKNOWN, + additional_info=[], + probable_cause=saNtf.eSaNtfProbableCauseT.SA_NTF_SOFTWARE_ERROR): + + ''' Sends a security alarm notification''' + + # Create the notification + notification = saNtf.SaNtfSecurityAlarmNotificationT() + + saNtfSecurityAlarmNotificationAllocate( + HANDLE, + notification, + 0, + len(additional_text) + 1, + len(additional_info), + 0) + + # Fill in the header + fill_in_header(notification.notificationHandle, + notification.notificationHeader, + notification_object, notifying_object, vendor_id, + major_id, minor_id, additional_text, event_type, + event_time, additional_info) + + # Fill in security alarm-specific fields + notification.probableCause.contents.value = probable_cause + notification.severity.contents.value = severity + + assign_ntf_value_to_attribute(notification.securityAlarmDetector, + alarm_detector.value, + alarm_detector.value_type) + + assign_ntf_value_to_attribute(notification.serviceUser, + user.value, + user.value_type) + + assign_ntf_value_to_attribute(notification.serviceProvider, + provider.value, + provider.value_type) + + # Send the alarm notification + saNtfNotificationSend(notification.notificationHandle) + + # Free the alarm notification + saNtfNotificationFree(notification.notificationHandle) + + +def send_alarm_notification(vendor_id, major_id, minor_id, severity, + additional_text="", + notification_object="", + notifying_object="", + event_type=saNtf.eSaNtfEventTypeT.SA_NTF_ALARM_PROCESSING, + event_time=saAis.saAis.SA_TIME_UNKNOWN, + additional_info=[]): + ''' Sends an alarm notification''' + + # Create the notification + notification = saNtf.SaNtfAlarmNotificationT() + + saNtfAlarmNotificationAllocate( + HANDLE, + notification, + 0, + len(additional_text) + 1, + len(additional_info), + 0, + 0, + 0, + 0) + + # Fill in the header + fill_in_header(notification.notificationHandle, + notification.notificationHeader, + notification_object, notifying_object, vendor_id, + major_id, minor_id, additional_text, event_type, + event_time, additional_info) + + notification.numMonitoredAttributes = 0 + notification.numSpecificProblems = 0 + notification.numProposedRepairActions = 0 + notification.perceivedSeverity.contents.value = severity + notification.probableCause.contents.value = \ + saNtf.eSaNtfProbableCauseT.SA_NTF_DEGRADED_SIGNAL + + # Send the alarm notification + saNtfNotificationSend(notification.notificationHandle) + + # Free the alarm notification + saNtfNotificationFree(notification.notificationHandle) + + +def subscribe_for_notifications(notification_types=None): + ''' Subscribes for notifications from NTF. The types of notifications to + subscribe to are passed in the notification_types list and + subscriptions are set up for all types if the list is empty + ''' + + filters = [] + + filter_handles = saNtf.SaNtfNotificationTypeFilterHandlesT() + + filter_handles.objectCreateDeleteFilterHandle = saNtf.SaNtfNotificationFilterHandleT(0) + filter_handles.attributeChangeFilterHandle = saNtf.SaNtfNotificationFilterHandleT(0) + filter_handles.stateChangeFilterHandle = saNtf.SaNtfNotificationFilterHandleT(0) + filter_handles.alarmFilterHandle = saNtf.SaNtfNotificationFilterHandleT(0) + filter_handles.securityFilterHandle = saNtf.SaNtfNotificationFilterHandleT(0) + + + # Create and allocate the alarm filter + if not notification_types or \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM in notification_types: + notification_filter = saNtf.SaNtfAlarmNotificationFilterT() + + saNtfAlarmNotificationFilterAllocate(HANDLE, notification_filter, + 0, 0, 0, 0, 0, 0, 0) + + filter_handles.alarmFilterHandle = notification_filter.notificationFilterHandle + + filters.append(notification_filter.notificationFilterHandle) + + # Create and allocate the object create delete filter + if not notification_types or \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_OBJECT_CREATE_DELETE in notification_types: + notification_filter = saNtf.SaNtfObjectCreateDeleteNotificationFilterT() + + saNtfObjectCreateDeleteNotificationFilterAllocate(HANDLE, + notification_filter, + 0, 0, 0, 0, 0) + + filter_handles.objectCreateDeleteFilterHandle = notification_filter.notificationFilterHandle + filters.append(notification_filter.notificationFilterHandle) + + # Create and allocate the attribute change filter + if not notification_types or \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ATTRIBUTE_CHANGE in notification_types: + + notification_filter = saNtf.SaNtfAttributeChangeNotificationFilterT() + + saNtfAttributeChangeNotificationFilterAllocate(HANDLE, + notification_filter, + 0, 0, 0, 0, 0) + + filter_handles.attributeChangeFilterHandle = notification_filter.notificationFilterHandle + + filters.append(notification_filter.notificationFilterHandle) + + # Create and allocate the state change filter + if not notification_types or \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_STATE_CHANGE in notification_types: + + notification_filter = saNtf.SaNtfStateChangeNotificationFilterT() + + saNtfStateChangeNotificationFilterAllocate(HANDLE, + notification_filter, + 0, 0, 0, 0, 0, 0) + + filter_handles.stateChangeFilterHandle = notification_filter.notificationFilterHandle + + filters.append(notification_filter.notificationFilterHandle) + + # Create and allocate the security alarm filter + if not notification_types or \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM in notification_types: + + notification_filter = saNtf.SaNtfSecurityAlarmNotificationFilterT() + + saNtfSecurityAlarmNotificationFilterAllocate(HANDLE, + notification_filter, + 0, 0, 0, 0, 0, 0, 0, 0, 0) + + filter_handles.securityAlarmFilterHandle = notification_filter.notificationFilterHandle + + filters.append(notification_filter.notificationFilterHandle) + + # Create a unique subscription id + sub_id = saNtf.SaNtfSubscriptionIdT(1) + + # Start subscription + saNtfNotificationSubscribe(filter_handles, sub_id) + + # Free up the filters + for filter_handle in filters: + saNtfNotificationFilterFree(filter_handle) + + +def dispatch(mode=saAis.eSaDispatchFlagsT.SA_DISPATCH_ALL): + ''' Invokes NTF callbacks for queued events. The default is to dispatch all + available events + ''' + + saNtfDispatch(HANDLE, mode) + diff --git a/python/samples/README b/python/samples/README --- a/python/samples/README +++ b/python/samples/README @@ -74,6 +74,17 @@ interface-handler: netifaces library to do so. Run 'interface-handler --help' for specific options and arguments. +ntfsend: + The ntfsend sample application is a copy of the ntfsend tool, + implemented in Python. It sends notifications through NTF. Run + 'ntfsend --help' for specific options and arguments. + +ntfsubscribe: + The ntfsubscribe sample application is a copy of the + ntfsubscribe tool, implemented in Python. It listens for + notifications and logs received notifications in the + terminal. Run 'ntfsubscribe --help'. + Logging for all apps/utils goes to /var/log/opensaf/saflog/saLogSystem*.log The IMM OI samples use the classes defined in the classes.xml file. Load it with immcfg -f classes.xml before trying them. diff --git a/python/samples/ntfsend b/python/samples/ntfsend new file mode 100755 --- /dev/null +++ b/python/samples/ntfsend @@ -0,0 +1,251 @@ +#! /usr/bin/env python + +import argparse +import time + +from pyosaf import saNtf, saAis +from pyosaf.utils import ntf + + +def construct_additional_info(additional_info_string): + ''' Constructs an AdditionalInfo instance from the given string. + + The string must be of the format ID,TYPE,VALUE + ''' + + info_id = int(additional_info_string.split(',')[0]) + info_type = int(additional_info_string.split(',')[1]) + info_value = ','.join(additional_info_string.split(',')[2:]) + + return ntf.AdditionalInfo(info_id, info_type, info_value) + + +if __name__ == '__main__': + + # Parse command line arguments + parser = argparse.ArgumentParser( + description='ntfsend is a SAF NTF client used to send a notificaiton.') + + parser.add_argument('--notificationType', '-T', metavar='0x1000...0x5000', + default='0x4000', + help='numeric value of SaNtfNotificationTypeT' + '(obj_create_del=0x1000,attr_ch,state_ch,al,sec_al=0x5000)') + parser.add_argument('--eventType', '-e', metavar='4096...24589', + help='numeric value of SaNtfEventTypeT' + '(SA_NTF_OBJECT_NOTIFICATIONS_START...SA_NTF_HPI_EVENT_OTHER)') + parser.add_argument('--eventTime', '-E', metavar='TIME', + default=saAis.saAis.SA_TIME_UNKNOWN, + help='numeric value of SaTimeT') + parser.add_argument('--notificationClassId', '-c', metavar='VE,MA,MI', + default='162,1,1', + help='vendorid, majorid, minorid') + parser.add_argument('--notificationObject', '-n', metavar='NOT_OBJ', + default="", + help='notification object (string value)') + parser.add_argument('--notifyingObject', '-N', metavar='NOTIFY_OBJ', + default="", + help='notififying object (string value)') + parser.add_argument('--additionalText', '-a', metavar='TEXT', + default="", + help='additional text (string value)') + parser.add_argument('--probableCause', '-p', metavar='0..74', + help='numeric value SaNtfProbableCauseT' + 'SA_NTF_ADAPTER_ERROR to SA_NTF_UNSPECIFIED_REASON') + parser.add_argument('--perceivedSeverity', '-s', metavar='0...5', + type=int, default='4', + help='severity numeric value' + '(clear=0,ind,warn,min,maj,crit=5)') + parser.add_argument('--repeatSends', '-r', metavar='NUM', + default=1, type=int, + help='send the same notifification NUM times') + parser.add_argument('--burstTimeout', '-b', metavar='TIME', + default=0, type=int, + help='send burst of NUM repeatSends ' + '[default: 1] and sleep TIME (usec)' + 'between each burst, will continue for ever') + parser.add_argument('--additionalInfo', '-i', metavar='ID,TYPE,VALUE', + help='additional information' + 'ID: SaNtfElementIdT integer value' + 'TYPE: numeric value SaNtfValueTypeT, only ' + 'SA_NTF_VALUE_STRING=11 is supported') + + args = parser.parse_args() + + # Fill in arguments + vendor_id = int(args.notificationClassId.split(',')[0]) + major_id = int(args.notificationClassId.split(',')[1]) + minor_id = int(args.notificationClassId.split(',')[2]) + + event_time = int(args.eventTime) + + severity = int(args.perceivedSeverity) + + additional_text = args.additionalText + notification_object = args.notificationObject + notifying_object = args.notifyingObject + + # Initialize the NTF library + ntf.initialize() + + # Send the notification + ntf_type = int(args.notificationType, 0) + + if ntf_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_OBJECT_CREATE_DELETE: + + # Create sample attributes + attributes = [] + + attr1 = ntf.Attribute() + + attr1.attribute_id = 1 + attr1.attribute_type = saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT16 + attr1.attribute_value = 23 + + attributes.append(attr1) + + attr2 = ntf.Attribute() + + attr2.attribute_id = 2 + attr2.attribute_type = saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT32 + attr2.attribute_value = -3 + + attributes.append(attr2) + + # Create sample additional info + additional_info = [] + if args.additionalInfo: + additional_info.append(construct_additional_info(args.additionalInfo)) + + # Send the notification + for i in range(0, args.repeatSends): + ntf.send_object_create_notification(vendor_id, + major_id, + minor_id, + additional_text=additional_text, + notification_object=notification_object, + notifying_object=notifying_object, + attributes=attributes, + event_time=event_time, + additional_info=additional_info) + + time.sleep(args.burstTimeout) + + elif ntf_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM: + + # Create security alarm sample fields + + detector = ntf.SecurityAlarmDetector( + value=15, + value_type=saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT32 + ) + + user = ntf.ServiceUser( + value=-2, + value_type=saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT16 + ) + + provider = ntf.ServiceProvider( + value=128, + value_type=saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_UINT32 + ) + + # Send the notification + for i in range(0, args.repeatSends): + ntf.send_security_alarm_notification(vendor_id, major_id, minor_id, severity, + detector, user, provider, + additional_text=additional_text, + notification_object=notification_object, + notifying_object=notifying_object, + event_time=event_time) + + time.sleep(args.burstTimeout) + + elif ntf_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM: + + for i in range(0, args.repeatSends): + ntf.send_alarm_notification(vendor_id, major_id, minor_id, severity, + additional_text=additional_text, + notification_object=notification_object, + notifying_object=notifying_object, + event_time=event_time) + + time.sleep(args.burstTimeout) + + elif ntf_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ATTRIBUTE_CHANGE: + + # Fill in sample attribute changes + + attr0 = ntf.AttributeChange() + + attr0.attribute_id = 0 + attr0.attribute_type = saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT32 + attr0.old_attribute_present = saAis.eSaBoolT.SA_FALSE + attr0.new_attribute_value = 1 + + attr1 = ntf.AttributeChange() + + attr1.attribute_id = 1 + attr1.attribute_type = saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_INT32 + attr1.old_attribute_present = saAis.eSaBoolT.SA_TRUE + attr1.old_attribute_value = 8 + attr1.new_attribute_value = -4 + + changed_attributes = [attr0, attr1] + + # Send the notification + for i in range(0, args.repeatSends): + ntf.send_attribute_change_notification(vendor_id, major_id, minor_id, + additional_text=additional_text, + notification_object=notification_object, + notifying_object=notifying_object, + event_time=event_time, + changed_attributes=changed_attributes) + + time.sleep(args.burstTimeout) + + elif ntf_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_STATE_CHANGE: + + # Fill in sample state changes + changes = [] + + change0 = ntf.StateChange() + + change0.state_id = 1 + change0.old_state_present = False + change0.new_state = 0 + + change1 = ntf.StateChange() + + change1.state_id = 2 + change1.old_state_present = False + change1.new_state = 5 + + change2 = ntf.StateChange() + + change2.state_id = 1 + change2.old_state_present = True + change2.old_state = 0 + change2.new_state = 1 + + change3 = ntf.StateChange() + + change3.state_id = 2 + change3.old_state_present = True + change3.old_state = 5 + change3.new_state = 10 + + changes.append(change0) + changes.append(change1) + changes.append(change2) + changes.append(change3) + + # Send the notification + for i in range(0, args.repeatSends): + ntf.send_state_change_notification(vendor_id, major_id, minor_id, + additional_text=additional_text, + notification_object=notification_object, + notifying_object=notifying_object, + event_time=event_time, + state_changes=changes) + + time.sleep(args.burstTimeout) diff --git a/python/samples/ntfsubscribe b/python/samples/ntfsubscribe new file mode 100755 --- /dev/null +++ b/python/samples/ntfsubscribe @@ -0,0 +1,307 @@ +#! /usr/bin/env python + +import select +import ctypes +import datetime +import argparse + +from pyosaf import saNtf, saAis +from pyosaf.utils import ntf + +def SaNameT_to_string(name): + ''' Converts an instance of SaNameT to a Python string''' + + return ctypes.create_string_buffer(name.value, name.length).value + +def p_char_to_string(p_char, length): + ''' Converts a char pointer with a missing NULL pointer to a string with the + given length''' + + return ctypes.create_string_buffer(p_char, length).value + +def SaTimeT_to_date_string(sa_time): + ''' Returns a string representation for the given SaTimeT instance''' + + milli_seconds = sa_time / 1000000 + + return datetime.datetime.fromtimestamp(milli_seconds/1000).isoformat() + +def print_notification_header(header): + ''' Prints the given notification header''' + + class_id = header.notificationClassId.contents + + print '''eventType = %s +notificationObject = "%s" +notifyingObject = "%s" +notificationClassId = %d.%d.%d (0x0) +additionalText = "%s"''' % ( + saNtf.eSaNtfEventTypeT.whatis(header.eventType.contents.value), + SaNameT_to_string(header.notificationObject.contents), + SaNameT_to_string(header.notifyingObject.contents), + class_id.vendorId, + class_id.majorId, + class_id.minorId, + p_char_to_string(header.additionalText, header.lengthAdditionalText) +) + + +def print_alarm_notification(notification): + ''' Prints the given alarm notification''' + + header = notification.notificationHeader + + print '=== %s - Alarm ===' % SaTimeT_to_date_string(header.eventTime.contents.value) + + print_notification_header(header) + + print 'probableCause = %s' % \ + saNtf.eSaNtfProbableCauseT.whatis(notification.probableCause.contents.value) + print 'perceivedSeverity = %s' % \ + saNtf.eSaNtfSeverityT.whatis(notification.perceivedSeverity.contents.value) + + +def print_object_create_delete_notification(notification): + ''' Prints the given object create delete notification''' + + header = notification.notificationHeader + + print '=== %s - Object Create/Delete ===' % SaTimeT_to_date_string(header.eventTime.contents.value) + + print_notification_header(header) + + print 'sourceIndicator = %s' % \ + saNtf.eSaNtfSourceIndicatorT.whatis(notification.sourceIndicator.contents.value) + + print + + print 'numAttributes: %d' % notification.numAttributes + + for i in range(0, notification.numAttributes): + + c_attribute = notification.objectAttributes[i] + + print '- Attribute ID: %d -' % c_attribute.attributeId + print ' Attribute Type: (%d) %s' % ( + c_attribute.attributeType, + saNtf.eSaNtfValueTypeT.whatis(c_attribute.attributeType) + ) + + print ' Attribute Value: %d' % \ + saNtf.unmarshalSaNtfValue(saAis.BYREF(c_attribute.attributeValue), + c_attribute.attributeType) + + +def print_attribute_change_notification(notification): + ''' Prints the given attribute change notification''' + + header = notification.notificationHeader + + print '=== %s - Attribute Change ===' % SaTimeT_to_date_string(header.eventTime.contents.value) + + print_notification_header(header) + + print 'sourceIndicator = %s' % \ + saNtf.eSaNtfSourceIndicatorT.whatis(notification.sourceIndicator.contents.value) + + print + + print 'numAttributes: %d' % notification.numAttributes + + for i in range(0, notification.numAttributes): + + c_attribute = notification.changedAttributes[i] + + print '''- Attribute ID: %d - + Attribute Type: (%d) %s''' % ( + c_attribute.attributeId, + c_attribute.attributeType, + saNtf.eSaNtfValueTypeT.whatis(c_attribute.attributeType) +) + + if c_attribute.oldAttributePresent: + print ''' Old Attribute Present: Yes + Old Attribute Value: %s''' % \ + saNtf.unmarshalSaNtfValue(saAis.BYREF(c_attribute.oldAttributeValue), + c_attribute.attributeType) + else: + print ' Old Attribute Present: No' + + print ' Attribute Value: %s' % \ + saNtf.unmarshalSaNtfValue(saAis.BYREF(c_attribute.newAttributeValue), + c_attribute.attributeType) + + +def print_state_change_notification(notification): + ''' Prints the given state change notification''' + + header = notification.notificationHeader + + print '=== %s - State Change ===' % SaTimeT_to_date_string(header.eventTime.contents.value) + + print_notification_header(header) + + print 'sourceIndicator = %s' % \ + saNtf.eSaNtfSourceIndicatorT.whatis(notification.sourceIndicator.contents.value) + + print + + i = 0 + for c_state in notification.changedStates: + + if i == notification.numStateChanges: + break + + i = i + 1 + + print '- State ID: %d -' % c_state.stateId + + if c_state.oldStatePresent: + print ' Old State Present: Yes' + print ' Old State: %s' % c_state.oldState + else: + print ' Old State Present: No' + + print ' New State: %s' % c_state.newState + + +def print_security_alarm_notification(notification): + ''' Prints the given security alarm notification''' + + header = notification.notificationHeader + + print '=== %s - Security Alarm ===' % SaTimeT_to_date_string(header.eventTime.contents.value) + + print_notification_header(header) + + print'''probableCause = %s +severity = %s +Security Alarm Detector Type: %d +Security Alarm Detector Value: %d +Service User Type: %d +Service User Value: %d +Service Provider Type: %d +Service Provider Value: %d +''' % ( + saNtf.eSaNtfProbableCauseT.whatis(notification.probableCause.contents.value), + saNtf.eSaNtfSeverityT.whatis(notification.severity.contents.value), + notification.securityAlarmDetector.contents.valueType, + saNtf.unmarshalSaNtfValue(saAis.BYREF(notification.securityAlarmDetector.contents.value), + notification.securityAlarmDetector.contents.valueType), + notification.serviceUser.contents.valueType, + saNtf.unmarshalSaNtfValue(saAis.BYREF(notification.serviceUser.contents.value), + notification.serviceUser.contents.valueType), + notification.serviceProvider.contents.valueType, + saNtf.unmarshalSaNtfValue(saAis.BYREF(notification.serviceProvider.contents.value), + notification.serviceProvider.contents.valueType) +) + + +def notification_received(subscription_id, c_p_notification): + ''' Handle received notifications''' + + notification_type = c_p_notification.contents.notificationType + + print + + if notification_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM: + notification = c_p_notification.contents.notification.alarmNotification + + print_alarm_notification(notification) + + elif notification_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_OBJECT_CREATE_DELETE: + notification = c_p_notification.contents.notification.objectCreateDeleteNotification + + print_object_create_delete_notification(notification) + + elif notification_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ATTRIBUTE_CHANGE: + notification = c_p_notification.contents.notification.attributeChangeNotification + + print_attribute_change_notification(notification) + + elif notification_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_STATE_CHANGE: + notification = c_p_notification.contents.notification.stateChangeNotification + + print_state_change_notification(notification) + + elif notification_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM: + notification = c_p_notification.contents.notification.securityAlarmNotification + + print_security_alarm_notification(notification) + + +if __name__ == '__main__': + + # Parse the parameters + parser = argparse.ArgumentParser( + description='ntfsubscribe is a SAF NTF client used to subscribe for all incoming notifications.') + + parser.add_argument('--timeout', '-t', metavar='TIME', + default=1, + help='timeout (sec) waiting for notification') + + parser.add_argument('--alarm', '-a', + dest='alarm', action='store_true', + help='subscribe for only alarm notifications') + + parser.add_argument('--objectCreateDelete', '-o', + dest='object_create_delete', action='store_true', + help='subscribe for only objectCreateDelete notifications') + + parser.add_argument('--attributeChange', '-c', + dest='attribute_change', action='store_true', + help='subscribe for only attributeChange notifications') + + parser.add_argument('--stateChange', '-s', + dest='state_change', action='store_true', + help='subscribe for only stateChange notifications') + + parser.add_argument('--securityAlarm', '-y', + dest='security_alarm', action='store_true', + help='subscribe for only securityAlarm notifications') + + args = parser.parse_args() + + print args.timeout + + # Initialize the NTF library + ntf.initialize(notification_callback=notification_received) + + # Subscribe for notifications + subscriptions = [] + + if args.object_create_delete: + subscriptions.append(saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_OBJECT_CREATE_DELETE) + + if args.alarm: + subscriptions.append(saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM) + + if args.attribute_change: + subscriptions.append(saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ATTRIBUTE_CHANGE) + + if args.state_change: + subscriptions.append(saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_STATE_CHANGE) + + if args.security_alarm: + subscriptions.append(saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM) + + if subscriptions == []: + ntf.subscribe_for_notifications() + else: + ntf.subscribe_for_notifications(notification_types=subscriptions) + + # Get selection object for the implementer + selection_object = ntf.SELECTION_OBJECT.value + + # Wait for next OI event or one second timeout + inputs = [selection_object] + outputs = [] + + # Loop and wait for notifications + while True: + + readable, writable, exceptional = \ + select.select(inputs, outputs, inputs, args.timeout) + + if selection_object in readable: + ntf.dispatch(saAis.eSaDispatchFlagsT.SA_DISPATCH_ALL) ------------------------------------------------------------------------------ _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel