- Refactor the ntfsend and ntfsubscribe python samples to make use of the new pyosaf utils implementation of enhancement ticket #2602. - Add a new ntfread sample to demonstrate usage of the new NtfReader utils. --- python/samples/ntfread | 411 ++++++++++++++++++++ python/samples/ntfsend | 922 ++++++++++++++++++++++++++++++++------------ python/samples/ntfsubscribe | 795 ++++++++++++++++++++++++-------------- 3 files changed, 1591 insertions(+), 537 deletions(-) create mode 100755 python/samples/ntfread mode change 100644 => 100755 python/samples/ntfsend mode change 100644 => 100755 python/samples/ntfsubscribe
diff --git a/python/samples/ntfread b/python/samples/ntfread new file mode 100755 index 0000000..a70552b --- /dev/null +++ b/python/samples/ntfread @@ -0,0 +1,411 @@ +#! /usr/bin/env python +############################################################################ +# +# (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 +# +############################################################################ +# pylint: disable=unused-argument +""" +ntfread tool used to read alarm and/or security alarm notifications from NTF + +Run ntfread --help/-h for more detail on usage +""" +from __future__ import print_function +import sys +import argparse +from datetime import datetime, tzinfo, timedelta + +from pyosaf import saNtf +from pyosaf.saAis import eSaAisErrorT +from pyosaf.utils.ntf.reader import NtfReader + + +class UTCOffsetTZ(tzinfo): + """ Time zone represented as UTC hour-offset """ + def __init__(self, hour_offset): + """ UTCOffsetTZ constructor """ + self._hour_offset = hour_offset + super(UTCOffsetTZ, self).__init__() + + def utcoffset(self, dt): + """ Return offset of local time from UTC, in minutes east of UTC """ + return timedelta(hours=self._hour_offset) + + def dst(self, dt): + """ Return the daylight saving time (DST) adjustment, in minutes east + of UTC, or None if DST information isn't known + """ + return timedelta(0) + + def tzname(self, dt): + """ Return the time zone name represented in UTC hour-offset format as + 'UTC+/-offset' + """ + if self._hour_offset > 0: + tzname = "UTC+%02d:00" % self._hour_offset + elif self._hour_offset < 0: + tzname = "UTC-%02d:00" % self._hour_offset + else: # hour_offset = 0 + tzname = "UTC" + + return tzname + + +def satime_to_readable_datetime(sa_time, format_str=None): + """ Convert the given SaTimeT time value to readable datetime string + representation in ISO 8601 format + + Args: + sa_time (SaTimeT): SaTimeT time value + format_str (str): Format string for datetime output representation + + Returns: + str: Datetime representation in format specified by format_str, or in + ISO 8601 format 'YYYY-MM-DDTHH:MM:SS' if format_str not provided + """ + time_sec = sa_time / 10**9 # Convert the time from nsec to sec 1000000000 + + # Calculate the UTC offset for time zone information + naive_dt = datetime.fromtimestamp(time_sec) + utc_offset = (naive_dt - datetime.utcfromtimestamp(time_sec)) + hour_offset = utc_offset.total_seconds() // 3600 + utc_offset_tz = UTCOffsetTZ(hour_offset) + + aware_dt = naive_dt.replace(tzinfo=utc_offset_tz) + + if format_str is not None: + return aware_dt.strftime(format_str) + + return aware_dt.isoformat(' ') + + +def _validate_ntf_class_id(arg): + """ Validate the input NtfClassId with format 'VENDOR_ID.MAJOR_ID.MINOR_ID' + + Args: + arg (str): The NtfClassId to validate + + Returns: + SaNtfClassIdT: The validated NtfClassId + """ + if arg.count('.') != 2: + msg = "%r is not in correct format 'VENDOR_ID.MAJOR_ID.MINOR_ID'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split('.')[0] or not arg.split('.')[1] or not arg.split('.')[2]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + # Validate element type + try: + vendor_id = int(arg.split('.')[0]) + major_id = int(arg.split('.')[1]) + minor_id = int(arg.split('.')[2]) + except ValueError: + msg = "%r must consist of all integers" % arg + raise argparse.ArgumentTypeError(msg) + + return saNtf.SaNtfClassIdT(vendor_id, major_id, minor_id) + + +def print_notification_header(header_info): + """ Print information of the header in the received notification + + Args: + header_info (NotificationInfo): NotificationInfo structure containing + information of the notification header + """ + dt_format_str = "%c %Z" + print ('notificationId = %d\n' + 'eventType = %s\n' + 'notificationObject = "%s"\n' + 'notifyingObject = "%s"\n' + 'notificationClassId = %d.%d.%d\n' + 'eventTime = %d (%s)\n' + 'additionalText = "%s"' % + (header_info.notification_id, + saNtf.eSaNtfEventTypeT.whatis(header_info.event_type), + header_info.notification_object, + header_info.notifying_object, + header_info.ntf_class_id.vendorId, + header_info.ntf_class_id.majorId, + header_info.ntf_class_id.minorId, + header_info.event_time, + satime_to_readable_datetime(header_info.event_time, dt_format_str), + header_info.additional_text)) + if header_info.additional_info: + print("numAdditionalInfo = %d" % len(header_info.additional_info)) + for add_info in header_info.additional_info: + print ("- Info ID: %d\n" + " Info Type: %s (%d)\n" + " Info Value: %s" % + (add_info.info_id, + saNtf.eSaNtfValueTypeT.whatis(add_info.info_type), + add_info.info_type, + add_info.info_value)) + print() + + +def print_alarm_notification(notification): + """ Print information of the alarm notification found from reading NTF + + Args: + notification (NotificationInfo): NotificationInfo structure containing + information of the found alarm notification + """ + print("=== %s - Alarm ===" % + satime_to_readable_datetime(notification.event_time)) + print_notification_header(notification) + print("probableCause = %s" % + saNtf.eSaNtfProbableCauseT.whatis(notification.probable_cause)) + print("perceivedSeverity = %s" % + saNtf.eSaNtfSeverityT.whatis(notification.perceived_severity)) + + if args.verbose: + print("trend = %s" % + saNtf.eSaNtfSeverityTrendT.whatis(notification.trend)) + print("thresholdInformation:\n" + "- Threshold ID: %d\n" + " Threshold Value Type: %s (%d)\n" + " Threshold Value: %s\n" + " Threshold Hysteresis: %s\n" + " Observed Value: %s\n" + " Arm Time: %s" % + (notification.threshold_information.threshold_id, + saNtf.eSaNtfValueTypeT.whatis( + notification.threshold_information.threshold_value_type), + notification.threshold_information.threshold_value_type, + notification.threshold_information.threshold_value, + notification.threshold_information.threshold_hysteresis, + notification.threshold_information.observed_value, + satime_to_readable_datetime( + notification.threshold_information.arm_time))) + print("numSpecificProblems = %d" % len(notification.specific_problems)) + for spec_problem in notification.specific_problems: + print("- Problem ID: %d\n" + " Problem Class ID: %d.%d.%d\n" + " Problem Type: %s (%d)\n" + " Problem Value: %s" % + (spec_problem.problem_id, + spec_problem.problem_class_id.vendorId, + spec_problem.problem_class_id.majorId, + spec_problem.problem_class_id.minorId, + saNtf.eSaNtfValueTypeT.whatis(spec_problem.problem_type), + spec_problem.problem_type, spec_problem.problem_value)) + print("numMonitoredAttributes = %d" % + len(notification.monitored_attrs)) + for monitored_attr in notification.monitored_attrs: + print("- Attribute ID: %d\n" + " Attribute Type: %s (%d)\n" + " Attribute Value: %s" % + (monitored_attr.attribute_id, + saNtf.eSaNtfValueTypeT.whatis( + monitored_attr.attribute_type), + monitored_attr.attribute_type, + monitored_attr.attribute_value)) + print("numProposedRepairActions = %d" % + len(notification.proposed_repair_actions)) + for repair_action in notification.proposed_repair_actions: + print("- Action ID: %d\n" + " Action Value Type: %s (%d)\n" + " Action Value: %s" % + (repair_action.action_id, + saNtf.eSaNtfValueTypeT.whatis( + repair_action.action_value_type), + repair_action.action_value_type, + repair_action.action_value)) + + +def print_security_alarm_notification(notification): + """ Print information of the security alarm notification found from reading + NTF + + Args: + notification (NotificationInfo): NotificationInfo structure containing + information of the found security alarm notification + """ + print("=== %s - Security Alarm ===" % + satime_to_readable_datetime(notification.event_time)) + print_notification_header(notification) + print("probableCause = %s\n" + "severity = %s\n" + "Security Alarm Detector Type: %s (%d)\n" + "Security Alarm Detector Value: %s\n" + "Service User Type: %s (%d)\n" + "Service User Value: %s\n" + "Service Provider Type: %s (%d)\n" + "Service Provider Value: %s" % + (saNtf.eSaNtfProbableCauseT.whatis(notification.probable_cause), + saNtf.eSaNtfSeverityT.whatis(notification.severity), + saNtf.eSaNtfValueTypeT.whatis( + notification.security_alarm_detector.value_type), + notification.security_alarm_detector.value_type, + notification.security_alarm_detector.value, + saNtf.eSaNtfValueTypeT.whatis(notification.service_user.value_type), + notification.service_user.value_type, + notification.service_user.value, + saNtf.eSaNtfValueTypeT.whatis( + notification.service_provider.value_type), + notification.service_provider.value_type, + notification.service_provider.value)) + + +# Define command line arguments for ntfread +parser = argparse.ArgumentParser( + description='A SAF NTF client used to read alarm and/or security alarm ' + 'notifications from NTF,\nwhich match optionally provided ' + 'filter argument(s).\nWithout any argument, all alarm and ' + 'security alarm notifications will be read by default.', + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument('--alarmOnly', '-a', action='store_true', + help='read alarm notifications only') +parser.add_argument('--securityAlarmOnly', '-y', action='store_true', + help='read security alarm notifications only') +parser.add_argument('--searchMode', '-m', metavar='1...7', type=int, + choices=range(1, 8), + help='numeric value of SaNtfSearchModeT\n' + '(SA_NTF_SEARCH_BEFORE_OR_AT_TIME...' + 'SA_NTF_SEARCH_ONLY_FILTER)') +parser.add_argument('--eventTime', '-T', metavar='TIME', type=int, + help='notification time (in nanosecond) to search for') +parser.add_argument('--notificationId', '-i', metavar='NOTIF_ID', type=int, + help='notification id to search for') +parser.add_argument('--alarmEventTypes', '-e', metavar='16384...16389', + type=int, nargs='+', choices=range(16384, 16390), + help='numeric value of alarm SaNtfEventTypeT\n' + '(SA_NTF_ALARM_NOTIFICATIONS_START...' + 'SA_NTF_ALARM_ENVIRONMENT)') +parser.add_argument('--securityAlarmEventTypes', '-E', metavar='20480...20485', + type=int, nargs='+', choices=range(20480, 20486), + help='numeric value of security alarm SaNtfEventTypeT\n' + '(SA_NTF_SECURITY_ALARM_NOTIFICATIONS_START...' + 'SA_NTF_TIME_VIOLATION)') +parser.add_argument('--notificationClassIds', '-c', + type=_validate_ntf_class_id, + metavar='VENDOR_ID.MAJOR_ID.MINOR_ID', nargs='+', + help='notification class identifier\n' + 'VENDOR_ID: SaUint32T integer value\n' + 'MAJOR_ID: SaUint16T integer value\n' + 'MINOR_ID: SaUint16T integer value') +parser.add_argument('--notificationObjects', '-n', metavar='NOTIFICATION_OBJ', + type=str, nargs='+', + help='notification object (string value)') +parser.add_argument('--notifyingObjects', '-N', metavar='NOTIFYING_OBJ', + type=str, nargs='+', + help='notifying object (string value)') +parser.add_argument('--probableCauses', '-p', metavar='0...74', + type=int, nargs='+', choices=range(75), + help='numeric value of SaNtfProbableCauseT\n' + '(SA_NTF_ADAPTER_ERROR...SA_NTF_UNSPECIFIED_REASON)') +parser.add_argument('--perceivedSeverities', '-s', metavar='0...5', type=int, + nargs='+', choices=range(6), + help='numeric value of alarm SaNtfSeverityT\n' + '(clear=0,ind,warn,min,maj,critical=5)') +parser.add_argument('--trends', '-t', metavar='0...2', type=int, + nargs='+', choices=range(3), + help='numeric value of SaNtfSeverityTrendT') +parser.add_argument('--severities', '-S', metavar='0...5', type=int, + nargs='+', choices=range(6), + help='numeric value of security alarm SaNtfSeverityT\n' + '(clear=0,ind,warn,min,maj,critical=5)') +parser.add_argument('--searchYounger', '-g', action='store_true', + help='SA_NTF_SEARCH_YOUNGER\n' + '(search in descending chronological order w.r.t ' + 'previously read notification)') +parser.add_argument('--verbose', '-v', action='store_true', + help='print all information from alarm notifications') + +# Parse command line arguments for user input, if any +args = parser.parse_args() + +notification_type = None +if args.alarmOnly and args.securityAlarmOnly: + print ("ERROR: Cannot use both --alarmOnly and --securityAlarmOnly\n") + sys.exit(0) +elif args.alarmOnly: + notification_type = saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM +elif args.securityAlarmOnly: + notification_type = \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM + +search_mode = args.searchMode +event_time = args.eventTime if args.eventTime is not None else 0 +notif_id = args.notificationId if args.notificationId is not None else 0 + +search_criteria = None +if search_mode is not None: + search_criteria = \ + saNtf.SaNtfSearchCriteriaT(search_mode, event_time, notif_id) + +event_types = args.alarmEventTypes +if args.securityAlarmEventTypes is not None: + if event_types is not None: + for evt_type in args.securityAlarmEventTypes: + event_types.append(evt_type) + else: + event_types = args.securityAlarmEventTypes + +# Initialize an NTF reader +reader = NtfReader() +init_rc = reader.init() +if init_rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: saNtfInitialize FAILED, rc = %s\n" % + eSaAisErrorT.whatis(init_rc)) + sys.exit(1) + +# Set notification read filter values, if any, provided by the users +if search_criteria is not None: + reader.set_search_criteria(search_criteria) +if args.searchYounger: + reader.set_search_direction( + saNtf.eSaNtfSearchDirectionT.SA_NTF_SEARCH_YOUNGER) +if event_types is not None: + reader.set_filter_event_types(event_types) +if args.notificationClassIds is not None: + reader.set_filter_ntf_class_ids(args.notificationClassIds) +if args.notificationObjects is not None: + reader.set_filter_notification_objects(args.notificationObjects) +if args.notifyingObjects is not None: + reader.set_filter_notifying_objects(args.notifyingObjects) +if args.probableCauses is not None: + reader.set_filter_probable_causes(args.probableCauses) +if args.perceivedSeverities is not None: + reader.set_filter_perceived_severities(args.perceivedSeverities) +if args.trends is not None: + reader.set_filter_trends(args.trends) +if args.severities is not None: + reader.set_filter_severities(args.severities) + +# Start reading notifications +if notification_type is not None: + rc = reader.read([notification_type]) +else: + rc = reader.read() + +if rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: Reading notifications FAILED, rc = %s\n" % + eSaAisErrorT.whatis(rc)) + sys.exit(1) + +# Print out the found notifications +for notif_type, notif_info in reader: + print() + if notif_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM: + print_alarm_notification(notif_info) + else: + print_security_alarm_notification(notif_info) + print() + +# Finalize the reader +reader.finalize() diff --git a/python/samples/ntfsend b/python/samples/ntfsend old mode 100644 new mode 100755 index c31a9ba..f36cbcd --- a/python/samples/ntfsend +++ b/python/samples/ntfsend @@ -1,251 +1,679 @@ #! /usr/bin/env python - +############################################################################ +# +# (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 +# +############################################################################ +""" ntfsend tool used to send a type of NTF notification + +Run ntfsend --help/-h for more detail on usage +""" +from __future__ import print_function +import sys 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) +from pyosaf import saNtf +from pyosaf.saAis import eSaAisErrorT +from pyosaf.utils.ntf import agent as ntf +from pyosaf.utils.ntf.producer import NtfProducer + +NOTIFICATIONS_TYPE_MASK = saNtf.saNtf.SA_NTF_NOTIFICATIONS_TYPE_MASK + + +class InputValidation(object): + """ This class consists of methods to validate different types of input + argument for the ntfsend tool + """ + @staticmethod + def validate_ntf_class_id(arg): + """ Validate the input NtfClassId with format + 'VENDOR_ID.MAJOR_ID.MINOR_ID' + + Args: + arg (str): The NtfClassId to validate + + Returns: + SaNtfClassIdT: The validated NtfClassId + """ + if arg.count('.') != 2: + msg = "%r is not in correct format " \ + "'VENDOR_ID.MAJOR_ID.MINOR_ID'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split('.')[0] or not arg.split('.')[1] \ + or not arg.split('.')[2]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + # Validate element type + try: + vendor_id = int(arg.split('.')[0]) + major_id = int(arg.split('.')[1]) + minor_id = int(arg.split('.')[2]) + except ValueError: + msg = "%r must consist of all integers" % arg + raise argparse.ArgumentTypeError(msg) + + return saNtf.SaNtfClassIdT(vendor_id, major_id, minor_id) + + @staticmethod + def validate_id_type_value(arg): + """ Validate the input argument with format 'ID,TYPE,VALUE' + + Args: + arg (str): The argument to validate + + Returns: + tuple: The validated argument as (ID, TYPE, VALUE) + """ + if arg.count(',') != 2: + msg = "%r is not in correct format 'ID,TYPE,VALUE'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split(',')[0] or not arg.split(',')[1] \ + or not arg.split(',')[2]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + # Validate element type + try: + _id = int(arg.split(',')[0]) + except ValueError: + msg = "%r - ID must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + + try: + _type = int(arg.split(',')[1]) + if _type not in saNtf.eSaNtfValueTypeT.reverse_lookup: + msg = "%r - TYPE is not a valid SaNtfValueTypeT type" % arg + raise argparse.ArgumentTypeError(msg) + except ValueError: + msg = "%r - TYPE must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + + _value = arg.split(',')[2] + + return _id, _type, _value + + @staticmethod + def validate_type_value(arg): + """ Validate the input argument with format 'TYPE,VALUE' + + Args: + arg (str): The argument to validate + + Returns: + tuple: The validated argument as (TYPE, VALUE) + """ + if arg.count(',') != 1: + msg = "%r is not in correct format 'TYPE,VALUE'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split(',')[0] or not arg.split(',')[1]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + # Validate TYPE element + try: + _type = int(arg.split(',')[0]) + if _type not in saNtf.eSaNtfValueTypeT.reverse_lookup: + msg = "%r - TYPE is not a valid SaNtfValueTypeT type" % arg + raise argparse.ArgumentTypeError(msg) + except ValueError: + msg = "%r - TYPE must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + + _value = arg.split(',')[1] + + return _type, _value + + @staticmethod + def validate_changed_attribute(arg): + """ Validate the input changedAttributes argument with format + 'ID,TYPE,OLD_PRESENT,OLD_VAL,NEW_VAL' + + Args: + arg (str): The changedAttributes argument to validate + + Returns: + tuple: The validated changedAttributes argument as + (ID, TYPE, OLD_PRESENT, OLD_VALUE, NEW_VALUE) + """ + if arg.count(',') != 4: + msg = "%r is not in correct format " \ + "'ID,TYPE,OLD_PRESENT,OLD_VAL,NEW_VAL'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split(',')[0] or not arg.split(',')[1] \ + or not arg.split(',')[2] or not arg.split(',')[4]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + # Validate element type + try: + _id = int(arg.split(',')[0]) + except ValueError: + msg = "%r - ID must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + + try: + _type = int(arg.split(',')[1]) + if _type not in saNtf.eSaNtfValueTypeT.reverse_lookup: + msg = "%r - TYPE is not a valid SaNtfValueTypeT type" % arg + raise argparse.ArgumentTypeError(msg) + except ValueError: + msg = "%r - TYPE must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + + if arg.split(',')[2] not in ['True', 'False']: + msg = "%r - OLD_PRESENT must be either 'True' or 'False'" % arg + raise argparse.ArgumentTypeError(msg) + _old_present = True if arg.split(',')[2] == 'True' else False + + _old_value = arg.split(',')[3] + if _old_present and not _old_value: + msg = "%r - OLD_VAL is missing for OLD_PRESENT=True" % arg + raise argparse.ArgumentTypeError(msg) + + _new_value = arg.split(',')[4] + + return _id, _type, _old_present, _old_value, _new_value + + @staticmethod + def validate_changed_state(arg): + """ Validate the input changedStates argument with format + 'ID,OLD_PRESENT,OLD_STATE,NEW_STATE' + + Args: + arg (str): The changedStates argument to validate + + Returns: + tuple: The validated changedStates argument as + (ID, OLD_PRESENT, OLD_STATE, NEW_STATE) + """ + if arg.count(',') != 3: + msg = "%r is not in correct format " \ + "'ID,OLD_PRESENT,OLD_STATE,NEW_STATE'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split(',')[0] or not arg.split(',')[1] \ + or not arg.split(',')[3]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + # Validate element type + try: + _id = int(arg.split(',')[0]) + except ValueError: + msg = "%r - ID must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + + if arg.split(',')[1] not in ['True', 'False']: + msg = "%r - OLD_PRESENT must be either 'True' or 'False'" % arg + raise argparse.ArgumentTypeError(msg) + _old_present = True if arg.split(',')[1] == 'True' else False + + if _old_present: + try: + if not arg.split(',')[2]: + msg = "%r - OLD_STATE is missing for " \ + "OLD_PRESENT=True" % arg + raise argparse.ArgumentTypeError(msg) + _old_state = int(arg.split(',')[2]) + except ValueError: + msg = "%r - OLD_STATE must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + else: + _old_state = arg.split(',')[2] + + try: + _new_state = int(arg.split(',')[3]) + except ValueError: + msg = "%r - NEW_STATE must be an integer" % arg + raise argparse.ArgumentTypeError(msg) + + return _id, _old_present, _old_state, _new_state + + @staticmethod + def validate_specific_problem(arg): + """ Validate the input specificProblems argument with format + 'ID,TYPE,VALUE[,VENDOR_ID.MAJOR_ID.MINOR_ID]' + + Args: + arg (str): The specificProblems argument to validate + + Returns: + tuple: The validated specificProblems argument as + (ID, TYPE, VALUE, SaNtfClassIdT) if problemClassId is provided, + or (ID, TYPE, VALUE, None) if problemClassId is not provided + """ + if arg.count(',') < 2 or arg.count(',') > 3: + msg = "%r is not in correct format " \ + "'ID,TYPE,VALUE[,VENDOR_ID.MAJOR_ID.MINOR_ID]'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split(',')[0] or not arg.split(',')[1] \ + or not arg.split(',')[2]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + arg_list = arg.split(',') + # Validate the required ID,TYPE,VALUE part + required_part = ','.join(arg_list[:3]) + _id, _type, _value = \ + InputValidation.validate_id_type_value(required_part) + + # Validate the problemClassId part, if provided + if len(arg_list) == 4 and arg_list[3]: + _class_id = InputValidation.validate_ntf_class_id(arg_list[3]) + else: + _class_id = None + + return _id, _type, _value, _class_id + + @staticmethod + def validate_threshold_information(arg): + """ Validate the input thresholdInformation argument with format + 'ID,TYPE,THRES_VALUE,HYST,OBSRV_VALUE[,ARM_TIME]' + + Args: + arg (str): The thresholdInformation argument to validate + + Returns: + tuple: The validated thresholdInformation argument as + (ID, TYPE, THRES_VALUE, HYST, OBSRV_VALUE, ARM_TIME) if + armTime is provided, or + (ID, TYPE, THRES_VALUE, HYST, OBSRV_VALUE, CURRENT_TIME) if + armTime is not provided + """ + if arg.count(',') < 4 or arg.count(',') > 5: + msg = "%r is not in correct format " \ + "'ID,TYPE,THRES_VALUE,HYST,OBSRV_VALUE[,ARM_TIME]'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split(',')[0] or not arg.split(',')[1] \ + or not arg.split(',')[2] or not arg.split(',')[3] \ + or not arg.split(',')[4]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + arg_list = arg.split(',') + # Validate the required ID,TYPE,VALUE part + required_part = ','.join(arg_list[:3]) + _id, _type, _thres_value = \ + InputValidation.validate_id_type_value(required_part) + + _thres_hyst = arg_list[3] + _obsrv_value = arg_list[4] + + if len(arg_list) == 6 and arg_list[5]: + _arm_time = arg_list[5] + else: + _arm_time = int(time.time() * 10**9) + + return _id, _type, _thres_value, _thres_hyst, _obsrv_value, _arm_time + + +def fill_notification_header(): + """ Fill the notification header with user-provided or default values """ + producer.set_event_type(event_type) + if args.notificationObject is not None: + producer.set_notification_object(args.notificationObject) + if args.notifyingObject is not None: + producer.set_notifying_object(args.notifyingObject) + if args.notificationClassId is not None: + producer.set_class_id(args.notificationClassId) + if args.eventTime is not None: + producer.set_event_time(args.eventTime) + if args.additionalText is not None: + producer.set_additional_text(args.additionalText) + if additional_info: + producer.set_additional_info(additional_info) + + +def send_notification(notif_type_desc): + """ Send notification(s) of a specific type + + Args: + notif_type_desc (str): Type of notification to send + """ + ntf_send = {'Object Create/Delete Notification': + producer.send_object_create_delete_notification, + 'Attribute Change Notification': + producer.send_attribute_change_notification, + 'State Change Notification': + producer.send_state_change_notification, + 'Alarm Notification': + producer.send_alarm_notification, + 'Security Alarm Notification': + producer.send_security_alarm_notification} + + repeat_count = 0 + if args.burstTimeout: + print("*** Send burst of %d notifications every %4.3f seconds ***\n" % + (args.repeatSends, (args.burstTimeout / 1000000.0))) + while True: + try: + # Send the notification for 'repeatSends' times + for _ in range(args.repeatSends): + send_rc = ntf_send[notif_type_desc]() + if send_rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: ntfsend FAILED, rc = %s\n" % + eSaAisErrorT.whatis(send_rc)) + sys.exit(1) + repeat_count += 1 + print("Send %s successfully! send_count=%d" % + (notif_type_desc, repeat_count)) + print() + # Keep sending the same notification forever if burstTimeout is set + if not args.burstTimeout: + break + time.sleep(args.burstTimeout / 1000000.0) + except KeyboardInterrupt: + sys.exit(0) + + +# Define command line arguments for ntfsend +parser = argparse.ArgumentParser( + description='A SAF NTF client used to send notifications.\nWithout any ' + 'argument, a default alarm notification will be sent.', + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument('--notificationType', '-T', metavar='0x1000...0x5000', + default='0x4000', choices=['0x1000', '0x2000', '0x3000', + '0x4000', '0x5000'], + help='hexadecimal value of SaNtfNotificationTypeT\n' + '(obj_create_delete=0x1000,attr_change,state_change,' + 'alarm,sec_alarm=0x5000)') +parser.add_argument('--eventType', '-e', metavar='4096...20485', + type=int, default=16384, + choices=sorted(saNtf.eSaNtfEventTypeT.reverse_lookup)[:22], + help='numeric value of SaNtfEventTypeT\n' + '(SA_NTF_OBJECT_NOTIFICATIONS_START...' + 'SA_NTF_TIME_VIOLATION)') +parser.add_argument('--eventTime', '-E', metavar='TIME', type=int, + help='numeric value of SaTimeT in nanosecond') +parser.add_argument('--notificationClassId', '-c', + type=InputValidation.validate_ntf_class_id, + metavar='VENDOR_ID.MAJOR_ID.MINOR_ID', + help='notification class identifier\n' + 'VENDOR_ID: SaUint32T integer value\n' + 'MAJOR_ID: SaUint16T integer value\n' + 'MINOR_ID: SaUint16T integer value') +parser.add_argument('--notificationObject', '-n', metavar='NOTIFICATION_OBJ', + type=str, help='notification object (string value)') +parser.add_argument('--notifyingObject', '-N', metavar='NOTIFYING_OBJ', + type=str, help='notifying object (string value)') +parser.add_argument('--additionalText', '-a', metavar='TEXT', type=str, + help='additional text (string value)') +parser.add_argument('--additionalInfo', '-i', metavar='ID,TYPE,VALUE', + type=InputValidation.validate_id_type_value, nargs='+', + help='additional information\n' + 'ID: SaNtfElementIdT integer value\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: additional info value') +parser.add_argument('--sourceIndicator', '-I', metavar='1...3', + type=int, choices=range(1, 4), + help='numeric value of SaNtfSourceIndicatorT\n' + '(SA_NTF_OBJECT_OPERATION...' + 'SA_NTF_UNKNOWN_OPERATION)') +parser.add_argument('--objectAttributes', metavar='ID,TYPE,VALUE', + type=InputValidation.validate_id_type_value, nargs='+', + help='object create/delete attributes\n' + 'ID: SaNtfElementIdT integer value\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: object attribute value') +parser.add_argument('--changedAttributes', + metavar='ID,TYPE,OLD_PRESENT,OLD_VALUE,NEW_VALUE', + type=InputValidation.validate_changed_attribute, nargs='+', + help='changed attributes of AttributeChange notification\n' + 'ID: SaNtfElementIdT integer value\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'OLD_PRESENT: boolean value (True or False)\n' + 'OLD_VALUE: old attribute value ' + '(ignored if OLD_PRESENT=False)\n' + 'NEW_VALUE: new attribute value') +parser.add_argument('--changedStates', + metavar='ID,OLD_PRESENT,OLD_STATE,NEW_STATE', + type=InputValidation.validate_changed_state, nargs='+', + help='changed states of StateChange notification\n' + 'ID: SaNtfElementIdT integer value\n' + 'OLD_PRESENT: boolean value (True or False)\n' + 'OLD_STATE: SaUint16T integer value ' + '(ignored if OLD_PRESENT=False)\n' + 'NEW_STATE: SaUint16T integer value') +parser.add_argument('--probableCause', '-p', metavar='0...74', + type=int, choices=range(75), + help='numeric value of SaNtfProbableCauseT\n' + '(SA_NTF_ADAPTER_ERROR...SA_NTF_UNSPECIFIED_REASON)') +parser.add_argument('--perceivedSeverity', '-s', metavar='0...5', + type=int, choices=range(6), + help='numeric value of SaNtfSeverityT\n' + '(SA_NTF_SEVERITY_CLEARED...' + 'SA_NTF_SEVERITY_CRITICAL)') +parser.add_argument('--trend', '-t', metavar='0...2', type=int, + default=1, choices=range(3), + help='numeric value of SaNtfSeverityTrendT\n' + '(SA_NTF_TREND_MORE_SEVERE...' + 'SA_NTF_TREND_LESS_SEVERE)') +parser.add_argument('--monitoredAttributes', metavar='ID,TYPE,VALUE', + type=InputValidation.validate_id_type_value, nargs='+', + help='monitored attributes of alarm notification\n' + 'ID: SaNtfElementIdT integer value\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: monitored attribute value') +parser.add_argument('--specificProblems', + metavar='ID,TYPE,VALUE[,VENDOR_ID.MAJOR_ID.MINOR_ID]', + type=InputValidation.validate_specific_problem, nargs='+', + help='specific problems of alarm notification ' + '(the problemClassId is optional)\n' + 'ID: SaNtfElementIdT integer value\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: specific problem value\n' + 'VENDOR_ID: SaUint32T integer value\n' + 'MAJOR_ID: SaUint16T integer value\n' + 'MINOR_ID: SaUint16T integer value') +parser.add_argument('--thresholdInformation', + metavar='ID,TYPE,THRES_VALUE,HYST,OBSRV_VALUE[,ARM_TIME]', + type=InputValidation.validate_threshold_information, + help='threshold information of alarm notification ' + '(the armTime is optional)\n' + 'ID: SaNtfElementIdT integer value\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'THRES_VALUE: threshold value\n' + 'HYST: threshold hysteresis value\n' + 'OBSRV_VALUE: observed value\n' + 'ARM_TIME: arm time value in nanosecond') +parser.add_argument('--proposedRepairActions', metavar='ID,TYPE,VALUE', + type=InputValidation.validate_id_type_value, nargs='+', + help='proposed repair actions of alarm notification\n' + 'ID: SaNtfElementIdT integer value\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: proposed repair action value') +parser.add_argument('--severity', '-S', metavar='1...5', + type=int, choices=range(1, 6), + help='numeric value of SaNtfSeverityT for security alarm\n' + '(SA_NTF_SEVERITY_INDETERMINATE...' + 'SA_NTF_SEVERITY_CRITICAL)') +parser.add_argument('--securityAlarmDetector', metavar='TYPE,VALUE', + type=InputValidation.validate_type_value, + help='security alarm detector of security alarm ' + 'notification\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: security alarm detector value') +parser.add_argument('--serviceUser', metavar='TYPE,VALUE', + type=InputValidation.validate_type_value, + help='service user of security alarm notification\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: service user value') +parser.add_argument('--serviceProvider', metavar='TYPE,VALUE', + type=InputValidation.validate_type_value, + help='service provider of security alarm notification\n' + 'TYPE: numeric value of SaNtfValueTypeT\n' + 'VALUE: service provider value') +parser.add_argument('--repeatSends', '-r', metavar='NUM', default=1, type=int, + help='send the same notification 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)\n' + 'between each burst, will continue forever') + +# Parse command line arguments for user input, if any +# Default values will be used otherwise +args = parser.parse_args() + +notification_type = int(args.notificationType, 0) +event_type = args.eventType +if (event_type & NOTIFICATIONS_TYPE_MASK) != notification_type: + print("ERROR: Either eventType or notificationType is missing, or they " + "do not correspond with each other\n") + sys.exit(0) + +additional_info = [] +if args.additionalInfo is not None: + for add_info in args.additionalInfo: + info_id = add_info[0] + info_type = add_info[1] + info_value = add_info[2] + additional_info.append( + ntf.AdditionalInfo(info_id, info_type, info_value)) + +# Initialize an NTF producer +producer = NtfProducer() +init_rc = producer.init() +if init_rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: saNtfInitialize FAILED, rc = %s\n" % + eSaAisErrorT.whatis(init_rc)) + sys.exit(1) + +# Fill the notification header with user-provided or default values +fill_notification_header() + +if notification_type \ + == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_OBJECT_CREATE_DELETE: + if args.sourceIndicator is not None: + producer.set_source_indicator(args.sourceIndicator) + if args.objectAttributes is not None: + obj_attributes = [] + for obj_attr in args.objectAttributes: + attr_id = obj_attr[0] + attr_type = obj_attr[1] + attr_value = obj_attr[2] + obj_attributes.append( + ntf.Attribute(attr_id, attr_type, attr_value)) + producer.set_object_attributes(obj_attributes) + # Send object create/delete notification + send_notification("Object Create/Delete Notification") + +elif notification_type \ + == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ATTRIBUTE_CHANGE: + if args.sourceIndicator is not None: + producer.set_source_indicator(args.sourceIndicator) + if args.changedAttributes is not None: + changed_attributes = [] + for ch_attr in args.changedAttributes: + ch_attr_id = ch_attr[0] + ch_attr_type = ch_attr[1] + old_attr_present = ch_attr[2] + old_attr_value = ch_attr[3] + new_attr_value = ch_attr[4] + changed_attributes.append( + ntf.AttributeChange(ch_attr_id, ch_attr_type, new_attr_value, + old_attr_present, old_attr_value)) + producer.set_changed_attributes(changed_attributes) + # Send attribute change notification + send_notification("Attribute Change Notification") + +elif notification_type \ + == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_STATE_CHANGE: + if args.sourceIndicator is not None: + producer.set_source_indicator(args.sourceIndicator) + if args.changedStates is not None: + state_changes = [] + for ch_state in args.changedStates: + state_id = ch_state[0] + old_state_present = ch_state[1] + old_state = ch_state[2] + new_state = ch_state[3] + state_changes.append(ntf.StateChange(state_id, new_state, + old_state_present, old_state)) + producer.set_state_changes(state_changes) + # Send state change notification + send_notification("State Change Notification") + +elif notification_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM: + if args.probableCause is not None: + producer.set_probable_cause(args.probableCause) + if args.perceivedSeverity is not None: + producer.set_perceived_severity(args.perceivedSeverity) + if args.trend is not None: + producer.set_trend(args.trend) + if args.monitoredAttributes is not None: + monitored_attrs = [] + for mon_attr in args.monitoredAttributes: + mon_attr_id = mon_attr[0] + mon_attr_type = mon_attr[1] + mon_attr_value = mon_attr[2] + monitored_attrs.append( + ntf.Attribute(mon_attr_id, mon_attr_type, mon_attr_value)) + producer.set_monitored_attributes(monitored_attrs) + if args.specificProblems is not None: + specific_problems = [] + for problem in args.specificProblems: + prob_id = problem[0] + prob_type = problem[1] + prob_value = problem[2] + prob_class_id = problem[3] + specific_problems.append( + ntf.SpecificProblem(prob_id, prob_class_id, + prob_type, prob_value)) + producer.set_specific_problems(specific_problems) + if args.thresholdInformation is not None: + threshold_id = args.thresholdInformation[0] + threshold_type = args.thresholdInformation[1] + threshold_value = args.thresholdInformation[2] + threshold_hysteresis = args.thresholdInformation[3] + observed_value = args.thresholdInformation[4] + arm_time = args.thresholdInformation[5] + threshold_info = \ + ntf.ThresholdInformation(threshold_id, threshold_type, + threshold_value, threshold_hysteresis, + observed_value, arm_time) + producer.set_threshold_information(threshold_info) + if args.proposedRepairActions is not None: + proposed_repair_actions = [] + for repair_action in args.proposedRepairActions: + action_id = repair_action[0] + action_type = repair_action[1] + action_value = repair_action[2] + proposed_repair_actions.append( + ntf.ProposedRepairAction(action_id, action_type, action_value)) + producer.set_proposed_repair_actions(proposed_repair_actions) + # Send alarm notification + send_notification("Alarm Notification") + +elif notification_type \ + == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM: + if args.probableCause is not None: + producer.set_probable_cause(args.probableCause) + if args.severity is not None: + producer.set_severity(args.severity) + if args.securityAlarmDetector is not None: + sec_alarm_detector = \ + ntf.SecurityAlarmDetector(args.securityAlarmDetector[1], + args.securityAlarmDetector[0]) + producer.set_security_alarm_detector(sec_alarm_detector) + if args.serviceUser is not None: + srv_user = ntf.ServiceUser(args.serviceUser[1], args.serviceUser[0]) + producer.set_service_user(srv_user) + if args.serviceProvider is not None: + srv_provider = ntf.ServiceProvider(args.serviceProvider[1], + args.serviceProvider[0]) + producer.set_service_provider(srv_provider) + # Send security alarm notification + send_notification("Security Alarm Notification") diff --git a/python/samples/ntfsubscribe b/python/samples/ntfsubscribe old mode 100644 new mode 100755 index b885815..dc78825 --- a/python/samples/ntfsubscribe +++ b/python/samples/ntfsubscribe @@ -1,307 +1,522 @@ #! /usr/bin/env python - +############################################################################ +# +# (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 +# +############################################################################ +# pylint: disable=unused-argument +""" +ntfsubscribe tool used to subscribe for incoming notifications from NTF + +Run ntfsubscribe --help/-h for more detail on usage +""" +from __future__ import print_function +import sys 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, - header.additionalText[0: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) +from datetime import datetime, tzinfo, timedelta + +from pyosaf import saNtf +from pyosaf.saAis import eSaAisErrorT, eSaDispatchFlagsT +from pyosaf.utils.ntf import agent as ntf +from pyosaf.utils.ntf.subscriber import NtfSubscriber + + +class UTCOffsetTZ(tzinfo): + """ Time zone represented as UTC hour-offset """ + def __init__(self, hour_offset): + """ UTCOffsetTZ constructor """ + self._hour_offset = hour_offset + super(UTCOffsetTZ, self).__init__() + + def utcoffset(self, dt): + """ Return offset of local time from UTC, in minutes east of UTC """ + return timedelta(hours=self._hour_offset) + + def dst(self, dt): + """ Return the daylight saving time (DST) adjustment, in minutes east + of UTC, or None if DST information isn't known + """ + return timedelta(0) + + def tzname(self, dt): + """ Return the time zone name represented in UTC hour-offset format as + 'UTC+/-offset' + """ + if self._hour_offset > 0: + tzname = "UTC+%02d:00" % self._hour_offset + elif self._hour_offset < 0: + tzname = "UTC-%02d:00" % self._hour_offset + else: # hour_offset = 0 + tzname = "UTC" + + return tzname + + +def satime_to_readable_datetime(sa_time, format_str=None): + """ Convert the given SaTimeT time value to readable datetime string + representation in ISO 8601 format + + Args: + sa_time (SaTimeT): SaTimeT time value + format_str (str): Format string for datetime output representation + + Returns: + str: Datetime representation in format specified by format_str, or in + ISO 8601 format 'YYYY-MM-DDTHH:MM:SS' if format_str not provided + """ + time_sec = sa_time / 10**9 # Convert the time from nsec to sec 1000000000 + + # Calculate the UTC offset for time zone information + naive_dt = datetime.fromtimestamp(time_sec) + utc_offset = (naive_dt - datetime.utcfromtimestamp(time_sec)) + hour_offset = utc_offset.total_seconds() // 3600 + utc_offset_tz = UTCOffsetTZ(hour_offset) + + aware_dt = naive_dt.replace(tzinfo=utc_offset_tz) + + if format_str is not None: + return aware_dt.strftime(format_str) + + return aware_dt.isoformat(' ') + + +def _validate_ntf_class_id(arg): + """ Validate the NtfClassId filter argument with format + 'VENDOR_ID.MAJOR_ID.MINOR_ID' + + Args: + arg (str): The NtfClassId to validate + + Returns: + SaNtfClassIdT: The validated NtfClassId + """ + if arg.count('.') != 2: + msg = "%r is not in correct format " \ + "'VENDOR_ID.MAJOR_ID.MINOR_ID'" % arg + raise argparse.ArgumentTypeError(msg) + if not arg.split('.')[0] or not arg.split('.')[1] \ + or not arg.split('.')[2]: + msg = "%r does not have enough required values" % arg + raise argparse.ArgumentTypeError(msg) + + # Validate element type + try: + vendor_id = int(arg.split('.')[0]) + major_id = int(arg.split('.')[1]) + minor_id = int(arg.split('.')[2]) + except ValueError: + msg = "%r must consist of all integers" % arg + raise argparse.ArgumentTypeError(msg) + + return saNtf.SaNtfClassIdT(vendor_id, major_id, minor_id) + + +def print_notification_header(notif_info): + """ Print information of the header in the received notification + + Args: + notif_info (NotificationInfo): NotificationInfo structure containing + information of the notification header + """ + dt_format_str = "%c %Z" + print ('notificationId = %d\n' + 'eventType = %s\n' + 'notificationObject = "%s"\n' + 'notifyingObject = "%s"\n' + 'notificationClassId = %d.%d.%d\n' + 'eventTime = %d (%s)\n' + 'additionalText = "%s"' % + (notif_info.notification_id, + saNtf.eSaNtfEventTypeT.whatis(notif_info.event_type), + notif_info.notification_object, + notif_info.notifying_object, + notif_info.ntf_class_id.vendorId, + notif_info.ntf_class_id.majorId, + notif_info.ntf_class_id.minorId, + notif_info.event_time, + satime_to_readable_datetime(notif_info.event_time, dt_format_str), + notif_info.additional_text)) + if notif_info.additional_info: + print("numAdditionalInfo = %d" % len(notif_info.additional_info)) + for add_info in notif_info.additional_info: + print ("- Info ID: %d\n" + " Info Type: %s (%d)\n" + " Info Value: %s" % + (add_info.info_id, + saNtf.eSaNtfValueTypeT.whatis(add_info.info_type), + add_info.info_type, + add_info.info_value)) + print() 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) + """ Print information of the received object create/delete notification + + Args: + notification (NotificationInfo): NotificationInfo structure containing + information of the received object create/delete notification + """ + print("=== %s - Object Create/Delete ===" % + satime_to_readable_datetime(notification.event_time)) + print_notification_header(notification) + print("sourceIndicator = %s" % + saNtf.eSaNtfSourceIndicatorT.whatis(notification.source_indicator)) + print("numAttributes = %d" % len(notification.object_attributes)) + for obj_attr in notification.object_attributes: + print("- Attribute ID: %d\n" + " Attribute Type: %s (%d)\n" + " Attribute Value: %s" % + (obj_attr.attribute_id, + saNtf.eSaNtfValueTypeT.whatis(obj_attr.attribute_type), + obj_attr.attribute_type, obj_attr.attribute_value)) 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) + """ Print information of the received attribute change notification + + Args: + notification (NotificationInfo): NotificationInfo structure containing + information of the received attribute change notification + """ + print("=== %s - Attribute Change ===" % + satime_to_readable_datetime(notification.event_time)) + print_notification_header(notification) + print("sourceIndicator = %s" % + saNtf.eSaNtfSourceIndicatorT.whatis(notification.source_indicator)) + print("numAttributes = %d" % len(notification.changed_attributes)) + for changed_attr in notification.changed_attributes: + print("- Attribute ID: %d\n" + " Attribute Type: %s (%d)\n" + " Old Attribute Present: %s\n" + " New Attribute Value: %s" % + (changed_attr.attribute_id, + saNtf.eSaNtfValueTypeT.whatis(changed_attr.attribute_type), + changed_attr.attribute_type, + bool(changed_attr.old_attribute_present), + changed_attr.new_attribute_value)) + if changed_attr.old_attribute_present: + print(" Old Attribute Value: %s" % + changed_attr.old_attribute_value) 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: + """ Print information of the received state change notification + + Args: + notification (NotificationInfo): NotificationInfo structure containing + information of the received state change notification + """ + print("=== %s - State Change ===" % + satime_to_readable_datetime(notification.event_time)) + print_notification_header(notification) + print("sourceIndicator = %s" % + saNtf.eSaNtfSourceIndicatorT.whatis(notification.source_indicator)) + print("numStateChanges = %d" % len(notification.state_changes)) + for changed_state in notification.state_changes: + print("- State ID: %d\n" + " Old State Present: %s\n" + " New State: %s" % + (changed_state.state_id, bool(changed_state.old_state_present), + changed_state.new_state)) + if changed_state.old_state_present: + print(" Old State: %s" % changed_state.old_state) - 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_alarm_notification(notification): + """ Print information of the received alarm notification + + Args: + notification (NotificationInfo): NotificationInfo structure containing + information of the received alarm notification + """ + print("=== %s - Alarm ===" % + satime_to_readable_datetime(notification.event_time)) + print_notification_header(notification) + print("probableCause = %s" % + saNtf.eSaNtfProbableCauseT.whatis(notification.probable_cause)) + print("perceivedSeverity = %s" % + saNtf.eSaNtfSeverityT.whatis(notification.perceived_severity)) + + if args.verbose: + print("trend = %s" % + saNtf.eSaNtfSeverityTrendT.whatis(notification.trend)) + print("thresholdInformation:\n" + "- Threshold ID: %d\n" + " Threshold Value Type: %s (%d)\n" + " Threshold Value: %s\n" + " Threshold Hysteresis: %s\n" + " Observed Value: %s\n" + " Arm Time: %s" % + (notification.threshold_information.threshold_id, + saNtf.eSaNtfValueTypeT.whatis( + notification.threshold_information.threshold_value_type), + notification.threshold_information.threshold_value_type, + notification.threshold_information.threshold_value, + notification.threshold_information.threshold_hysteresis, + notification.threshold_information.observed_value, + satime_to_readable_datetime( + notification.threshold_information.arm_time))) + print("numSpecificProblems = %d" % len(notification.specific_problems)) + for spec_problem in notification.specific_problems: + print("- Problem ID: %d\n" + " Problem Class ID: %d.%d.%d\n" + " Problem Type: %s (%d)\n" + " Problem Value: %s" % + (spec_problem.problem_id, + spec_problem.problem_class_id.vendorId, + spec_problem.problem_class_id.majorId, + spec_problem.problem_class_id.minorId, + saNtf.eSaNtfValueTypeT.whatis(spec_problem.problem_type), + spec_problem.problem_type, spec_problem.problem_value)) + print("numMonitoredAttributes = %d" % + len(notification.monitored_attrs)) + for monitored_attr in notification.monitored_attrs: + print("- Attribute ID: %d\n" + " Attribute Type: %s (%d)\n" + " Attribute Value: %s" % + (monitored_attr.attribute_id, + saNtf.eSaNtfValueTypeT.whatis( + monitored_attr.attribute_type), + monitored_attr.attribute_type, + monitored_attr.attribute_value)) + print("numProposedRepairActions = %d" % + len(notification.proposed_repair_actions)) + for repair_action in notification.proposed_repair_actions: + print("- Action ID: %d\n" + " Action Value Type: %s (%d)\n" + " Action Value: %s" % + (repair_action.action_id, + saNtf.eSaNtfValueTypeT.whatis( + repair_action.action_value_type), + repair_action.action_value_type, + repair_action.action_value)) 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) + """ Print information of the received security alarm notification + + Args: + notification (NotificationInfo): NotificationInfo structure containing + information of the received security alarm notification + """ + print("=== %s - Security Alarm ===" % + satime_to_readable_datetime(notification.event_time)) + print_notification_header(notification) + print("probableCause = %s\n" + "severity = %s\n" + "Security Alarm Detector Type: %s (%d)\n" + "Security Alarm Detector Value: %s\n" + "Service User Type: %s (%d)\n" + "Service User Value: %s\n" + "Service Provider Type: %s (%d)\n" + "Service Provider Value: %s" % + (saNtf.eSaNtfProbableCauseT.whatis(notification.probable_cause), + saNtf.eSaNtfSeverityT.whatis(notification.severity), + saNtf.eSaNtfValueTypeT.whatis( + notification.security_alarm_detector.value_type), + notification.security_alarm_detector.value_type, + notification.security_alarm_detector.value, + saNtf.eSaNtfValueTypeT.whatis(notification.service_user.value_type), + notification.service_user.value_type, + notification.service_user.value, + saNtf.eSaNtfValueTypeT.whatis( + notification.service_provider.value_type), + notification.service_provider.value_type, + notification.service_provider.value)) + + +def print_received_notification(subscription_id, notif_type, notif_info): + """ Test callback for subscribed notifications, which simply prints + information of every received notification + + Args: + subscription_id (SaNtfSubscriptionIdT): The subscription id previously + provided by the subscriber when subscribing for this type of + notification + notif_type (SaNtfNotificationTypeT): Type of the received notification + notif_info (NotificationInfo): NotificationInfo structure containing + information of the received notification + """ + print("\nSubscription ID: %d" % subscription_id) + if notif_type == \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_OBJECT_CREATE_DELETE: + print_object_create_delete_notification(notif_info) + elif notif_type == \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ATTRIBUTE_CHANGE: + print_attribute_change_notification(notif_info) + elif notif_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_STATE_CHANGE: + print_state_change_notification(notif_info) + elif notif_type == saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM: + print_alarm_notification(notif_info) + elif notif_type == \ + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM: + print_security_alarm_notification(notif_info) + print() + + +# Define command line arguments for ntfsubscribe +parser = argparse.ArgumentParser( + description='A SAF NTF client used to subscribe for incoming ' + 'notifications matching optionally provided filter ' + 'argument(s).\nIf not specified, all types of notification ' + 'will be subscribed to by default.', + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument('--subscriptionId', '-i', metavar='ID', type=int, + default=1, help='id for the notification subscription') +parser.add_argument('--timeout', '-t', metavar='TIME', type=int, + help='timeout (sec) to wait for notification') +parser.add_argument('--verbose', '-v', action='store_true', + help='print all information from alarm notifications') +parser.add_argument('--objectCreateDelete', '-o', action='store_true', + help='subscribe for objectCreateDelete notifications only') +parser.add_argument('--attributeChange', '-c', action='store_true', + help='subscribe for attributeChange notifications only') +parser.add_argument('--stateChange', '-s', action='store_true', + help='subscribe for stateChange notifications only') +parser.add_argument('--alarm', '-a', action='store_true', + help='subscribe for alarm notifications only') +parser.add_argument('--securityAlarm', '-y', action='store_true', + help='subscribe for securityAlarm notifications only') +parser.add_argument('--eventTypes', '-e', metavar='4096...20485', + type=int, nargs='+', + choices=sorted(saNtf.eSaNtfEventTypeT.reverse_lookup)[:22], + help='numeric value of SaNtfEventTypeT\n' + '(SA_NTF_OBJECT_NOTIFICATIONS_START...' + 'SA_NTF_TIME_VIOLATION)') +parser.add_argument('--notificationClassIds', '-C', + type=_validate_ntf_class_id, + metavar='VENDOR_ID.MAJOR_ID.MINOR_ID', nargs='+', + help='notification class identifier\n' + 'VENDOR_ID: SaUint32T integer value\n' + 'MAJOR_ID: SaUint16T integer value\n' + 'MINOR_ID: SaUint16T integer value') +parser.add_argument('--notificationObjects', '-n', metavar='NOTIFICATION_OBJ', + type=str, nargs='+', + help='notification object (string value)') +parser.add_argument('--notifyingObjects', '-N', metavar='NOTIFYING_OBJ', + type=str, nargs='+', + help='notifying object (string value)') +parser.add_argument('--sourceIndicators', '-I', metavar='1...3', + type=int, nargs='+', choices=range(1, 4), + help='numeric value of SaNtfSourceIndicatorT\n' + '(SA_NTF_OBJECT_OPERATION...' + 'SA_NTF_UNKNOWN_OPERATION)') +parser.add_argument('--changedStateIds', metavar='STATE_ID', + type=int, nargs='+', + help='changed state id of StateChange notification') +parser.add_argument('--probableCauses', '-p', metavar='0...74', + type=int, nargs='+', choices=range(75), + help='numeric value of SaNtfProbableCauseT\n' + '(SA_NTF_ADAPTER_ERROR...SA_NTF_UNSPECIFIED_REASON)') +parser.add_argument('--perceivedSeverities', '-r', metavar='0...5', type=int, + nargs='+', choices=range(6), + help='numeric value of alarm SaNtfSeverityT\n' + '(clear=0,ind,warn,min,maj,critical=5)') +parser.add_argument('--trends', '-T', metavar='0...2', type=int, + nargs='+', choices=range(3), + help='numeric value of SaNtfSeverityTrendT') +parser.add_argument('--severities', '-S', metavar='0...5', type=int, + nargs='+', choices=range(6), + help='numeric value of security alarm SaNtfSeverityT\n' + '(clear=0,ind,warn,min,maj,critical=5)') + +# Parse command line arguments for user input, if any +# Default values will be used otherwise +args = parser.parse_args() + +notif_type_subscriptions = [] + +if args.objectCreateDelete: + notif_type_subscriptions.append( + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_OBJECT_CREATE_DELETE) +if args.attributeChange: + notif_type_subscriptions.append( + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ATTRIBUTE_CHANGE) +if args.stateChange: + notif_type_subscriptions.append( + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_STATE_CHANGE) +if args.alarm: + notif_type_subscriptions.append( + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_ALARM) +if args.securityAlarm: + notif_type_subscriptions.append( + saNtf.eSaNtfNotificationTypeT.SA_NTF_TYPE_SECURITY_ALARM) + +# Initialize an NTF subscriber +subscriber = NtfSubscriber() +rc = subscriber.init(print_received_notification) +if rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: saNtfInitialize FAILED, rc = %s\n" % + eSaAisErrorT.whatis(rc)) + sys.exit(1) + +# Set notification subscribe filter values, if any, provided by the users +if args.eventTypes is not None: + subscriber.set_filter_event_types(args.eventTypes) +if args.notificationClassIds is not None: + subscriber.set_filter_ntf_class_ids(args.notificationClassIds) +if args.notificationObjects is not None: + subscriber.set_filter_notification_objects(args.notificationObjects) +if args.notifyingObjects is not None: + subscriber.set_filter_notifying_objects(args.notifyingObjects) +if args.sourceIndicators is not None: + subscriber.set_filter_source_indicators(args.sourceIndicators) +if args.changedStateIds is not None: + state_changes = [] + for state_id in args.changedStateIds: + state_changes.append(ntf.StateChange(state_id, 0, False, 0)) + subscriber.set_filter_changed_states(state_changes) +if args.probableCauses is not None: + subscriber.set_filter_probable_causes(args.probableCauses) +if args.perceivedSeverities is not None: + subscriber.set_filter_perceived_severities(args.perceivedSeverities) +if args.trends is not None: + subscriber.set_filter_trends(args.trends) +if args.severities is not None: + subscriber.set_filter_severities(args.severities) + +# Subscribe for user-specified notification types or all types by default +if notif_type_subscriptions: + rc = subscriber.subscribe(args.subscriptionId, notif_type_subscriptions) + if rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: saNtfNotificationSubscribe FAILED, rc = %s\n" % + eSaAisErrorT.whatis(rc)) + sys.exit(1) +else: + rc = subscriber.subscribe(args.subscriptionId) + if rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: saNtfNotificationSubscribe FAILED, rc = %s\n" % + eSaAisErrorT.whatis(rc)) + sys.exit(1) + +# Obtain the subscriber selection object to poll for incoming notifications +select_obj = subscriber.get_selection_object().value + +# Poll forever for notifications unless a timeout is specified +while True: + try: + read_evt, _, _ = select.select([select_obj], [], [], args.timeout) + if select_obj in read_evt: + rc = subscriber.dispatch(eSaDispatchFlagsT.SA_DISPATCH_ALL) + if rc != eSaAisErrorT.SA_AIS_OK: + print("ERROR: saNtfDispatch FAILED, rc = %s\n" % + eSaAisErrorT.whatis(rc)) + sys.exit(1) + elif not read_evt: + print("Poll timeout!") + sys.exit(1) + except KeyboardInterrupt: + sys.exit(0) -- 2.7.4 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel