Skip to content

Commit

Permalink
Merge branch 'develop' into PawelPlesniak/Ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
PawelPlesniak authored Nov 15, 2024
2 parents e9548e6 + 5c9e8b4 commit 3adf012
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 61 deletions.
38 changes: 37 additions & 1 deletion src/drunc/controller/children_interface/child_node.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import abc
from drunc.exceptions import DruncSetupException
from drunc.utils.utils import ControlType, get_control_type_and_uri_from_connectivity_service, get_control_type_and_uri_from_cli
from drunc.utils.grpc_utils import pack_to_any
from druncschema.token_pb2 import Token
from druncschema.request_response_pb2 import Response, ResponseFlag, Description
import os

class ChildInterfaceTechnologyUnknown(DruncSetupException):
def __init__(self, t, name):
super().__init__(f'The type {t} is not supported for the ChildNode {name}')


class ChildNode(abc.ABC):
def __init__(self, name:str, node_type:ControlType, **kwargs) -> None:
def __init__(self, name:str, configuration, node_type:ControlType, **kwargs) -> None:
super().__init__(**kwargs)

self.node_type = node_type
import logging
self.log = logging.getLogger(f"{name}-child-node")
self.name = name
self.configuration = configuration

@abc.abstractmethod
def __str__(self):
Expand All @@ -39,6 +44,37 @@ def get_status(self, token):
def get_endpoint(self):
pass

def describe(self, token:Token) -> Response:
descriptionType = None
descriptionName = None

if hasattr(self.configuration.data, "application_name"): # Get the application name and type
descriptionType = self.configuration.data.application_name
descriptionName = self.configuration.data.id
elif hasattr(self.configuration.data, "controller") and hasattr(self.configuration.data.controller, "application_name"): # Get the controller name and type
descriptionType = self.configuration.data.controller.application_name
descriptionName = self.configuration.data.controller.id

from drunc.controller.utils import get_detector_name
d = Description(
type = descriptionType,
name = descriptionName,
endpoint = self.get_endpoint(),
info = get_detector_name(self.configuration),
session = os.getenv("DUNEDAQ_SESSION"),
commands = None,
broadcast = None,
)

resp = Response(
name = self.name,
token = token,
data = pack_to_any(d),
flag = ResponseFlag.EXECUTED_SUCCESSFULLY,
children = None
)
return resp


@staticmethod
def get_child(name:str, cli, configuration, init_token=None, connectivity_service=None, **kwargs):
Expand Down
6 changes: 3 additions & 3 deletions src/drunc/controller/children_interface/grpc_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ class gRPCChildNode(ChildNode):
def __init__(self, name, configuration:gRCPChildConfHandler, init_token, uri):
super().__init__(
name = name,
node_type = ControlType.gRPC
node_type = ControlType.gRPC,
configuration = configuration
)

from logging import getLogger
self.log = getLogger(f'{self.name}-grpc-child')
self.configuration = configuration


host, port = uri.split(":")
port = int(port)
Expand Down Expand Up @@ -110,7 +111,6 @@ def terminate(self):
pass

def propagate_command(self, command, data, token) -> Response:

