From 9de9489c82dcb6cc44494466bfd8625cce644de0 Mon Sep 17 00:00:00 2001 From: MRiganSUSX Date: Thu, 9 Oct 2025 18:02:31 +0200 Subject: [PATCH 1/4] updating the script to work with ccm config changes --- .../daqconf/set_connectivity_service_port.py | 83 +++++++++++++------ 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/python/daqconf/set_connectivity_service_port.py b/python/daqconf/set_connectivity_service_port.py index d923b96d..97546def 100755 --- a/python/daqconf/set_connectivity_service_port.py +++ b/python/daqconf/set_connectivity_service_port.py @@ -1,48 +1,77 @@ import conffwk import confmodel_dal -from daqconf.utils import find_free_port +import socket +import random + +def find_free_k8s_nodeport(): + """ + Finds and returns an available TCP port within the k8s NodePort range (30000-32767). + """ + while True: + port = random.randint(30000, 32767) + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + try: + s.bind(("0.0.0.0", port)) + return port + except OSError: + continue -import re def set_connectivity_service_port(oksfile, session_name, connsvc_port=0): """Script to set the value of the Connectivity Service port in the specified Session of the specified - OKS database file. If the new port is not specified, it is set to a random available port number.""" + OKS database file. If the new port is not specified, it is set to a random available k8s NodePort.""" db = conffwk.Configuration("oksconflibs:" + oksfile) - if session_name == "": - print(f"Error: the session name needs to be specified") + if not session_name: + print("Error: the session name needs to be specified") return 0 else: try: session = db.get_dal("Session", session_name) - except: - print(f"Error could not find Session {session_name} in file {oksfile}") + except Exception: + print(f"Error: could not find Session {session_name} in file {oksfile}") return 0 - schemafiles = [ - "schema/confmodel/dunedaq.schema.xml" - ] - dal = conffwk.dal.module("dal", schemafiles) - + k8s_min_port, k8s_max_port = 30000, 32767 if connsvc_port == 0: - new_port = find_free_port() + new_port = find_free_k8s_nodeport() + print(f"Found free Kubernetes NodePort: {new_port}") else: new_port = connsvc_port + if not (k8s_min_port <= new_port <= k8s_max_port): + print(f"Warning: Port {new_port} is outside the standard k8s NodePort range ({k8s_min_port}-{k8s_max_port}).") - if session.connectivity_service is not None: - session.connectivity_service.service.port = new_port - db.update_dal(session.connectivity_service.service) + # This block has been removed as it was redundant and caused the confusing printout. + # if session.connectivity_service is not None: + # session.connectivity_service.service.port = new_port + # db.update_dal(session.connectivity_service.service) - for app in session.infrastructure_applications: - if app.className() == "ConnectionService": - index = 0 - for clparam in app.commandline_parameters: - if "gunicorn" in clparam: - pattern = re.compile(r'(.*0\.0\.0\.0)\:\d+(.*)') - app.commandline_parameters[index] = pattern.sub(f'\\1:{new_port}\\2', clparam) - #print(f"{app}") - db.update_dal(app) - break - index += 1 + if hasattr(session, 'environment') and session.environment is not None: + found_var = False + for item in session.environment: + if item.className() == 'VariableSet': + for var in item.contains: + if var.name == "CONNECTION_PORT": + var.value = str(new_port) + db.update_dal(var) + # This is now the only, and clearest, confirmation message. + print(f"Updated connection port variable '{var.id}' to {new_port}") + found_var = True + break + elif item.className() == 'Variable': + if item.name == "CONNECTION_PORT": + item.value = str(new_port) + db.update_dal(item) + print(f"Updated connection port variable '{item.id}' to {new_port}") + found_var = True + + if found_var: + break + + if not found_var: + print("Warning: Could not find a Variable named 'CONNECTION_PORT' in the session's environment.") + else: + print("Warning: Session has no 'environment' configured. Cannot update CONNECTION_PORT variable.") db.commit() + print(f"Successfully set connectivity service port for session '{session_name}'.") return new_port From fe963a5b10cf3d6de0562f9861be77ff60b9c08d Mon Sep 17 00:00:00 2001 From: MRiganSUSX Date: Wed, 15 Oct 2025 13:25:01 +0200 Subject: [PATCH 2/4] fixing script --- .../daqconf/set_connectivity_service_port.py | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/python/daqconf/set_connectivity_service_port.py b/python/daqconf/set_connectivity_service_port.py index 97546def..97cd4ba0 100755 --- a/python/daqconf/set_connectivity_service_port.py +++ b/python/daqconf/set_connectivity_service_port.py @@ -40,11 +40,16 @@ def set_connectivity_service_port(oksfile, session_name, connsvc_port=0): if not (k8s_min_port <= new_port <= k8s_max_port): print(f"Warning: Port {new_port} is outside the standard k8s NodePort range ({k8s_min_port}-{k8s_max_port}).") - # This block has been removed as it was redundant and caused the confusing printout. - # if session.connectivity_service is not None: - # session.connectivity_service.service.port = new_port - # db.update_dal(session.connectivity_service.service) + # Update the Service + if session.connectivity_service is not None: + session.connectivity_service.service.port = new_port + db.update_dal(session.connectivity_service.service) + print(f"Updated Connectivity Service '{session.connectivity_service.service.id}' to use port {new_port}") + else: + print(f"Warning: Session '{session_name}' has no connectivity_service defined. Skipping Service object update.") + + # Update the env var if hasattr(session, 'environment') and session.environment is not None: found_var = False for item in session.environment: @@ -53,25 +58,25 @@ def set_connectivity_service_port(oksfile, session_name, connsvc_port=0): if var.name == "CONNECTION_PORT": var.value = str(new_port) db.update_dal(var) - # This is now the only, and clearest, confirmation message. - print(f"Updated connection port variable '{var.id}' to {new_port}") + print(f"Updated runtime environment variable '{var.id}' to '{new_port}'") found_var = True break elif item.className() == 'Variable': if item.name == "CONNECTION_PORT": item.value = str(new_port) db.update_dal(item) - print(f"Updated connection port variable '{item.id}' to {new_port}") + print(f"Updated runtime environment variable '{item.id}' to '{new_port}'") found_var = True if found_var: break if not found_var: - print("Warning: Could not find a Variable named 'CONNECTION_PORT' in the session's environment.") + print("Warning: Could not find a 'CONNECTION_PORT' variable in the session's environment.") else: print("Warning: Session has no 'environment' configured. Cannot update CONNECTION_PORT variable.") db.commit() - print(f"Successfully set connectivity service port for session '{session_name}'.") + print(f"Successfully configured connectivity service port for session '{session_name}'.") return new_port + From d3826d4121cf5f168c69932a25e621e75946984b Mon Sep 17 00:00:00 2001 From: Kurt Biery Date: Thu, 23 Oct 2025 13:42:13 -0500 Subject: [PATCH 3/4] Combined the find_free_k8s_nodeport and find_free_port functions into a single one that supports an optional range; promoted a few warnings to errors in set_connectivity_service_port.py --- .../daqconf/set_connectivity_service_port.py | 34 ++++++------------- python/daqconf/utils.py | 32 +++++++++++++---- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/python/daqconf/set_connectivity_service_port.py b/python/daqconf/set_connectivity_service_port.py index 97cd4ba0..578d5442 100755 --- a/python/daqconf/set_connectivity_service_port.py +++ b/python/daqconf/set_connectivity_service_port.py @@ -1,21 +1,6 @@ import conffwk import confmodel_dal -import socket -import random - -def find_free_k8s_nodeport(): - """ - Finds and returns an available TCP port within the k8s NodePort range (30000-32767). - """ - while True: - port = random.randint(30000, 32767) - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - try: - s.bind(("0.0.0.0", port)) - return port - except OSError: - continue - +from daqconf.utils import find_free_port def set_connectivity_service_port(oksfile, session_name, connsvc_port=0): """Script to set the value of the Connectivity Service port in the specified Session of the specified @@ -33,7 +18,7 @@ def set_connectivity_service_port(oksfile, session_name, connsvc_port=0): k8s_min_port, k8s_max_port = 30000, 32767 if connsvc_port == 0: - new_port = find_free_k8s_nodeport() + new_port = find_free_port(k8s_min_port, k8s_max_port) print(f"Found free Kubernetes NodePort: {new_port}") else: new_port = connsvc_port @@ -46,8 +31,8 @@ def set_connectivity_service_port(oksfile, session_name, connsvc_port=0): db.update_dal(session.connectivity_service.service) print(f"Updated Connectivity Service '{session.connectivity_service.service.id}' to use port {new_port}") else: - print(f"Warning: Session '{session_name}' has no connectivity_service defined. Skipping Service object update.") - + print(f"Error: Session '{session_name}' has no connectivity_service defined. Skipping Service object update.") + return 0 # Update the env var if hasattr(session, 'environment') and session.environment is not None: @@ -67,16 +52,17 @@ def set_connectivity_service_port(oksfile, session_name, connsvc_port=0): db.update_dal(item) print(f"Updated runtime environment variable '{item.id}' to '{new_port}'") found_var = True - + if found_var: break - + if not found_var: - print("Warning: Could not find a 'CONNECTION_PORT' variable in the session's environment.") + print("Error: Could not find a 'CONNECTION_PORT' variable in the session's environment.") + return 0 else: - print("Warning: Session has no 'environment' configured. Cannot update CONNECTION_PORT variable.") + print("Error: Session has no 'environment' configured. Cannot update CONNECTION_PORT variable.") + return 0 db.commit() print(f"Successfully configured connectivity service port for session '{session_name}'.") return new_port - diff --git a/python/daqconf/utils.py b/python/daqconf/utils.py index fa3ecbdf..b245dda6 100755 --- a/python/daqconf/utils.py +++ b/python/daqconf/utils.py @@ -1,6 +1,7 @@ import glob import logging import os +import random import socket from rich.logging import RichHandler @@ -87,10 +88,27 @@ def find_oksincludes(includes:list[str], extra_dirs:list[str] = []): return [True, includefiles] -def find_free_port(): - with socket.socket() as s: - s.bind(("", 0)) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - port = s.getsockname()[1] - s.close() - return port +# This function returns a random available network port. Users can optionally +# specify a range that should be used. +def find_free_port(min_port_num:int=0, max_port_num:int=65535): + # If the user didn't specify a minimum port number (or deliberately specified + # zero), we can simply ask the system for an available port. + if min_port_num == 0: + with socket.socket() as s: + s.bind(("", 0)) + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + port = s.getsockname()[1] + s.close() + return port + # If the user specified a minimum port number, use the specified range. + else: + if min_port_num < 1024: + min_port_num = 1024 + while True: + port = random.randint(min_port_num, max_port_num) + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + try: + s.bind(("0.0.0.0", port)) + return port + except OSError: + continue From 9dd0f121e202c6b051664b0fcfd9ffeef4d2d549 Mon Sep 17 00:00:00 2001 From: MRiganSUSX Date: Tue, 4 Nov 2025 18:49:52 +0100 Subject: [PATCH 4/4] changes for k8s --- python/daqconf/set_rc_controller_port.py | 86 ++++++++++++++++++++++++ scripts/daqconf_set_rc_controller_port | 30 +++++++++ 2 files changed, 116 insertions(+) create mode 100644 python/daqconf/set_rc_controller_port.py create mode 100755 scripts/daqconf_set_rc_controller_port diff --git a/python/daqconf/set_rc_controller_port.py b/python/daqconf/set_rc_controller_port.py new file mode 100644 index 00000000..94b32a80 --- /dev/null +++ b/python/daqconf/set_rc_controller_port.py @@ -0,0 +1,86 @@ +import conffwk +import confmodel_dal +from daqconf.utils import find_free_port +import sys + +def set_rc_controller_port(oksfile, session_name, rc_port=0): + """ + Script to set the value of the RC Controller Service port used by the specified Session + in the specified OKS database file. If the new port is not specified, + it is set to a random available k8s NodePort. + """ + try: + db = conffwk.Configuration("oksconflibs:" + oksfile) + except Exception as e: + print(f"Error: Could not open OKS file {oksfile}. Make sure OKS_CONFLIBS_PATH is set.") + print(f"Details: {e}") + return 0 + + if not session_name: + print("Error: The session name needs to be specified") + return 0 + else: + try: + session = db.get_dal("Session", session_name) + except Exception: + print(f"Error: Could not find Session '{session_name}' in file '{oksfile}'") + return 0 + + # Find a new port if one isn't specified + k8s_min_port, k8s_max_port = 30000, 32767 + if rc_port == 0: + new_port = find_free_port(k8s_min_port, k8s_max_port) + print(f"Found free Kubernetes NodePort: {new_port}") + else: + new_port = rc_port + if not (k8s_min_port <= new_port <= k8s_max_port): + print(f"Warning: Port {new_port} is outside the standard k8s NodePort range ({k8s_min_port}-{k8s_max_port}).") + + # Traverse from Session -> Segment -> Controller -> Service + service_to_update = None + try: + if not hasattr(session, 'segment') or session.segment is None: + print(f"Error: Session '{session_name}' has no 'segment' defined.") + return 0 + + segment = session.segment + if not hasattr(segment, 'controller') or segment.controller is None: + print(f"Error: Segment '{segment.id}' has no 'controller' defined.") + return 0 + + controller = segment.controller + if not hasattr(controller, 'exposes_service') or not controller.exposes_service: + # Check if the attribute exists AND if the list is not empty + print(f"Error: Controller '{controller.id}' has no 'exposes_service' defined or the list is empty.") + return 0 + + service_list = controller.exposes_service + + if len(service_list) > 1: + print(f"Warning: Controller '{controller.id}' exposes multiple services. Only updating the first one ('{service_list[0].id}').") + + service_to_update = service_list[0] + + if service_to_update is None: + print(f"Error: Controller '{controller.id}' has a null service in its 'exposes_service' list.") + return 0 + + except Exception as e: + print(f"Error: Failed to navigate object graph from Session '{session_name}'.") + print(f"Details: {e}") + return 0 + + # Update the Service + if service_to_update: + service_to_update.port = new_port + db.update_dal(service_to_update) + print(f"Updated RC Controller Service '{service_to_update.id}' to use port {new_port}") + + db.commit() + print(f"Successfully configured RC controller port for session '{session_name}'.") + return new_port + else: + # This case is mostly covered by the checks above, but serves as a fallback. + print(f"Error: Could not find the RC Controller Service for session '{session_name}'.") + return 0 + diff --git a/scripts/daqconf_set_rc_controller_port b/scripts/daqconf_set_rc_controller_port new file mode 100755 index 00000000..4d803407 --- /dev/null +++ b/scripts/daqconf_set_rc_controller_port @@ -0,0 +1,30 @@ +#!/bin/env python3 +import click +import sys + +# Assuming the new script is saved as daqconf/set_rc_controller_port.py +from daqconf.set_rc_controller_port import set_rc_controller_port + +@click.command() +@click.argument('oks_session_name', type=str) +@click.argument('oksfile', type=str) +@click.argument('rc_port', type=int, required=False, default=0) +def daqconf_set_rc_controller_port(oks_session_name, oksfile, rc_port): + """Script to set the value of the RC Controller Service port used by the specified Session + in the specified OKS database file. If the new port is not specified, it is set to a + random available k8s NodePort.""" + + # The set_rc_controller_port function (oksfile, session_name, rc_port) + # prints its own status messages and returns the new port, or 0 on failure. + new_port = set_rc_controller_port(oksfile, oks_session_name, rc_port) + + if new_port == 0: + click.echo(f"Error: Failed to set RC controller port for session '{oks_session_name}'.", err=True) + sys.exit(1) + else: + # Print the final port to stdout for scripting (e.g., port=$(...)) + print(new_port) + sys.exit(0) + +if __name__ == '__main__': + daqconf_set_rc_controller_port()