Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/drunc/authoriser/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@


class DummyAuthoriserConfHandler(ConfHandler):
pass
"""Handler for dummy authoriser configuration."""

def populate_from_dict(self, data: dict[str, object]) -> None:
pass
13 changes: 9 additions & 4 deletions src/drunc/controller/children_interface/grpc_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,17 @@


class gRCPChildConfHandler(ConfHandler):
"""Handler for gRPC child node configuration."""

def _post_process_oks(self) -> None:
self.controller = self._raw_data.controller

def get_uri(self):
for service in self.data.controller.exposes_service:
if self.data.controller.id + "_control" in service.id:
return f"{service.protocol}://{self.data.controller.runs_on.runs_on.id}:{service.port}"
for service in self.controller.exposes_service:
if self.controller.id + "_control" in service.id:
return f"{service.protocol}://{self.controller.runs_on.runs_on.id}:{service.port}"
raise DruncSetupException(
f"gRPC API child node {self.data.controller.id} does not expose a control service"
f"gRPC API child node {self.controller.id} does not expose a control service"
)


Expand Down
41 changes: 26 additions & 15 deletions src/drunc/controller/children_interface/rest_api_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,12 +355,24 @@ def check_response(self, timeout: int = 0) -> dict:


class RESTAPIChildNodeConfHandler(ConfHandler):
"""Handler for REST API child node configuration."""

def _post_process_oks(self) -> None:
raw = self._raw_data
# Flatten attributes that are always accessed from outside
self.id = getattr(raw, "id", None)
self.exposes_service = getattr(raw, "exposes_service", [])
self.runs_on = getattr(raw, "runs_on", None)
self.proxy = getattr(raw, "proxy", [None, None])
# Pass through any other attributes callers may inspect dynamically
self._raw = raw

def get_host_port(self):
for service in self.data.exposes_service:
if self.data.id + "_control" in service.id:
return self.data.runs_on.runs_on.id, service.port
for service in self.exposes_service:
if self.id + "_control" in service.id:
return self.runs_on.runs_on.id, service.port
raise DruncSetupException(
f"REST API child node {self.data.id} does not expose a control service"
f"REST API child node {self.id} does not expose a control service"
)


