Commit 4ce05af3 authored by Lu Xu's avatar Lu Xu 👀

promise/plugin: add alarms for lopcomm RU

parent ffcd378e
...@@ -20,18 +20,21 @@ class RunPromise(JSONPromise): ...@@ -20,18 +20,21 @@ class RunPromise(JSONPromise):
self.testing = self.getConfig('testing') == "True" self.testing = self.getConfig('testing') == "True"
def sense(self): def sense(self):
if self.testing:
if self.testing: self.logger.info("skipping promise")
self.logger.info("skipping promise") return
return
last_line = tail_file(self.amarisoft_rf_info_log) last_line = tail_file(self.amarisoft_rf_info_log)
if "CPRI" not in last_line: if "CPRI" not in last_line:
self.logger.info("No CPRI feature") self.logger.info("No CPRI feature")
else: else:
if "HW" in last_line and "SW" in last_line: if "HW" in last_line and "SW" in last_line:
self.logger.info("CPRI locked") self.logger.info("CPRI locked")
else: else:
self.logger.error("HW or SW missing") if "HW" not in last_line:
self.logger.error("HW Lock is missing")
if "SW" not in last_line:
self.logger.error("SW Lock is missing")
def test(self): def test(self):
""" """
......
import errno
import json
import logging
import os
from dateutil import parser
from .util import JSONPromise
from .util import tail_file
from zope.interface import implementer
from slapos.grid.promise import interface
@implementer(interface.IPromise)
class RunPromise(JSONPromise):
def __init__(self, config):
super(RunPromise, self).__init__(config)
self.setPeriodicity(minute=1)
self.config_log = self.getConfig('config-log')
def sense(self):
latest_log = tail_file(self.config_log)
latest_log.split("\n")
if "Sending edit-config RPC request..." not in latest_log:
self.logger.info("No edit-config RPC request")
else:
last_segment = latest_log.split("Sending edit-config RPC request...")[-1].strip()
if "Error" in last_segment:
self.logger.error("Error sending edit-config RPC request")
elif "Got exception" in last_segment:
self.logger.error("Connection lost")
else:
self.logger.info("Edit-config RPC request sent successfully")
def test(self):
"""
Called after sense() if the instance is still converging.
Returns success or failure based on sense results.
In this case, fail if the previous sensor result is negative.
"""
return self._test(result_count=1, failure_amount=1)
def anomaly(self):
"""
Called after sense() if the instance has finished converging.
Returns success or failure based on sense results.
Failure signals the instance has diverged.
In this case, fail if two out of the last three results are negative.
"""
return self._anomaly(result_count=1, failure_amount=1)
import errno
import json
import logging
import os
from dateutil import parser
from .util import iter_logrotate_file_handle
from .util import iter_reverse_lines
from .util import JSONPromise
from zope.interface import implementer
from slapos.grid.promise import interface
@implementer(interface.IPromise)
class RunPromise(JSONPromise):
def __init__(self, config):
super(RunPromise, self).__init__(config)
self.setPeriodicity(minute=1)
self.netconf_log = self.getConfig('netconf-log')
self.testing = self.getConfig('testing') == "True"
def sense(self):
if self.testing:
self.logger.info("skipping promise")
return
for f in iter_logrotate_file_handle(self.netconf_log, 'rb'):
for line in iter_reverse_lines(f):
l = json.loads(line.decode().replace("'", '"'))
alarm_notif = l.get('data', {}).get('notification', {}).get('alarm-notif', None)
if alarm_notif and alarm_notif['fault-id'] == '103':
if alarm_notif['is-cleared'] == 'false':
affected_objects = alarm_notif.get('affected-objects', {})
self.logger.error('PA Over Current Alarm is on, affected objects are: %s', affected_objects)
self.json_logger.info("Affected objects", extra={'data': affected_objects})
else:
self.logger.info('PA Over Current Alarm is off')
return
self.logger.info('No PA Over Current Alarm received')
def test(self):
"""
Called after sense() if the instance is still converging.
Returns success or failure based on sense results.
In this case, fail if the previous sensor result is negative.
"""
return self._test(result_count=1, failure_amount=1)
def anomaly(self):
"""
Called after sense() if the instance has finished converging.
Returns success or failure based on sense results.
Failure signals the instance has diverged.
In this case, fail if two out of the last three results are negative.
"""
return self._anomaly(result_count=1, failure_amount=1)
import errno
import json
import logging
import os
from dateutil import parser
from .util import JSONPromise
from .util import tail_file
from zope.interface import implementer
from slapos.grid.promise import interface
@implementer(interface.IPromise)
class RunPromise(JSONPromise):
def __init__(self, config):
super(RunPromise, self).__init__(config)
self.setPeriodicity(minute=1)
self.stats_log = self.getConfig('stats-log')
def sense(self):
latest_log = tail_file(self.stats_log)
latest_log.split("\n")
if "Waiting for notification from" not in latest_log:
self.logger.error("Not subscribed")
else:
self.logger.info("Subscribed successful")
def test(self):
"""
Called after sense() if the instance is still converging.
Returns success or failure based on sense results.
In this case, fail if the previous sensor result is negative.
"""
return self._test(result_count=1, failure_amount=1)
def anomaly(self):
"""
Called after sense() if the instance has finished converging.
Returns success or failure based on sense results.
Failure signals the instance has diverged.
In this case, fail if two out of the last three results are negative.
"""
return self._anomaly(result_count=1, failure_amount=1)
import errno
import json
import logging
import os
from dateutil import parser
from .util import iter_logrotate_file_handle
from .util import iter_reverse_lines
from .util import JSONPromise
from zope.interface import implementer
from slapos.grid.promise import interface
@implementer(interface.IPromise)
class RunPromise(JSONPromise):
def __init__(self, config):
super(RunPromise, self).__init__(config)
self.setPeriodicity(minute=1)
self.netconf_log = self.getConfig('netconf-log')
self.testing = self.getConfig('testing') == "True"
def sense(self):
if self.testing:
self.logger.info("skipping promise")
return
for f in iter_logrotate_file_handle(self.netconf_log, 'rb'):
for line in iter_reverse_lines(f):
l = json.loads(line.decode().replace("'", '"'))
alarm_notif = l.get('data', {}).get('notification', {}).get('alarm-notif', None)
if alarm_notif and alarm_notif['fault-id'] == '18':
if alarm_notif['is-cleared'] == 'false':
affected_objects = alarm_notif.get('affected-objects', {})
self.logger.error('Synchronization Error Alarm is on, affected objects are: %s', affected_objects)
self.json_logger.info("Affected objects", extra={'data': affected_objects})
else:
self.logger.info('Synchronization Error Alarm is off')
return
self.logger.info('No Synchronization Error Alarm received')
def test(self):
"""
Called after sense() if the instance is still converging.
Returns success or failure based on sense results.
In this case, fail if the previous sensor result is negative.
"""
return self._test(result_count=1, failure_amount=1)
def anomaly(self):
"""
Called after sense() if the instance has finished converging.
Returns success or failure based on sense results.
Failure signals the instance has diverged.
In this case, fail if two out of the last three results are negative.
"""
return self._anomaly(result_count=1, failure_amount=1)
import mock
import os
import time
from datetime import datetime
from datetime import timedelta
from slapos.grid.promise import PromiseError
from slapos.promise.plugin.check_lopcomm_config_log import RunPromise
from . import TestPromisePluginMixin
class TestCheckLopcommConfigLog(TestPromisePluginMixin):
promise_name = "check-lopcomm-config-log.py"
def setUp(self):
super(TestCheckLopcommConfigLog, self).setUp()
def writePromise(self, **kw):
super(TestCheckLopcommConfigLog, self).writePromise(self.promise_name,
"from %s import %s\nextra_config_dict = %r\n"
% (RunPromise.__module__, RunPromise.__name__, kw))
def test_promise_success(self):
self.config_log = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config.log')
if os.path.exists(self.config_log):
os.remove(self.config_log)
with open(self.config_log, 'w+') as f:
f.write("""2023-05-23 04:32:48,867 [INFO] Sending edit-config RPC request...
2023-05-23 04:32:49,111 [INFO] Edit-config RPC request sent successfully
"""
)
self.writePromise(**{
'config-log': self.config_log,
})
self.configureLauncher()
self.launcher.run()
def test_promise_fail(self):
self.config_log = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config.log')
if os.path.exists(self.config_log):
os.remove(self.config_log)
with open(self.config_log, 'w') as f:
f.write("""2023-05-23 04:32:20,110 [INFO] Connecting to ('2a11:9ac1:6:800a::1', 830), user oranuser...
2023-05-23 04:32:48,863 [INFO] Connection to ('2a11:9ac1:6:800a::1', 830) successful
2023-05-23 04:32:48,867 [INFO] Sending edit-config RPC request...
2023-05-23 04:32:49,111 [ERROR] Error sending edit-config RPC request: Operation failed
"""
)
self.writePromise(**{
'config-log': self.config_log,
'testing': 'True',
})
self.configureLauncher()
with self.assertRaises(PromiseError):
self.launcher.run()
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (c) 2018 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import os
import time
from datetime import datetime
from datetime import timedelta
from slapos.grid.promise import PromiseError
from slapos.promise.plugin.check_lopcomm_pa_current import RunPromise
from . import TestPromisePluginMixin
class TestCheckLopcommPACurrentSuccess(TestPromisePluginMixin):
promise_name = "check-lopcomm-pa-current.py"
def setUp(self):
super(TestCheckLopcommPACurrentSuccess, self).setUp()
self.netconf_log = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'netconf.json.log')
def writePromise(self, **kw):
super(TestCheckLopcommPACurrentSuccess, self).writePromise(self.promise_name,
"from %s import %s\nextra_config_dict = %r\n"
% (RunPromise.__module__, RunPromise.__name__, kw))
def test_promise_success(self):
with open(self.netconf_log, 'w+') as f:
f.write("""{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-05T00:38:50Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '103', 'fault-source': 'PA0', 'affected-objects': {'name': 'PA0'}, 'fault-severity': 'MINOR', 'is-cleared': 'false', 'fault-text': 'PA 1 Over Current Alarm', 'event-time': '1970-01-05T00:38:50Z'}}}}
{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-05T00:38:50Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '103', 'fault-source': 'PA0', 'affected-objects': {'name': 'PA0'}, 'fault-severity': 'MINOR', 'is-cleared': 'true', 'fault-text': 'PA 1 Over Current Alarm', 'event-time': '1970-01-05T00:38:50Z'}}}}""" % (
(datetime.now() - timedelta(seconds=25)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
(datetime.now() - timedelta(seconds=15)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
))
self.writePromise(**{
'netconf-log': self.netconf_log,
})
self.configureLauncher()
self.launcher.run()
def test_promise_fail(self):
with open(self.netconf_log, 'w+') as f:
f.write("""{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-05T00:38:50Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '103', 'fault-source': 'PA0', 'affected-objects': {'name': 'PA0'}, 'fault-severity': 'MINOR', 'is-cleared': 'true', 'fault-text': 'PA 1 Over Current Alarm', 'event-time': '1970-01-05T00:38:50Z'}}}}
{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-05T00:38:50Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '103', 'fault-source': 'PA0', 'affected-objects': {'name': 'PA0'}, 'fault-severity': 'MINOR', 'is-cleared': 'false', 'fault-text': 'PA 1 Over Current Alarm', 'event-time': '1970-01-05T00:38:50Z'}}}}""" % (
(datetime.now() - timedelta(seconds=25)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
(datetime.now() - timedelta(seconds=15)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
))
self.writePromise(**{
'netconf-log': self.netconf_log,
})
self.configureLauncher()
with self.assertRaises(PromiseError):
self.launcher.run()
self.assertEqual("PA Over Current Alarm is on, affected objects are: {'name': 'PA0'}", self.getPromiseResult(self.promise_name)['result']['message'])
import mock
import os
import time
from datetime import datetime
from datetime import timedelta
from slapos.grid.promise import PromiseError
from slapos.promise.plugin.check_lopcomm_stats_log import RunPromise
from . import TestPromisePluginMixin
class TestCheckLopcommConfigLog(TestPromisePluginMixin):
promise_name = "check-lopcomm-stats-log.py"
def setUp(self):
super(TestCheckLopcommConfigLog, self).setUp()
def writePromise(self, **kw):
super(TestCheckLopcommConfigLog, self).writePromise(self.promise_name,
"from %s import %s\nextra_config_dict = %r\n"
% (RunPromise.__module__, RunPromise.__name__, kw))
def test_promise_success(self):
self.stats_log = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'stats.log')
if os.path.exists(self.stats_log):
os.remove(self.stats_log)
with open(self.stats_log, 'w+') as f:
f.write("""2023-05-23 04:32:46,350 [INFO] Connecting to ('2a11:9ac1:6:800a::1', 830), user oranuser...
2023-05-23 04:32:48,830 [INFO] Connection to ('2a11:9ac1:6:800a::1', 830) successful
2023-05-23 04:32:49,692 [INFO] Subscription to ('2a11:9ac1:6:800a::1', 830) successful
2023-05-23 04:32:49,692 [DEBUG] Waiting for notification from ('2a11:9ac1:6:800a::1', 830)...
2023-05-23 04:33:09,787 [DEBUG] Got new notification from ('2a11:9ac1:6:800a::1', 830)...
2023-05-23 04:33:09,788 [DEBUG] Waiting for notification from ('2a11:9ac1:6:800a::1', 830)...
2023-05-23 04:33:41,318 [DEBUG] Got new notification from ('2a11:9ac1:6:800a::1', 830)...
2023-05-23 04:33:41,319 [DEBUG] Waiting for notification from ('2a11:9ac1:6:800a::1', 830)...
"""
)
self.writePromise(**{
'stats-log': self.stats_log,
})
self.configureLauncher()
self.launcher.run()
def test_promise_fail(self):
self.stats_log = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'stats.log')
if os.path.exists(self.stats_log):
os.remove(self.stats_log)
with open(self.stats_log, 'w') as f:
f.write("""
2023-05-23 04:32:33,230 [INFO] Connecting to ('2a11:9ac1:6:800a::1', 830), user oranuser...
2023-05-23 04:32:36,339 [DEBUG] Got exception, waiting 10 seconds before reconnecting...
2023-05-23 04:32:36,340 [DEBUG] Could not open socket to 2a11:9ac1:6:800a::1:830
"""
)
self.writePromise(**{
'stats-log': self.stats_log,
'testing': 'True',
})
self.configureLauncher()
with self.assertRaises(PromiseError):
self.launcher.run()
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (c) 2018 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import os
import time
from datetime import datetime
from datetime import timedelta
from slapos.grid.promise import PromiseError
from slapos.promise.plugin.check_lopcomm_sync import RunPromise
from . import TestPromisePluginMixin
class TestCheckLopcommSyncSuccess(TestPromisePluginMixin):
promise_name = "check-lopcomm-sync.py"
def setUp(self):
super(TestCheckLopcommSyncSuccess, self).setUp()
self.netconf_log = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'netconf.json.log')
def writePromise(self, **kw):
super(TestCheckLopcommSyncSuccess, self).writePromise(self.promise_name,
"from %s import %s\nextra_config_dict = %r\n"
% (RunPromise.__module__, RunPromise.__name__, kw))
def test_promise_success(self):
with open(self.netconf_log, 'w+') as f:
f.write("""{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-01T01:34:04Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '18', 'fault-source': 'Radio Module', 'affected-objects': {'name': 'Radio Module'}, 'fault-severity': 'MAJOR', 'is-cleared': 'false', 'fault-text': 'Synchronization Error Alarm', 'event-time': '1970-01-01T01:34:04Z'}}}}
{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-01T01:34:28Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '18', 'fault-source': 'Radio Module', 'affected-objects': {'name': 'Radio Module'}, 'fault-severity': 'MAJOR', 'is-cleared': 'true', 'fault-text': 'Synchronization Error Alarm', 'event-time': '1970-01-01T01:34:28Z'}}}}""" % (
(datetime.now() - timedelta(seconds=25)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
(datetime.now() - timedelta(seconds=15)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
))
self.writePromise(**{
'netconf-log': self.netconf_log,
})
self.configureLauncher()
self.launcher.run()
def test_promise_fail(self):
with open(self.netconf_log, 'w+') as f:
f.write("""{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-01T01:34:04Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '18', 'fault-source': 'Radio Module', 'affected-objects': {'name': 'Radio Module'}, 'fault-severity': 'MAJOR', 'is-cleared': 'false', 'fault-text': 'Synchronization Error Alarm', 'event-time': '1970-01-01T01:34:04Z'}}}}
{"time": "%s", "log_level": "INFO", "message": "", "data": {'notification': {'@xmlns': 'urn:ietf:params:xml:ns:netconf:notification:1.0', 'eventTime': '1970-01-01T01:34:28Z', 'alarm-notif': {'@xmlns': 'urn:o-ran:fm:1.0', 'fault-id': '18', 'fault-source': 'Radio Module', 'affected-objects': {'name': 'Radio Module'}, 'fault-severity': 'MAJOR', 'is-cleared': 'false', 'fault-text': 'Synchronization Error Alarm', 'event-time': '1970-01-01T01:34:28Z'}}}}""" % (
(datetime.now() - timedelta(seconds=25)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
(datetime.now() - timedelta(seconds=15)).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3],
))
self.writePromise(**{
'netconf-log': self.netconf_log,
})
self.configureLauncher()
with self.assertRaises(PromiseError):
self.launcher.run()
self.assertEqual("Synchronization Error Alarm is on, affected objects are: {'name': 'Radio Module'}", self.getPromiseResult(self.promise_name)['result']['message'])
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment