Merge branch 'main' into SIENTIAPDE-988-criar-ingestor-opc
This commit is contained in:
@@ -2,11 +2,12 @@ from logging import Logger
|
||||
import traceback
|
||||
from typing import Dict, List
|
||||
from copy import deepcopy
|
||||
from sientia_do.notifications.handlers import NotificationHandler
|
||||
from sientia_do.notifications.models import NotificationLevel
|
||||
from ingestor.managers.data_manager import DataManager
|
||||
from ingestor.managers.opc_manager import OpcManager
|
||||
from ingestor.managers.resource_manager import ResourceManager
|
||||
from sientia_do.notifications.models import Notification, NotificationLevel
|
||||
from sientia_do.notifications.handlers import NotificationHandler
|
||||
import ingestor.metrics as metrics
|
||||
|
||||
|
||||
class IngestorManager():
|
||||
@@ -29,8 +30,10 @@ class IngestorManager():
|
||||
self.opc_servers = {}
|
||||
|
||||
self.notification_handler = notification_handler
|
||||
self.pod_id = pod_id
|
||||
|
||||
def initialize_opc_from_config(self, server_config: dict, data_manager: DataManager, logger: Logger) -> OpcManager | None:
|
||||
def initialize_opc_from_config(self, server_config: dict,
|
||||
data_manager: DataManager, logger: Logger) -> OpcManager | None:
|
||||
"""
|
||||
Initializes an OPC Manager instance using the provided server configuration.
|
||||
Args:
|
||||
@@ -53,9 +56,11 @@ class IngestorManager():
|
||||
self.logger.info(
|
||||
f"Initializing OpcManager at {server_config['url']}")
|
||||
manager = OpcManager(
|
||||
server_config['name'], server_config['url'], data_manager, logger, server_config['server_uri'],
|
||||
self.notification_handler, server_config.get('cert_path'), server_config.get(
|
||||
'private_key_path'), server_config.get('server_cert_path')
|
||||
server_config['name'], server_config['url'],
|
||||
data_manager, logger, server_config['server_uri'],
|
||||
self.notification_handler, self.pod_id, server_config.get('cert_path'),
|
||||
server_config.get('private_key_path'),
|
||||
server_config.get('server_cert_path')
|
||||
)
|
||||
|
||||
manager.config = server_config
|
||||
@@ -76,6 +81,14 @@ class IngestorManager():
|
||||
|
||||
return manager
|
||||
|
||||
def shutdown(self):
|
||||
for _server_name, server in self.opc_managers.items():
|
||||
server.disconnect()
|
||||
self.data_manager.shutdown()
|
||||
|
||||
def __del__(self):
|
||||
self.shutdown()
|
||||
|
||||
def update_opc_servers(self):
|
||||
"""
|
||||
Updates the OPC (OLE for Process Control) server connections managed by the ingestor.
|
||||
@@ -91,7 +104,8 @@ class IngestorManager():
|
||||
4. Disconnects and removes OPC servers that are no longer registered.
|
||||
Attributes:
|
||||
self.managed_tags (dict): A nested dictionary containing slot and server configurations.
|
||||
self.opc_managers (dict): A dictionary mapping server names to their OPC manager instances.
|
||||
self.opc_managers (dict): A dictionary mapping server names to their
|
||||
OPC manager instances.
|
||||
self.data_manager: An object responsible for managing data operations.
|
||||
self.logger: A logging object for recording warnings and other messages.
|
||||
Raises:
|
||||
@@ -101,27 +115,44 @@ class IngestorManager():
|
||||
"""
|
||||
|
||||
registered_servers = []
|
||||
for slot, slot_config in self.managed_tags.items():
|
||||
current_managed_tags = deepcopy(self.managed_tags)
|
||||
for _slot, slot_config in current_managed_tags.items():
|
||||
for server, server_config in slot_config.items():
|
||||
registered_servers.append(server)
|
||||
server_config = server_config.copy()
|
||||
server_config = deepcopy(server_config)
|
||||
server_config.pop('tags', None)
|
||||
server_instance = None
|
||||
if server not in self.opc_managers:
|
||||
|
||||
server_instance = self.opc_managers.get(server, None)
|
||||
if server_instance is None:
|
||||
self.logger.debug(
|
||||
f"Initializing OPC manager for server {server}"
|
||||
)
|
||||
server_instance = self.initialize_opc_from_config(
|
||||
server_config, self.data_manager, self.logger
|
||||
)
|
||||
|
||||
elif self.opc_managers[server].config != server_config:
|
||||
self.opc_managers[server].disconnect()
|
||||
elif server_instance.config != server_config:
|
||||
self.logger.warning(
|
||||
f"Reinitializing OPC manager for server {server}"
|
||||
)
|
||||
server_instance.disconnect()
|
||||
del self.opc_managers[server]
|
||||
server_instance = self.initialize_opc_from_config(
|
||||
server_config, self.data_manager, self.logger
|
||||
)
|
||||
else:
|
||||
self.logger.debug(
|
||||
f"OPC manager for server {server} is already initialized and up to date"
|
||||
)
|
||||
|
||||
if server_instance is not None:
|
||||
self.opc_managers[server] = server_instance
|
||||
else:
|
||||
self.logger.warning(
|
||||
f"Failed to initialize OPC manager for server {server}, "
|
||||
f"removing server from managed tags."
|
||||
)
|
||||
_a = [self.managed_tags[slot].pop(server, None)
|
||||
for slot, _value in current_managed_tags.items()]
|
||||
|
||||
for server in list(self.opc_managers.keys()):
|
||||
if server not in registered_servers:
|
||||
@@ -132,6 +163,8 @@ class IngestorManager():
|
||||
self.opc_managers[server].disconnect()
|
||||
self.opc_managers.pop(server, None)
|
||||
|
||||
metrics.OPC_MANAGERS_ACTIVE.labels(pod_id=self.pod_id).set(len(self.opc_managers))
|
||||
|
||||
def check_opc_servers_integrity(self):
|
||||
"""
|
||||
Checks the integrity of the OPC servers and updates the OPC servers if necessary.
|
||||
@@ -143,18 +176,13 @@ class IngestorManager():
|
||||
if is_lost:
|
||||
self.logger.warning(
|
||||
f"OPC server {server} is lost. "
|
||||
f"Desconnecting from server."
|
||||
f"Server will be disconnected."
|
||||
)
|
||||
opc_manager.disconnect()
|
||||
self.opc_managers[server] = self.initialize_opc_from_config(
|
||||
opc_manager.config, self.data_manager, self.logger
|
||||
)
|
||||
self.update_opc_servers()
|
||||
for slot, slot_config in self.managed_tags.items():
|
||||
if server in slot_config:
|
||||
self.manage_server(
|
||||
slot, server, slot_config[server], slot_config[server]['tags']
|
||||
)
|
||||
|
||||
for slot, _config in self.managed_tags.items():
|
||||
self.managed_tags[slot].pop(server, None)
|
||||
|
||||
metrics.OPC_MANAGERS_ACTIVE.labels(pod_id=self.pod_id).set(len(self.opc_managers))
|
||||
|
||||
def declare_active(self):
|
||||
"""
|
||||
@@ -188,6 +216,7 @@ class IngestorManager():
|
||||
|
||||
leases = self.resource_manager.get_all_leases()
|
||||
self.number_of_slots = len(leases) if leases else 0
|
||||
metrics.LEASES_TOTAL.set(self.number_of_slots)
|
||||
return self.number_of_slots
|
||||
|
||||
def get_number_of_slots(self) -> int:
|
||||
@@ -201,6 +230,7 @@ class IngestorManager():
|
||||
|
||||
slots = self.resource_manager.get_all_slots()
|
||||
self.number_of_slots = len(slots) if slots else 0
|
||||
metrics.SLOTS_TOTAL.set(self.number_of_slots)
|
||||
return self.number_of_slots
|
||||
|
||||
def get_slot_leases(self, max_slots: int = 1) -> Dict:
|
||||
@@ -212,14 +242,16 @@ class IngestorManager():
|
||||
Dict: A dictionary where the keys are the slot identifiers (as strings)
|
||||
and the values are the leased slot details.
|
||||
Behavior:
|
||||
- Iterates through available slots and attempts to lease them using the resource manager.
|
||||
- Iterates through available slots and attempts to lease
|
||||
them using the resource manager.
|
||||
- Logs the leasing of each slot.
|
||||
- Updates the `managed_tags` attribute with the acquired slots.
|
||||
- Stops leasing once the specified `max_slots` are acquired.
|
||||
- If unable to acquire the requested number of slots, logs a warning and returns the slots that were leased.
|
||||
- If unable to acquire the requested number of slots,
|
||||
logs a warning and returns the slots that were leased.
|
||||
Notes:
|
||||
- If a slot is leased but its details cannot be retrieved (i.e., `get_tag_slot` returns None),
|
||||
that slot is skipped.
|
||||
- If a slot is leased but its details cannot be retrieved
|
||||
(i.e., `get_tag_slot` returns None), that slot is skipped.
|
||||
"""
|
||||
|
||||
acquired = {}
|
||||
@@ -230,9 +262,11 @@ class IngestorManager():
|
||||
if slots is None:
|
||||
continue
|
||||
acquired[str(i)] = slots
|
||||
metrics.SLOTS_ACQUIRED.labels(pod_id=self.pod_id).inc()
|
||||
|
||||
if len(acquired) >= max_slots:
|
||||
self.managed_tags.update(acquired)
|
||||
metrics.SLOTS_MANAGED.labels(pod_id=self.pod_id).set(len(self.managed_tags))
|
||||
return acquired
|
||||
|
||||
self.logger.warning(
|
||||
@@ -240,6 +274,7 @@ class IngestorManager():
|
||||
f"Only {acquired} slots were leased."
|
||||
)
|
||||
self.managed_tags.update(acquired)
|
||||
metrics.SLOTS_MANAGED.labels(pod_id=self.pod_id).set(len(self.managed_tags))
|
||||
return acquired
|
||||
|
||||
def unsubscribe_slot(self, slot: str):
|
||||
@@ -280,33 +315,17 @@ class IngestorManager():
|
||||
|
||||
removed_slots = []
|
||||
update = {}
|
||||
for slot, slot_config in self.managed_tags.items():
|
||||
for slot, _slot_config in self.managed_tags.items():
|
||||
self.resource_manager.renew_tag_lease(slot)
|
||||
update = self.resource_manager.get_tag_slot(slot)
|
||||
if update is None:
|
||||
self.logger.warning(
|
||||
f"Slot {slot} configuration not found. "
|
||||
f"Removing slot from managed tags."
|
||||
)
|
||||
self.unsubscribe_slot(slot)
|
||||
removed_slots.append(slot)
|
||||
|
||||
continue
|
||||
|
||||
if update != slot_config:
|
||||
self.logger.info(
|
||||
f"Slot {slot} configuration updated. "
|
||||
f"Old: {slot_config}, New: {update}"
|
||||
)
|
||||
self.managed_tags[slot] = update
|
||||
|
||||
self.unsubscribe_slot(slot)
|
||||
self.update_opc_servers()
|
||||
self.subscribe_to_tags({slot: update})
|
||||
self.managed_tags[slot] = update
|
||||
|
||||
for slot in removed_slots:
|
||||
del self.managed_tags[slot]
|
||||
self.update_opc_servers()
|
||||
self.managed_tags.pop(slot, None)
|
||||
|
||||
def drop_slot_leases(self, ids: List[str]) -> None:
|
||||
"""
|
||||
@@ -321,8 +340,8 @@ class IngestorManager():
|
||||
None
|
||||
"""
|
||||
|
||||
for _id in ids:
|
||||
self.resource_manager.drop_tag_lease(_id)
|
||||
self.resource_manager.drop_tag_lease(lease_id)
|
||||
metrics.SLOTS_RELEASED.labels(pod_id=self.pod_id).inc()
|
||||
|
||||
def manage_server(self, slot: str, server: str, server_config: dict, tags: dict) -> int:
|
||||
"""
|
||||
@@ -381,6 +400,7 @@ class IngestorManager():
|
||||
tags_to_sub
|
||||
)
|
||||
except Exception as e:
|
||||
metrics.OPC_SUBSCRIPTION_ERRORS.labels(pod_id=self.pod_id, server=server, slot=slot).inc()
|
||||
trace = traceback.format_exc()
|
||||
self.notification_handler.build_and_send_notification(
|
||||
notification_id=f'OPC_SUBSCRIPTION_ERROR_{slot}:{server}',
|
||||
|
||||
Reference in New Issue
Block a user