Expand All @@ -379,7 +391,7 @@ def __init__(
self.fsm_configuration = fsm_configuration
self.connectivity_service = connectivity_service
if fsm_configuration:
fsmch = FSMConfHandler(fsm_configuration)
fsmch = FSMConfHandler.from_pyobject(data=fsm_configuration)
self.fsm = FSM(conf=fsmch)

response_listener_host = socket.gethostname()
Expand All @@ -392,7 +404,7 @@ def __init__(
f"Application {name} does not expose a control service in the configuration, or has not advertised itself to the application registry service, or the application registry service is not reachable."
)

proxy_host, proxy_port = getattr(self.configuration.data, "proxy", [None, None])
proxy_host, proxy_port = self.configuration.proxy
proxy_port = int(proxy_port) if proxy_port is not None else None

self.commander = AppCommander(
Expand Down Expand Up @@ -542,16 +554,15 @@ def describe(
if self.configuration is not None:
if detector_name := get_detector_name(self.configuration):
description.info = detector_name
if hasattr(
self.configuration.data, "application_name"
): # Application nodes.
description.type = self.configuration.data.application_name
description.name = self.configuration.data.id
elif hasattr(self.configuration.data, "controller") and hasattr(
self.configuration.data.controller, "application_name"
raw = self.configuration._raw
if hasattr(raw, "application_name"): # Application nodes.
description.type = raw.application_name
description.name = raw.id
elif hasattr(raw, "controller") and hasattr(
raw.controller, "application_name"
): # Controller nodes.
description.type = self.configuration.data.controller.application_name
description.name = self.configuration.data.controller.id
description.type = raw.controller.application_name
description.name = raw.controller.id

response.description.CopyFrom(description)

Expand Down
49 changes: 19 additions & 30 deletions src/drunc/controller/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
)
from drunc.exceptions import DruncCommandException, DruncSetupException
from drunc.process_manager.configuration import get_commandline_parameters
from drunc.utils.configuration import ConfHandler, ConfTypes
from drunc.utils.configuration import ConfHandler
from drunc.utils.utils import (
ControlType,
get_control_type_and_uri_from_cli,
Expand All @@ -30,19 +30,9 @@
)


class ControllerConfData: # the bastardised OKS
def __init__(self):
class id_able:
id = None

class cler:
pass

self.controller = cler()
self.controller.fsm = id_able()


class ControllerConfHandler(ConfHandler):
"""Handler for controller configuration."""

@staticmethod
def find_segment(segment, id_):
if segment.controller.id == id_:
Expand All @@ -66,30 +56,29 @@ def _grab_segment_conf_from_controller(self, configuration):
)
return this_segment

def _post_process_oks(self, *args, **kwargs):
def _post_process_oks(self) -> None:
self.authoriser = None
self.data = self._grab_segment_conf_from_controller(self.data)
segment = self._grab_segment_conf_from_controller(self._raw_data)
self.controller = segment.controller
self.segments = segment.segments
self.applications = segment.applications

self.this_host = self.data.controller.runs_on.runs_on.id
self.this_host = self.controller.runs_on.runs_on.id
if self.this_host in ["localhost"] or self.this_host.startswith("127."):
self.this_host = socket.gethostname()

self.opmon_publisher = None
self.opmon_conf = parse_opmon_conf(
log=self.log,
conf=self.data.controller.opmon_conf,
conf=self.controller.opmon_conf,
uri=self.session.opmon_uri,
session=self.session_name,
application=self.data.controller.id,
application=self.controller.id,
)

if self.opmon_conf.path == "./info.json":
self.opmon_conf.path = (
"./info."
+ self.opmon_conf.session
+ "."
+ self.data.controller.id
+ ".json"
"./info." + self.opmon_conf.session + "." + self.controller.id + ".json"
)

self.log.debug("Initializing OpMon with configuration %s", self.opmon_conf)
Expand Down Expand Up @@ -193,13 +182,13 @@ def process_application(app):
# threading the children look up
threads = []

for segment in self.data.segments:
for segment in self.segments:
self.log.debug(segment)
t = threading.Thread(target=process_segment, args=(segment,))
threads.append(t)
t.start()

for app in self.data.applications:
for app in self.applications:
self.log.debug(app)
t = threading.Thread(target=process_application, args=(app,))
threads.append(t)
Expand Down Expand Up @@ -251,22 +240,22 @@ def child_node_factory(

match ctype:
case ControlType.gRPC:
grpc_conf_handler = gRCPChildConfHandler(
configuration, ConfTypes.PyObject
grpc_conf_handler = gRCPChildConfHandler.from_pyobject(
data=configuration
)
return gRPCChildNode(
name, grpc_conf_handler, uri, connectivity_service, init_token
)

case ControlType.REST_API:
restapi_conf_handler = RESTAPIChildNodeConfHandler(
configuration, ConfTypes.PyObject
restapi_conf_handler = RESTAPIChildNodeConfHandler.from_pyobject(
data=configuration
)
return RESTAPIChildNode(
name,
restapi_conf_handler,
uri,
self.data.controller.fsm,
self.controller.fsm,
connectivity_service=connectivity_service,
)

Expand Down
8 changes: 4 additions & 4 deletions src/drunc/controller/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ def __init__(self, configuration, name: str, session: str, token: Token):
self.stop_event: threading.Event | None = None
self.thread: threading.Thread | None = None

self.fsm_config = FSMConfHandler(
data=self.configuration.data.controller.fsm,
self.fsm_config = FSMConfHandler.from_pyobject(
data=self.configuration.controller.fsm,
)

self.stateful_node = StatefulNode(
Expand All @@ -118,7 +118,7 @@ def __init__(self, configuration, name: str, session: str, token: Token):
top_segment_controller=self.top_segment_controller,
)

dach = DummyAuthoriserConfHandler(
dach = DummyAuthoriserConfHandler.from_pyobject(
data=self.configuration.authoriser,
)
self.authoriser = DummyAuthoriser(dach, SystemType.CONTROLLER)
Expand Down Expand Up @@ -230,7 +230,7 @@ def init_controller(self) -> None:
log_init_controller.info(f"Taking control of {child.name}")
child.take_control(execute_on_all_subsequent_children_in_path=True)

interval_s = getattr(self.configuration.data, "interval_s", 10.0)
interval_s = getattr(self.configuration, "interval_s", 10.0)

if self.opmon_publisher is not None:
self.stop_event = threading.Event()
Expand Down
14 changes: 0 additions & 14 deletions src/drunc/controller/interface/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,6 @@ def create_drivers(self, **kwargs) -> Mapping[str, object]:
def create_token(self, **kwargs) -> Token:
return create_dummy_token_from_uname()

def get_endpoint_display_host_overrides(self) -> dict[str, str]:
"""
Return display hostname overrides for status-table rendering.

Returns an empty dict because this context connects directly to a
controller without a process manager, so no per-process hostname
metadata is available.

Returns:
dict[str, str]: Mapping of {process_name: hostname}.
Always empty for this context.
"""
return {}

def terminate(self):
if self.status_receiver:
self.status_receiver.stop()
7 changes: 3 additions & 4 deletions src/drunc/controller/interface/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
CONTROLLER_SERVER_GRPC_CONFIG,
CONTROLLER_SERVER_GRPC_MAX_WORKERS,
)
from drunc.utils.configuration import ConfTypes, OKSKey
from drunc.utils.configuration import OKSKey
from drunc.utils.utils import (
get_logger,
get_root_logger,
Expand Down Expand Up @@ -86,9 +86,8 @@ def controller_cli(
token="",
)

controller_configuration = ControllerConfHandler(
type=ConfTypes.OKSFileName,
data=configurationservice,
controller_configuration = ControllerConfHandler.from_oks(
url=configurationservice,
oks_key=OKSKey(
schema_file="schema/confmodel/dunedaq.schema.xml",
class_name="RCApplication",
Expand Down
13 changes: 6 additions & 7 deletions src/drunc/controller/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,16 @@ def get_status_message(controller):
def get_detector_name(configuration) -> str:
detector_name = None
log = get_logger("controller.core.get_detector_name")
if hasattr(configuration.data, "contains") and len(configuration.data.contains) > 0:
if len(configuration.data.contains) > 0:
raw = getattr(configuration, "_raw", None)
if raw is not None and hasattr(raw, "contains") and len(raw.contains) > 0:
if len(raw.contains) > 0:
log.debug(
f"Application {configuration.data.id} has multiple contains, using the first one"
f"Application {raw.id} has multiple contains, using the first one"
)
detector_name = (
configuration.data.contains[0].id.replace("-", "_").replace("_", " ")
)
detector_name = raw.contains[0].id.replace("-", "_").replace("_", " ")
else:
log.debug(
f'Application {configuration.data.id} has no "contains" relation, hence no detector'
f'Application {getattr(raw, "id", "?")} has no "contains" relation, hence no detector'
)
return detector_name

Expand Down
Loading
Loading