return send_command(
controller = self.controller,
token = token,
Expand Down
28 changes: 16 additions & 12 deletions src/drunc/controller/children_interface/rest_api_child.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from drunc.controller.children_interface.child_node import ChildNode
from drunc.exceptions import DruncSetupException
from drunc.utils.utils import ControlType
from druncschema.request_response_pb2 import Response
from drunc.utils.grpc_utils import pack_to_any
from druncschema.generic_pb2 import PlainText, Stacktrace
from druncschema.request_response_pb2 import Response, ResponseFlag, Description
from druncschema.controller_pb2 import FSMCommandResponse, FSMResponseFlag
from druncschema.token_pb2 import Token
import threading
from typing import NoReturn
import os

class ResponseDispatcher(threading.Thread):

Expand Down Expand Up @@ -395,14 +399,17 @@ class RESTAPIChildNode(ChildNode):
def __init__(self, name, configuration:RESTAPIChildNodeConfHandler, fsm_configuration:FSMConfHandler, uri):
super(RESTAPIChildNode, self).__init__(
name = name,
node_type = ControlType.REST_API
node_type = ControlType.REST_API,
configuration = configuration
)

from logging import getLogger
self.log = getLogger(f'{name}-rest-api-child')

self.response_listener = ResponseListener.get()

self.fsm_configuration = fsm_configuration

import socket
response_listener_host = socket.gethostname()

Expand All @@ -413,7 +420,7 @@ def __init__(self, name, configuration:RESTAPIChildNodeConfHandler, fsm_configur
from drunc.exceptions import DruncSetupException
raise DruncSetupException(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(configuration.data, "proxy", [None, None])
proxy_host, proxy_port = getattr(self.configuration.data, "proxy", [None, None])
proxy_port = int(proxy_port) if proxy_port is not None else None

self.commander = AppCommander(
Expand Down Expand Up @@ -465,10 +472,6 @@ def get_status(self, token):
)

def propagate_command(self, command:str, data, token:Token) -> Response:
from druncschema.request_response_pb2 import ResponseFlag
from druncschema.generic_pb2 import PlainText, Stacktrace
from drunc.utils.grpc_utils import pack_to_any

if command == 'exclude':
self.state.exclude()
return Response(
Expand Down Expand Up @@ -496,8 +499,6 @@ def propagate_command(self, command:str, data, token:Token) -> Response:
children = []
)

from druncschema.controller_pb2 import FSMCommandResponse, FSMResponseFlag

if self.state.excluded():
return Response(
name = self.name,
Expand All @@ -514,7 +515,11 @@ def propagate_command(self, command:str, data, token:Token) -> Response:
)

# here lies the mother of all the problems
if command != 'execute_fsm_command':
if command == 'execute_fsm_command':
return self.propagate_fsm_command(command, data, token)
elif command == 'describe':
return self.describe(token)
else:
self.log.info(f'Ignoring command \'{command}\' sent to \'{self.name}\'')
return Response(
name = self.name,
Expand All @@ -524,6 +529,7 @@ def propagate_command(self, command:str, data, token:Token) -> Response:
children = []
)

def propagate_fsm_command(self, command:str, data, token:Token) -> Response:
from drunc.exceptions import DruncException
entry_state = self.state.get_operational_state()
transition = self.fsm.get_transition(data.command_name)
Expand All @@ -532,7 +538,6 @@ def propagate_command(self, command:str, data, token:Token) -> Response:
import json
self.log.info(f'Sending \'{data.command_name}\' to \'{self.name}\'')


try:
self.commander.send_command(
cmd_id = data.command_name,
Expand All @@ -558,7 +563,6 @@ def propagate_command(self, command:str, data, token:Token) -> Response:
command_name = data.command_name,
data = response_data
)
from drunc.utils.grpc_utils import pack_to_any
response = Response(
name = self.name,
token = token,
Expand Down
42 changes: 21 additions & 21 deletions src/drunc/controller/controller.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
from druncschema.request_response_pb2 import Request, Response, ResponseFlag
from druncschema.token_pb2 import Token
from druncschema.generic_pb2 import PlainText, PlainTextVector
from druncschema.authoriser_pb2 import ActionType, SystemType
from druncschema.broadcast_pb2 import BroadcastType
from druncschema.controller_pb2_grpc import ControllerServicer
from druncschema.controller_pb2 import Status
from druncschema.controller_pb2 import FSMCommand, FSMCommandResponse, FSMResponseFlag
from druncschema.controller_pb2 import Status, FSMCommand, FSMCommandResponse, FSMResponseFlag
from druncschema.generic_pb2 import PlainText, PlainTextVector
from druncschema.request_response_pb2 import Request, Response, ResponseFlag
from druncschema.token_pb2 import Token

from drunc.controller.children_interface.child_node import ChildNode
from drunc.controller.stateful_node import StatefulNode
from drunc.authoriser.decorators import authentified_and_authorised
from drunc.broadcast.server.broadcast_sender import BroadcastSender
import drunc.controller.exceptions as ctler_excpt
from drunc.utils.grpc_utils import pack_to_any
from typing import Optional, List
from drunc.broadcast.server.decorators import broadcasted
from drunc.utils.grpc_utils import unpack_request_data_to, pack_response
from drunc.authoriser.decorators import authentified_and_authorised
from druncschema.authoriser_pb2 import ActionType, SystemType
from drunc.controller.children_interface.child_node import ChildNode
from drunc.controller.decorators import in_control
import drunc.controller.exceptions as ctler_excpt
from drunc.controller.stateful_node import StatefulNode
from drunc.exceptions import DruncException
from drunc.utils.grpc_utils import pack_to_any
from drunc.utils.grpc_utils import unpack_request_data_to, pack_response

import signal
from typing import Optional, List

class ControllerActor:
def __init__(self, token:Optional[Token]=None):
Expand Down Expand Up @@ -168,10 +167,10 @@ def __init__(self, configuration, name:str, session:str, token:Token):
name = 'describe_fsm',
data_type = ['generic_pb2.PlainText', 'None'],
help = '''Return a description of the FSM transitions:
if a transition name is provided in its input, return that transition description;
if a state is provided, return the transitions accessible from that state;
if "all-transitions" is provided, return all the transitions;
if nothing (None) is provided, return the transitions accessible from the current state.''',
if a transition name is provided in its input, return that transition description;
if a state is provided, return the transitions accessible from that state;
if "all-transitions" is provided, return all the transitions;
if nothing (None) is provided, return the transitions accessible from the current state.''',
return_type = 'request_response_pb2.Description'
),

Expand Down Expand Up @@ -457,21 +456,22 @@ def status(self, token:Token) -> Response:
def describe(self, token:Token) -> Response:
from druncschema.request_response_pb2 import Description
from drunc.utils.grpc_utils import pack_to_any
from drunc.controller.utils import get_detector_name
bd = self.describe_broadcast()
d = Description(
# endpoint = self.uri,
type = 'controller',
name = self.name,
endpoint = self.uri,
info = get_detector_name(self.configuration),
session = self.session,
commands = self.commands,
# children_endpoints = [child.get_endpoint() for child in self.children_nodes],
)

if bd:
d.broadcast.CopyFrom(pack_to_any(bd))


response_children = self.propagate_to_list(
children_description = self.propagate_to_list(
'describe',
command_data = None,
token = token,
Expand All @@ -483,7 +483,7 @@ def describe(self, token:Token) -> Response:
token = None,
data = pack_to_any(d),
flag = ResponseFlag.EXECUTED_SUCCESSFULLY,
children = response_children,
children = children_description,
)

# ORDER MATTERS!
Expand Down
20 changes: 10 additions & 10 deletions src/drunc/controller/controller_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from druncschema.controller_pb2 import Status

from drunc.utils.grpc_utils import unpack_any
from drunc.utils.shell_utils import GRPCDriver
from drunc.utils.shell_utils import GRPCDriver, DecodedResponse


class ControllerDriver(GRPCDriver):
Expand All @@ -19,35 +19,35 @@ def create_stub(self, channel):
from druncschema.controller_pb2_grpc import ControllerStub
return ControllerStub(channel)

def describe(self) -> Description:
def describe(self) -> DecodedResponse:
return self.send_command('describe', outformat = Description)

def describe_fsm(self, key:str=None) -> Description: # key can be: a state name, a transition name, none to get the currently accessible transitions, or all-transition for all the transitions
def describe_fsm(self, key:str=None) -> DecodedResponse: # key can be: a state name, a transition name, none to get the currently accessible transitions, or all-transition for all the transitions
from druncschema.controller_pb2 import FSMCommandsDescription
input = PlainText(text = key)
return self.send_command('describe_fsm', data = input, outformat = FSMCommandsDescription)

def status(self) -> Description:
def status(self) -> DecodedResponse:
return self.send_command('status', outformat = Status)

def take_control(self) -> Description:
def take_control(self) -> DecodedResponse:
return self.send_command('take_control', outformat = PlainText)

def who_is_in_charge(self, rethrow=None) -> Description:
def who_is_in_charge(self, rethrow=None) -> DecodedResponse:
return self.send_command('who_is_in_charge', outformat = PlainText)

def surrender_control(self) -> Description:
def surrender_control(self) -> DecodedResponse:
return self.send_command('surrender_control')

def execute_fsm_command(self, arguments) -> Description:
def execute_fsm_command(self, arguments) -> DecodedResponse:
from druncschema.controller_pb2 import FSMCommandResponse
return self.send_command('execute_fsm_command', data = arguments, outformat = FSMCommandResponse)

def include(self, arguments) -> Description:
def include(self, arguments) -> DecodedResponse:
from druncschema.controller_pb2 import FSMCommandResponse
return self.send_command('include', data = arguments, outformat = PlainText)

def exclude(self, arguments) -> Description:
def exclude(self, arguments) -> DecodedResponse:
from druncschema.controller_pb2 import FSMCommandResponse
return self.send_command('exclude', data = arguments, outformat = PlainText)

Expand Down
6 changes: 4 additions & 2 deletions src/drunc/controller/interface/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ def wait(obj:ControllerContext, sleep_time:int) -> None:
@click.command('status')
@click.pass_obj
def status(obj:ControllerContext) -> None:
# Get the dynamic system information
statuses = obj.get_driver('controller').status()

# Get the static system information
descriptions = obj.get_driver('controller').describe()
from drunc.controller.interface.shell_utils import print_status_table
print_status_table(obj,statuses)
print_status_table(obj, statuses, descriptions)

@click.command('connect')
@click.argument('controller_address', type=str)
Expand Down
Loading

0 comments on commit 3adf012

Please sign in to comment.