Commit 784aa033 authored by Joanne Hugé's avatar Joanne Hugé

simpleran: add gps locked promise

parent 36fd598e
......@@ -16,7 +16,7 @@
[template]
filename = instance.cfg
md5sum = 9013df1ac77d35a1fc8df37bb5615dcd
md5sum = c1588b160ca830cbd42a295e043d4405
[template-ors]
filename = instance-ors.cfg
......@@ -60,7 +60,7 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 04b723fc2a3d5555243921823b0e087b
md5sum = de757719d6cf4bd731394f50dbce8d99
[template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg
......@@ -142,6 +142,10 @@ md5sum = f02fbfd31ba89cf243e2752adcae28d9
_update_hash_filename_ = promise/check_frequency_outofbounds.py
md5sum = 7c83eab2df4f5a5d519e3eb16e4077a3
[gps_lock_promise]
_update_hash_filename_ = promise/check_gps_lock.py
md5sum = c79fb837cc32bc0182ebf15078115b10
[nginx_conf.in]
_update_hash_filename_ = config/nginx_conf.in
md5sum = e2496564695fb76b242c3e0f8d0ab6c3
Changelog
=========
Version 1.0.384 (2024-12-16)
-------------
* Add promise to check if GPS is synchronized when enabled
Version 1.0.383 (2024-12-11)
-------------
......
......@@ -65,6 +65,9 @@ parts =
xlog-fluentbit-service
check-xlog-fluentbit-forward-host.py
check-xlog-fluentbit-health.py
{%- endif %}
{%- if slapparameter_dict.get('gps_sync', False) %}
gps-lock-promise
{%- endif %}
nginx-launcher
nginx-graceful
......@@ -385,3 +388,12 @@ config-amarisoft-stats-log = ${ru_amarisoft-stats-template:log-output}
config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
config-min-rxtx-delay = {{ slapparameter_dict.get("min_rxtx_delay", 0) }}
{%- if slapparameter_dict.get('gps_sync', False) %}
[gps-lock-promise]
recipe = slapos.cookbook:promise.plugin
eggs = slapos.core
file = {{ gps_lock_promise }}
output = ${directory:plugins}/check-gps-lock.py
config-amarisoft-rf-info-log = ${ru_amarisoft-rf-info-template:log-output}
config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
{%- endif %}
......@@ -243,6 +243,7 @@ extra-context =
raw fluent_bit_location ${fluent-bit:location}
raw openssh_location ${openssh:location}
raw openssh_output_keygen ${openssh-output:keygen}
raw gps_lock_promise ${gps_lock_promise:target}
[dynamic-template-core-network]
< = jinja2-template-base
......
import itertools
import json
import logging
import os
import re
from dateutil import parser as dateparser
from datetime import datetime
from zope.interface import implementer
from slapos.grid.promise import interface
from slapos.grid.promise.generic import GenericPromise
def iter_reverse_lines(f):
"""
Read lines from the end of the file
"""
f.seek(0, os.SEEK_END)
while True:
try:
while f.seek(-2, os.SEEK_CUR) and f.read(1) != b'\n':
pass
except OSError:
return
pos = f.tell()
yield f.readline()
f.seek(pos, os.SEEK_SET)
def iter_logrotate_file_handle(path, mode='r'):
"""
Yield successive file handles for rotated logs
(XX.log, XX.log.1, XX.log.2, ...)
"""
for i in itertools.count():
path_i = path + str(i or '')
try:
with open(path_i, mode) as f:
yield f
except OSError:
break
def get_json_log_data_interval(json_log_file, interval):
"""
Get all data in the last "interval" seconds from JSON log
Reads rotated logs too (XX.log, XX.log.1, XX.log.2, ...)
"""
current_time = datetime.now()
data_list = []
for f in iter_logrotate_file_handle(json_log_file, 'rb'):
for line in iter_reverse_lines(f):
l = json.loads(line)
timestamp = dateparser.parse(l['time'])
if (current_time - timestamp).total_seconds() > interval:
return data_list
data_list.append(l['data'])
return data_list
class JSONPromise(GenericPromise):
def __init__(self, config):
self.__name = config.get('name', None)
self.__log_folder = config.get('log-folder', None)
super(JSONPromise, self).__init__(config)
json_log_name = os.path.splitext(self.__name)[0] + '.json.log'
self.__json_log_file = os.path.join(self.__log_folder, json_log_name)
self.json_logger = self.__make_json_logger(self.__json_log_file)
def __make_json_logger(self, json_log_file):
logger = logging.getLogger('json-logger')
logger.setLevel(logging.INFO)
handler = logging.FileHandler(json_log_file)
formatter = logging.Formatter(
'{"time": "%(asctime)s", "log_level": "%(levelname)s"'
', "message": "%(message)s", "data": %(data)s}'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
@implementer(interface.IPromise)
class RunPromise(JSONPromise):
def __init__(self, config):
super(RunPromise, self).__init__(config)
self.setPeriodicity(minute=1)
self.amarisoft_rf_info_log = self.getConfig('amarisoft-rf-info-log')
self.stats_period = int(self.getConfig('stats-period'))
def sense(self):
data_list = get_json_log_data_interval(self.amarisoft_rf_info_log, self.stats_period * 2)
if len(data_list) < 1:
self.logger.error("rf_info: stale data")
return
rf_info_text = data_list[0]['rf_info']
if 'Sync: gps (locked)' in rf_info_text:
self.logger.info("GPS locked")
else:
self.logger.error("GPS not locked")
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)
......@@ -222,6 +222,9 @@ update-command = ${:command}
<= setcap
exe = ${dnsmasq:location}/sbin/dnsmasq
[gps_lock_promise]
<= download-base
[versions]
websocket-client = 1.4.2
ncclient = 0.6.13
......
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