diff --git a/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver.py b/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver.py index 1e6015c7437014904492f82038fb8b251fcd103a..0ffa589ed12e03fd5410edf296048d658d47385a 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver.py @@ -59,7 +59,7 @@ class TestArchiver(BaseIntegrationTestCase): self.archiver.remove_attributes_in_error() time.sleep(3) attr_fullname = 'stat/recv/1/recvtr_translator_busy_r' # boolean - self.archiver.add_attribute_to_archiver(attr_fullname, polling_period=1000, event_period=3000) + self.archiver.add_attribute_to_archiver(attr_fullname, polling_period=1000, archive_event_period=3000) time.sleep(3) # Test if the attribute has been correctly added to event subscriber self.assertTrue(self.archiver.is_attribute_archived(attribute_fqdn(attr_fullname))) @@ -99,7 +99,7 @@ class TestArchiver(BaseIntegrationTestCase): self.archiver.remove_attributes_in_error() time.sleep(3) attr_fullname = 'stat/sdp/1/fpga_temp_r' # double - self.archiver.add_attribute_to_archiver(attr_fullname, polling_period=1000, event_period=3000) + self.archiver.add_attribute_to_archiver(attr_fullname, polling_period=1000, archive_event_period=3000) time.sleep(3) # Test if the attribute has been correctly added to event subscriber self.assertTrue(self.archiver.is_attribute_archived(attribute_fqdn(attr_fullname))) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver_util.py b/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver_util.py index 277740f8b0326b387e8b3da9c69fa2b07668d318..ad4595951d43c5cacdf26459e9cb982c1e32e142 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver_util.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/toolkit/test_archiver_util.py @@ -9,7 +9,7 @@ from tangostationcontrol.integration_test.base import BaseIntegrationTestCase from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy -from tangostationcontrol.toolkit.archiver_util import get_attributes_from_suffix +from tangostationcontrol.toolkit.archiver_util import get_attributes_from_suffix, retrieve_attributes_from_wildcards from tango import DevState import json import pkg_resources @@ -24,9 +24,21 @@ class TestArchiverUtil(BaseIntegrationTestCase): """Test if attributes are correctly matched with the defined global suffixes""" device_name = 'STAT/RECV/1' attribute_name = 'ANT_mask_RW' - suffixes = self.config_dict['_global_suffixes'] + dev_suffixes = self.config_dict['_global_variables']['development']['suffixes'] # Start RECV Device recv_proxy = TestDeviceProxy(device_name) recv_proxy.off() self.assertEqual(DevState.OFF, recv_proxy.state()) - self.assertIn(attribute_name, get_attributes_from_suffix(device_name,suffixes)) + self.assertIn(attribute_name, get_attributes_from_suffix(device_name,dev_suffixes)) + + def test_retrieve_attributes_from_wildcards(self): + """Test if attributes are correctly retrieved with wildcards matching""" + device_name = 'STAT/SDP/1' + attribute_names = ['FPGA_scrap_R','FPGA_scrap_RW'] + exclude_list = self.config_dict['devices'][device_name]['exclude'] + # Start SDP Device + sdp_proxy = TestDeviceProxy(device_name) + sdp_proxy.off() + self.assertEqual(DevState.OFF, sdp_proxy.state()) + for a in attribute_names: + self.assertIn(a, retrieve_attributes_from_wildcards(device_name,exclude_list)) diff --git a/tangostationcontrol/tangostationcontrol/test/toolkit/test_archiver_configurator.py b/tangostationcontrol/tangostationcontrol/test/toolkit/test_archiver_configurator.py new file mode 100644 index 0000000000000000000000000000000000000000..a0f9d00f981d22f14715d773966610b55efe2fd4 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/test/toolkit/test_archiver_configurator.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +from tangostationcontrol.test import base +from tangostationcontrol.toolkit.archiver_configurator import get_parameters_from_attribute, get_global_env_parameters +import json +import pkg_resources + +class TestArchiverConfigurator(base.TestCase): + + device_name = 'STAT/RECV/1' + attribute_name = 'ant_mask_rw' + config_dict = json.load(pkg_resources.resource_stream('tangostationcontrol.toolkit', f'archiver_config/lofar2.json')) + # Environments + dev_env = 'development' + prod_env = 'production' + dev_suffixes = config_dict['_global_variables'][dev_env]['suffixes'] + prod_suffixes = config_dict['_global_variables'][prod_env]['suffixes'] + prod_infixes = config_dict['_global_variables'][prod_env]['infixes'] + + def test_get_parameters_from_attribute(self): + """Test if the attribute archiving parameters are correctly retrieved from the JSON config file""" + self.assertIsNotNone(self.config_dict) + archive_period, event_period, abs_change, rel_change = get_parameters_from_attribute(self.device_name, self.attribute_name, + self.config_dict, self.dev_env) + self.assertEqual(archive_period,int(self.dev_suffixes[2]['archive_period'])) + self.assertEqual(event_period,int(self.dev_suffixes[2]['event_period'])) + self.assertEqual(abs_change,int(self.dev_suffixes[2]['abs_change'])) + self.assertEqual(rel_change,self.dev_suffixes[2]['rel_change']) + + """Test if the attribute archiving parameters are correctly retrieved from the infixes list (production environment)""" + attribute_name = 'rcu_temp_r' # 'TEMP' is in the infixes list + archive_period, event_period, abs_change, rel_change = get_parameters_from_attribute(self.device_name, attribute_name, + self.config_dict, self.prod_env) + self.assertEqual(archive_period,int(self.prod_infixes[2]['archive_period'])) + self.assertEqual(event_period,int(self.prod_infixes[2]['event_period'])) + self.assertEqual(abs_change,int(self.prod_infixes[2]['abs_change'])) + self.assertEqual(rel_change,self.prod_infixes[2]['rel_change']) + + def test_get_global_env_parameters(self): + """Test if the include attribute list is correctly retrieved from the JSON config file""" + self.assertIsNotNone(self.config_dict) + polling_time, archive_abs_change, archive_rel_change, archive_period, event_period, strategy = get_global_env_parameters( + self.config_dict, self.dev_env) + self.assertEqual(type(polling_time),int) + self.assertEqual(type(archive_abs_change), int) + self.assertEqual(f"{type(archive_rel_change)}", f"<class 'NoneType'>") + self.assertEqual(type(archive_period),int) + self.assertEqual(type(event_period),int) + self.assertEqual(type(strategy),str) diff --git a/tangostationcontrol/tangostationcontrol/test/toolkit/test_archiver_util.py b/tangostationcontrol/tangostationcontrol/test/toolkit/test_archiver_util.py index 9936046cf21bc709bb3fda523471d64b47a62a30..c0322593510b580202d8e26211ce2df01e5ac5f7 100644 --- a/tangostationcontrol/tangostationcontrol/test/toolkit/test_archiver_util.py +++ b/tangostationcontrol/tangostationcontrol/test/toolkit/test_archiver_util.py @@ -8,17 +8,12 @@ # See LICENSE.txt for more info. from tangostationcontrol.test import base -from tangostationcontrol.toolkit.archiver_util import device_fqdn, attribute_fqdn, get_parameters_from_attribute -import json -import pkg_resources +from tangostationcontrol.toolkit.archiver_util import device_fqdn, attribute_fqdn class TestArchiverUtil(base.TestCase): device_name = 'STAT/RECV/1' attribute_name = 'ant_mask_rw' - suffixes = ["_error_R","_good_R","_mask_RW","_version_R"] - config_dict = json.load(pkg_resources.resource_stream('tangostationcontrol.toolkit', f'archiver_config/lofar2.json')) - def test_device_fqdn(self): """Test if a device name is correctly converted in a Tango FQDN""" @@ -30,13 +25,3 @@ class TestArchiverUtil(base.TestCase): attribute_fqdn(f"{self.device_name}/{self.attribute_name}")) self.assertRaises(ValueError, lambda: attribute_fqdn(self.attribute_name)) - def test_get_parameters_from_attribute(self): - """Test if the attribute archiving parameters are correctly retrieved from the JSON config file""" - self.assertIsNotNone(self.config_dict) - suffixes = self.config_dict['_global_suffixes'] - archive_period, event_period, abs_change, rel_change = get_parameters_from_attribute(self.device_name, self.attribute_name, - suffixes, self.config_dict) - self.assertEqual(archive_period,int(suffixes[2]['archive_period'])) - self.assertEqual(event_period,int(suffixes[2]['event_period'])) - self.assertEqual(abs_change,int(suffixes[2]['abs_change'])) - self.assertEqual(rel_change,suffixes[2]['rel_change']) diff --git a/tangostationcontrol/tangostationcontrol/toolkit/archiver.py b/tangostationcontrol/tangostationcontrol/toolkit/archiver.py index cb66e94706521dd867d75ce1c2b21173ff78a3e4..dab6e15c6209dba7d662c11b4f594f30d8c36ebf 100644 --- a/tangostationcontrol/tangostationcontrol/toolkit/archiver.py +++ b/tangostationcontrol/tangostationcontrol/toolkit/archiver.py @@ -3,7 +3,8 @@ import logging from tango import DeviceProxy, AttributeProxy, DevState, DevFailed -from tangostationcontrol.toolkit.archiver_util import get_db_config, device_fqdn, attribute_fqdn, get_attributes_from_suffix, get_parameters_from_attribute +from tangostationcontrol.toolkit.archiver_util import get_db_config, device_fqdn, attribute_fqdn +from tangostationcontrol.toolkit.archiver_configurator import get_parameters_from_attribute, get_include_attribute_list, get_exclude_attribute_list, get_global_env_parameters import time import json @@ -38,12 +39,19 @@ class Archiver(): """ # Global 'DEVELOPMENT' environment variables set by configuration file - dev_polling_time = 600 + dev_polling_time = 1000 dev_archive_abs_change = 1 dev_archive_rel_change = None - dev_archive_period = 3600 - dev_event_period = 600 + dev_archive_period = 10000 + dev_event_period = 1000 dev_strategy = 'RUN' + # Global 'PRODUCTION' environment variables set by configuration file + prod_polling_time = 1000 + prod_archive_abs_change = 1 + prod_archive_rel_change = None + prod_archive_period = 3600000 + prod_event_period = 60000 + prod_strategy = 'RUN' def __init__(self, cm_name: str = 'archiving/hdbppts/confmanager01', context: str = 'RUN'): self.cm_name = cm_name @@ -105,46 +113,18 @@ class Archiver(): Apply the customized strategy defined by the given archiver configuration. """ # Set global development env variables - var_dict = config_dict['_global_variables'] - self.dev_polling_time = int(var_dict['development_polling_time']) - abs_change = var_dict['development_archive_abs_change'] - rel_change = var_dict['development_archive_rel_change'] - self.dev_archive_abs_change = abs_change and int(abs_change) - self.dev_archive_rel_change = rel_change and int(rel_change) - self.dev_archive_period = int(var_dict['development_archive_period']) - self.dev_event_period = int(var_dict['development_event_period']) - self.dev_strategy = var_dict['development_strategy'] - suffixes = config_dict['_global_suffixes'] # suffixes list of attributes that need to be archived + self.dev_polling_time, self.dev_archive_abs_change, self.dev_archive_rel_change, self.dev_archive_period, self.dev_event_period, self.dev_strategy = get_global_env_parameters(config_dict, "development") + # Set global production env variables + self.prod_polling_time, self.prod_archive_abs_change, self.prod_archive_rel_change, self.prod_archive_period, self.prod_event_period, self.prod_strategy = get_global_env_parameters(config_dict, "production") # Set devices archiving env_dict = config_dict['devices'] for device in env_dict: try: dev_env = str(env_dict[device]['environment']) # Get device environment if dev_env == 'development': # DEV environment -> all attributes are excluded by default - include_node = env_dict[device].get('include',[]) - include_att_list = [] - for a in include_node: - include_att_list.append(a['attribute']) - # Add attributes with defined suffixes - include_att_list.extend(get_attributes_from_suffix(device,suffixes)) - self.remove_attributes_by_device(device, exclude=include_att_list) - # Include attributes by custom configuration - for att in include_att_list: - # Retrieve specific attribute parameters from config file - archive_period, event_period, abs_change, rel_change = get_parameters_from_attribute(device,att,suffixes,config_dict) - att_fqname = attribute_fqdn(f"{device}/{att}") - self.add_attribute_to_archiver(att_fqname,archive_period or self.dev_polling_time, - event_period or self.dev_archive_period, self.dev_strategy, - abs_change or self.dev_archive_abs_change, rel_change or self.dev_archive_rel_change) + self.configure_for_development(config_dict, device) elif dev_env == 'production': # PROD environment -> all attributes are included by default - exclude_att_list = env_dict[device].get('exclude', []) - self.add_attributes_by_device(device, exclude=exclude_att_list) - # Remove attributes by custom configuration if already present - # The following cycle is a security check in the special case that an attribute is in the - # included list in DEV mode, and in the excluded list in PROD mode - for att in exclude_att_list: - att_fqname = attribute_fqdn(f"{device}/{att}") - self.remove_attribute_from_archiver(att_fqname) + self.configure_for_production(config_dict, device) except Exception as e: if 'API_DeviceNotExported' in str(e): # ignore if device is offline logger.warning(f"Device {device} offline") @@ -152,11 +132,67 @@ class Archiver(): logger.warning(f"Device {device} not found") elif 'DB_DeviceNotDefined' in str(e): logger.warning(f"Device {device} not defined in TangoDB") - elif 'already subscribed' in str(e): - logger.warning(f"Multiple entries of Attribute {device}'/'{att} in config file") else: raise Exception from e + def configure_for_development(self, config_dict:dict, device:str): + """ + Procedure that enables the Archiving configuration in a 'development' environment + """ + environment = 'development' + # Retrieve global parameters + dev_polling_time, dev_archive_abs_change, dev_archive_rel_change, dev_archive_period, dev_event_period, dev_strategy = get_global_env_parameters(config_dict, environment) + # Attributes to be included in archiving stategy + include_att_list = get_include_attribute_list(device, config_dict, environment) + self.remove_attributes_by_device(device, exclude=include_att_list) + # Include attributes by custom configuration + try: + for att in include_att_list: + # Retrieve specific attribute parameters from config file + archive_period, event_period, abs_change, rel_change = get_parameters_from_attribute(device,att,config_dict,environment) + att_fqname = attribute_fqdn(f"{device}/{att}") + # Add the attribute to the archiver setting either specific or global parameters + self.add_attribute_to_archiver(att_fqname, dev_polling_time, archive_period or dev_archive_period, dev_strategy, + abs_change or dev_archive_abs_change, rel_change or dev_archive_rel_change) + except DevFailed as e: + if 'already subscribed' in str(e): + logger.warning(f"Multiple entries of Attribute {device}'/'{att} in config file") + else: + raise + + def configure_for_production(self, config_dict:dict, device:str): + """ + Procedure that enables the Archiving configuration in a 'production' environment + """ + environment = 'production' + # Retrieve global parameters + prod_polling_time, prod_archive_abs_change, prod_archive_rel_change, prod_archive_period, prod_event_period, prod_strategy = get_global_env_parameters(config_dict, environment) + # Cleanup the subscriber + self.remove_attributes_by_device(device) + attribute_list = DeviceProxy(device).get_attribute_list() + try: + # Add attributes in 'suffixes' and 'infixes' list which have different parameters + for att in attribute_list: + archive_period, event_period, abs_change, rel_change = get_parameters_from_attribute(device,att,config_dict,environment) + att_fqname = attribute_fqdn(f"{device}/{att}") + self.add_attribute_to_archiver(att_fqname, prod_polling_time, archive_period or prod_archive_period, prod_strategy, + abs_change or prod_archive_abs_change, rel_change or prod_archive_rel_change) + exclude_att_list = get_exclude_attribute_list(device, config_dict) + # Add all the other attributes except the ones in exclude list + self.add_attributes_by_device(device, global_archive_period = prod_archive_period, global_abs_change = prod_archive_abs_change, + global_rel_change = prod_archive_rel_change, exclude=exclude_att_list) + # Remove attributes by custom configuration if already present + # The following cycle is a security check in the special case that an attribute is in the + # included list in DEV mode, and in the excluded list in PROD mode + for att in exclude_att_list: + att_fqname = attribute_fqdn(f"{device}/{att}") + self.remove_attribute_from_archiver(att_fqname) + except DevFailed as e: + if 'already subscribed' in str(e): + logger.warning(f"Multiple entries of Attribute {device}'/'{att} in config file") + else: + raise + def add_event_subscriber(self, es_name:str=None): """ Add an additional Event Subscriber to the Configuration Manager @@ -177,7 +213,7 @@ class Archiver(): else: raise - def add_attribute_to_archiver(self, attribute_name: str, polling_period: int, event_period: int, strategy: str = 'RUN', + def add_attribute_to_archiver(self, attribute_name: str, polling_period: int, archive_event_period: int, strategy: str = 'RUN', abs_change: int = 1, rel_change: int = None, es_name:str=None): """ Takes as input the attribute name, polling period (ms), event period (ms) and archiving strategy, @@ -191,18 +227,19 @@ class Archiver(): self.cm.write_attribute('SetArchiver', es_name or self.get_next_subscriber()) self.cm.write_attribute('SetStrategy', strategy) self.cm.write_attribute('SetPollingPeriod', polling_period) - self.cm.write_attribute('SetPeriodEvent', event_period) + self.cm.write_attribute('SetPeriodEvent', archive_event_period) if abs_change is not None: self.cm.write_attribute('SetAbsoluteEvent', abs_change) if rel_change is not None: self.cm.write_attribute('SetRelativeEvent', rel_change) self.cm.AttributeAdd() logger.info(f"Attribute {attribute_name} added to archiving list!") except DevFailed as e: - if e.args[0].reason == 'Already archived': + if e.args[0].reason == 'Already archived' or 'already subscribed' in str(e) : logger.warning(f"Attribute {attribute_name} already in archiving list!") else: raise - def add_attributes_by_device(self, device_name, global_archive_period:int = None, es_name:str=None, exclude:list = None): + def add_attributes_by_device(self, device_name, global_archive_period:int = None, global_abs_change:int = None, + global_rel_change:int = None, es_name:str=None, exclude:list = None): """ Add sequentially all the attributes of the selected device in the event subscriber list, if not already present """ @@ -225,8 +262,10 @@ class Archiver(): es = DeviceProxy(es_name or self.get_next_subscriber()) # choose an e.s. or get the first one available polling_period = attr_proxy.get_poll_period() or self.dev_polling_time archive_period = global_archive_period or int(attr_proxy.get_property('archive_period')['archive_period'][0]) or self.dev_archive_period + abs_change = global_abs_change or 1 + rel_change = global_rel_change self.add_attribute_to_archiver(attr_fullname,polling_period=polling_period, - event_period=archive_period, abs_change=1, rel_change=None, es_name = es.name()) + archive_event_period = archive_period, abs_change=abs_change, rel_change=rel_change, es_name = es.name()) except IndexError as e: logger.warning(f"Attribute {attr_fullname} will not be archived because archive event period is not defined!") except Exception as e: @@ -320,14 +359,14 @@ class Archiver(): # so check whether an exact match is included. return any(attribute_name == a for a in attributes) - def update_archiving_attribute(self, attribute_name: str, polling_period: int, event_period: int, strategy: str = 'RUN'): + def update_archiving_attribute(self, attribute_name: str, polling_period: int, archive_period: int, strategy: str = 'RUN'): """ Update the archiving properties of an attribute already in a subscriber list """ attribute_name = attribute_fqdn(attribute_name) self.remove_attribute_from_archiver(attribute_name) time.sleep(3.) - self.add_attribute_to_archiver(attribute_name,polling_period,event_period,strategy) + self.add_attribute_to_archiver(attribute_name,polling_period,archive_period,strategy) time.sleep(3.) self.start_archiving_attribute(attribute_name) logger.info(f"Attribute {attribute_name} successfully updated!") diff --git a/tangostationcontrol/tangostationcontrol/toolkit/archiver_config/lofar2.json b/tangostationcontrol/tangostationcontrol/toolkit/archiver_config/lofar2.json index c519686dd99c7e47d719fc95ce8c82e6db2a8ba7..b81b46cf111b0743791c3b60f3151c10022a1ac2 100644 --- a/tangostationcontrol/tangostationcontrol/toolkit/archiver_config/lofar2.json +++ b/tangostationcontrol/tangostationcontrol/toolkit/archiver_config/lofar2.json @@ -1,36 +1,56 @@ { "_global_variables": { - "development_polling_time": "1000", - "development_archive_abs_change": "1", - "development_archive_rel_change": null, - "development_archive_period": "10000", - "development_event_period": "1000", - "development_strategy": "RUN" - + "development": { + "polling_time": "1000", + "archive_abs_change": "1", + "archive_rel_change": null, + "archive_period": "10000", + "event_period": "1000", + "strategy": "RUN", + "suffixes":[ + {"attribute": "_error_R", "archive_period": "10000", "event_period": "1000", "abs_change": "1", "rel_change": null}, + {"attribute": "_good_R", "archive_period": "10000", "event_period": "1000", "abs_change": "1", "rel_change": null}, + {"attribute": "_mask_RW", "archive_period": "10000", "event_period": "1000", "abs_change": "1", "rel_change": null}, + {"attribute": "_version_R", "archive_period": "60000", "event_period": "10000", "abs_change": "1", "rel_change": null} + ] + }, + "production":{ + "polling_time": "1000", + "archive_abs_change": "1", + "archive_rel_change": null, + "archive_period": "3600000", + "event_period": "60000", + "strategy": "RUN", + "infixes":[ + {"attribute": "/*IOUT*", "archive_period": "60000", "event_period": "1000", "abs_change": null, "rel_change": 5}, + {"attribute": "/*VOUT*", "archive_period": "60000", "event_period": "1000", "abs_change": null, "rel_change": 5}, + {"attribute": "/*TEMP*", "archive_period": "60000", "event_period": "1000", "abs_change": 0.5, "rel_change": 5} + ], + "suffixes":[ + {"attribute": "_error_R", "archive_period": "60000", "event_period": "1000", "abs_change": "1", "rel_change": null}, + {"attribute": "_good_R", "archive_period": "60000", "event_period": "1000", "abs_change": "1", "rel_change": null}, + {"attribute": "_mask_RW", "archive_period": "3600000", "event_period": "1000", "abs_change": "1", "rel_change": null} + ] + } }, - "_global_suffixes":[ - {"attribute": "_error_R", "archive_period": "10000", "event_period": "1000", "abs_change": "1", "rel_change": null}, - {"attribute": "_good_R", "archive_period": "10000", "event_period": "1000", "abs_change": "1", "rel_change": null}, - {"attribute": "_mask_RW", "archive_period": "10000", "event_period": "1000", "abs_change": "1", "rel_change": null}, - {"attribute": "_version_R", "archive_period": "60000", "event_period": "10000", "abs_change": "1", "rel_change": null} - ], "devices": { - "STAT/RECV/1": { + "STAT/Beamlet/1": { "environment": "development", "exclude": [ - "CLK_Enable_PWR_R", - "CLK_I2C_STATUS_R", - "CLK_PLL_error_R", - "CLK_PLL_locked_R", - "CLK_translator_busy_R" + "FPGA_bf_weights_*" ], "include": [] }, + "STAT/RECV/1": { + "environment": "development", + "exclude": [], + "include": [] + }, "STAT/SDP/1": { "environment": "development", "exclude": [ - "FPGA_scrap_R", - "FPGA_scrap_RW" + "FPGA_scrap_*", + "FPGA_signal_input_*" ], "include": [ {"attribute":"FPGA_temp_R", "archive_period": "10000", "event_period": "1000", "abs_change": "1", "rel_change": null}, @@ -39,7 +59,12 @@ }, "STAT/SST/1": { "environment": "development", - "exclude": [], + "exclude": [ + "sst_R", + "sst_timestamp_R", + "integration_interval_R", + "subbands_calibrated_R" + ], "include": [] }, "STAT/UNB2/1": { @@ -49,7 +74,10 @@ }, "STAT/XST/1": { "environment": "development", - "exclude": [], + "exclude": [ + "xst_*_R", + "integration_interval_R" + ], "include": [] } } diff --git a/tangostationcontrol/tangostationcontrol/toolkit/archiver_configurator.py b/tangostationcontrol/tangostationcontrol/toolkit/archiver_configurator.py new file mode 100644 index 0000000000000000000000000000000000000000..f6e9e60d1a57892598495e81bfe6679c5e7dfd98 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/toolkit/archiver_configurator.py @@ -0,0 +1,83 @@ +#! /usr/bin/env python3 + +""" + +Functions related to the managing of the archiver configuration JSON file + +""" +import logging +import re +from tangostationcontrol.toolkit.archiver_util import get_attributes_from_suffix, retrieve_attributes_from_wildcards + +logger = logging.getLogger() + +def _get_archiving_parameters(attribute:str): + """Helper function that returns the following archiving parameters defined in a JSON file: + archive period [ms], event period [ms], absolute change, relative change + """ + archive_period = int(attribute['archive_period']) + event_period = int(attribute['event_period']) + abs_change = attribute['abs_change'] and int(attribute['abs_change']) + rel_change = attribute['rel_change'] and int(attribute['rel_change']) + return archive_period, event_period, abs_change, rel_change + +def get_parameters_from_attribute(device_name:str, attribute_name:str, config_dict:dict, environment: str): + """ + Return the archiving parameters ( see ref.: '_get_archiving_parameters' ) + defined in the configuration file for a certain attribute + """ + if environment == 'development': + # Search if the attribute parameters are listed inside the device configuration + included_attrs = config_dict['devices'][device_name]['include'] + for a in included_attrs: + if attribute_name.lower() == a['attribute'].lower(): + return _get_archiving_parameters(a) + elif environment == 'production': + # Search if the archiving parameters are listed inside the global infixes attributes + infixes = config_dict['_global_variables'][environment]['infixes'] + for a in infixes: + # Match regular expression with attribute name + if re.compile(a['attribute'].lower()).search(attribute_name): + return _get_archiving_parameters(a) + # Search if the archiving parameters are listed inside the global suffixes attributes + suffixes = config_dict['_global_variables'][environment]['suffixes'] + for a in suffixes: + if attribute_name.lower().endswith(a['attribute'].lower()): + return _get_archiving_parameters(a) + return None, None, None, None + +def get_include_attribute_list(device:str, config_dict:dict, environment:str): + """ + Return the list of attributes that must be archived from the JSON configuration file + """ + suffixes = config_dict['_global_variables'][environment]['suffixes'] + # Attributes to be included in archiving stategy + include_att_list = [] + include_node = config_dict['devices'][device].get('include',[]) + for a in include_node: + include_att_list.append(a['attribute']) + # Add attributes with defined suffixes + include_att_list.extend(get_attributes_from_suffix(device,suffixes)) + return include_att_list + +def get_exclude_attribute_list(device:str, config_dict:dict): + """ + Return the list of attributes that must not be archived from the JSON configuration file + """ + exclude_list = config_dict['devices'][device].get('exclude', []) # may contain wildcards + exclude_att_list = retrieve_attributes_from_wildcards(device,exclude_list) + return exclude_att_list + +def get_global_env_parameters(config_dict:dict, environment:str): + """Return the following archiving parameters defined in the 'global_variable' section of the JSON configuration file: + polling time [ms], absolute change, relative change, archive period [ms], event period [ms] and strategy + """ + var_dict = config_dict['_global_variables'] + # Archiving parameters retrieved from JSON file + polling_time = int(var_dict[environment]['polling_time']) + archive_abs_change = var_dict[environment]['archive_abs_change'] and int(var_dict[environment]['archive_abs_change']) + archive_rel_change = var_dict[environment]['archive_rel_change'] and int(var_dict[environment]['archive_rel_change']) + archive_period = int(var_dict[environment]['archive_period']) + event_period = int(var_dict[environment]['event_period']) + strategy = var_dict[environment]['strategy'] + return polling_time, archive_abs_change, archive_rel_change, archive_period, event_period, strategy diff --git a/tangostationcontrol/tangostationcontrol/toolkit/archiver_util.py b/tangostationcontrol/tangostationcontrol/toolkit/archiver_util.py index b01c8c51f4f33b72d926136d1b6bf42ebde26490..bc6e2b37ad37c9f3f9638f54c4f5b9c25c8f5a3f 100644 --- a/tangostationcontrol/tangostationcontrol/toolkit/archiver_util.py +++ b/tangostationcontrol/tangostationcontrol/toolkit/archiver_util.py @@ -5,6 +5,7 @@ """ from tango import DeviceProxy +import re def get_db_config(device_name:str) -> dict: """ @@ -90,24 +91,16 @@ def get_attributes_from_suffix(device_name:str, suffixes:list): result.extend([a for a in attribute_list if a.lower().endswith(att_name.lower())]) return result -def get_parameters_from_attribute(device_name:str, attribute_name:str, suffixes: list, config_dict:dict): +def retrieve_attributes_from_wildcards(device_name: str, matching_list: list): """ - Return the archiving parameters defined in the configuration file for a certain attribute + Return a list of device attibutes based on given wildcards and/or attribute names """ - # Search if the attribute parameters are listed inside the device configuration - included_attrs = config_dict['devices'][device_name]['include'] - for a in included_attrs: - if attribute_name.lower() == a['attribute'].lower(): - archive_period = int(a['archive_period']) - event_period = int(a['event_period']) - abs_change = a['abs_change'] and int(a['abs_change']) - rel_change = a['rel_change'] and int(a['rel_change']) - return archive_period, event_period, abs_change, rel_change - # Search if the archiving parameters are listed inside the global suffixes attributes - for a in suffixes: - if attribute_name.lower().endswith(a['attribute'].lower()): - archive_period = int(a['archive_period']) - event_period = int(a['event_period']) - abs_change = a['abs_change'] and int(a['abs_change']) - rel_change = a['rel_change'] and int(a['rel_change']) - return archive_period, event_period, abs_change, rel_change + device = DeviceProxy(device_name) + attribute_list = device.get_attribute_list() + matched_list = [] + for m in matching_list: + pattern = re.compile(m) + for a in attribute_list: + if pattern.search(a): + matched_list.append(a) + return matched_list