Skip to content

Commit

Permalink
Merge pull request #298 from DUNE-DAQ/revert-296-revert-239-plasorak/…
Browse files Browse the repository at this point in the history
…recursive-statuses

Revert "Revert "Recursive statuses""
  • Loading branch information
plasorak authored Nov 8, 2024
2 parents 4b870e8 + c77ddb8 commit 6afa5fd
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 168 deletions.
18 changes: 5 additions & 13 deletions src/drunc/controller/children_interface/grpc_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,13 @@ def start_listening(self, bdesc):
)

def get_status(self, token) -> Response:
from druncschema.controller_pb2 import Status
from drunc.utils.grpc_utils import unpack_any

status = unpack_any(
send_command(
controller = self.controller,
token = token,
command = 'get_status',
data = None
).data,
Status
return send_command(
controller = self.controller,
token = token,
command = 'status',
data = None
)

return status

def terminate(self):
if self.channel:
self.channel.close()
Expand Down
12 changes: 10 additions & 2 deletions src/drunc/controller/children_interface/rest_api_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,22 @@ def get_endpoint(self):

def get_status(self, token):
from druncschema.controller_pb2 import Status
from druncschema.request_response_pb2 import Response, ResponseFlag
from drunc.utils.grpc_utils import pack_to_any

return Status(
name = self.name,
status = Status(
state = self.state.get_operational_state(),
sub_state = 'idle' if not self.state.get_executing_command() else 'executing_cmd',
in_error = self.state.in_error() or not self.commander.ping(), # meh
included = self.state.included(),
)
return Response(
name = self.name,
token = None,
data = pack_to_any(status),
flag = ResponseFlag.EXECUTED_SUCCESSFULLY,
children = [],
)

def propagate_command(self, command:str, data, token:Token) -> Response:
from druncschema.request_response_pb2 import ResponseFlag
Expand Down
84 changes: 6 additions & 78 deletions src/drunc/controller/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from druncschema.generic_pb2 import PlainText, PlainTextVector
from druncschema.broadcast_pb2 import BroadcastType
from druncschema.controller_pb2_grpc import ControllerServicer
from druncschema.controller_pb2 import Status, ChildrenStatus
from druncschema.controller_pb2 import Status
from druncschema.controller_pb2 import FSMCommand, FSMCommandResponse, FSMResponseFlag

from drunc.controller.children_interface.child_node import ChildNode
Expand Down Expand Up @@ -158,26 +158,12 @@ def __init__(self, configuration, name:str, session:str, token:Token):
),

CommandDescription(
name = 'get_children_status',
data_type = ['generic_pb2.PlainText','None'],
help = 'Get the status of all the children. Only get the status from the child if provided in the request.',
return_type = 'controller_pb2.ChildrenStatus'
),

CommandDescription(
name = 'get_status',
name = 'status',
data_type = ['None'],
help = 'Get the status of self',
return_type = 'controller_pb2.Status'
),

CommandDescription(
name = 'ls',
data_type = ['None'],
help = 'List the children',
return_type = 'generic_pb2.PlainTextVector'
),

CommandDescription(
name = 'describe_fsm',
data_type = ['generic_pb2.PlainText', 'None'],
Expand Down Expand Up @@ -447,75 +433,17 @@ def propagate_to_child(child, command, command_data, token, response_lock, respo
action=ActionType.READ,
system=SystemType.CONTROLLER
) # 2nd step
@unpack_request_data_to(pass_token=True) # 3rd step
def get_children_status(self, token:Token) -> Response:
#from drunc.controller.utils import get_status_message
cs = []
for n in self.children_nodes:
try:
cs += [n.get_status(token)]
except Exception as e: # TEMPORARY hack
from druncschema.controller_pb2 import Status
cs += [
Status(
name = n.name,
state = 'unknown',
sub_state = 'unknown',
in_error = True,
)
]

response = ChildrenStatus(
children_status = cs
)
return Response(
name = self.name,
token = None,
data = pack_to_any(response),
flag = ResponseFlag.EXECUTED_SUCCESSFULLY,
children = [],
)

# ORDER MATTERS!
@broadcasted # outer most wrapper 1st step
@authentified_and_authorised(
action=ActionType.READ,
system=SystemType.CONTROLLER
) # 2nd step
@unpack_request_data_to(None) # 3rd step
def get_status(self) -> Response:
@unpack_request_data_to(None, pass_token=True) # 3rd step
def status(self, token:Token) -> Response:
from drunc.controller.utils import get_status_message
status = get_status_message(self.stateful_node)
status.name = self.name

return Response (
name = self.name,
token = None,
token = token,
data = pack_to_any(status),
flag = ResponseFlag.EXECUTED_SUCCESSFULLY,
children = [],
)


# ORDER MATTERS!
@broadcasted # outer most wrapper 1st step
@authentified_and_authorised(
action=ActionType.READ,
system=SystemType.CONTROLLER
) # 2nd step
@unpack_request_data_to(None) # 3rd step
def ls(self) -> PlainTextVector:
nodes = [node.name for node in self.children_nodes]
response = PlainTextVector(
text = nodes
)

return Response (
name = self.name,
token = None,
data = pack_to_any(response),
flag = ResponseFlag.EXECUTED_SUCCESSFULLY,
children = [],
children = [n.get_status(token) for n in self.children_nodes]
)


Expand Down
12 changes: 3 additions & 9 deletions src/drunc/controller/controller_driver.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from druncschema.request_response_pb2 import Request, Response, Description
from druncschema.generic_pb2 import PlainText, PlainTextVector
from druncschema.controller_pb2 import Status, ChildrenStatus
from druncschema.controller_pb2 import Status

from drunc.utils.grpc_utils import unpack_any
from drunc.utils.shell_utils import GRPCDriver
Expand All @@ -27,14 +27,8 @@ def describe_fsm(self, key:str=None) -> Description: # key can be: a state name,
input = PlainText(text = key)
return self.send_command('describe_fsm', data = input, outformat = FSMCommandsDescription)

def ls(self) -> Description:
return self.send_command('ls', outformat = PlainTextVector)

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

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

def take_control(self) -> Description:
return self.send_command('take_control', outformat = PlainText)
Expand Down
56 changes: 5 additions & 51 deletions src/drunc/controller/interface/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,6 @@ def list_transitions(obj:ControllerContext, all:bool) -> None:
obj.print('\nUse [yellow]help <command>[/] for more information on a command.\n')



@click.command('ls')
@click.pass_obj
def ls(obj:ControllerContext) -> None:
children = obj.get_driver('controller').ls().data
if not children: return
obj.print(children.text)



@click.command('wait')
@click.argument("sleep_time", type=int, default=1)
@click.pass_obj
Expand All @@ -44,51 +34,15 @@ def wait(obj:ControllerContext, sleep_time:int) -> None:
obj.print(f"Command [green]wait[/green] ran for {sleep_time} seconds.")




@click.command('status')
@click.pass_obj
def status(obj:ControllerContext) -> None:
from druncschema.controller_pb2 import Status, ChildrenStatus
status = obj.get_driver('controller').get_status().data

if not status: return
statuses = obj.get_driver('controller').status()

from drunc.controller.interface.shell_utils import format_bool, tree_prefix

from rich.table import Table
t = Table(title=f'{status.name} status')
t.add_column('Name')
t.add_column('State')
t.add_column('Substate')
t.add_column('In error', justify='center')
t.add_column('Included', justify='center')
t.add_row(
status.name,
status.state,
status.sub_state,
format_bool(status.in_error, false_is_good = True),
format_bool(status.included),
)

statuses = obj.get_driver('controller').get_children_status().data

if not statuses:
statuses = []

how_many = len(statuses.children_status)

for i, c_status in enumerate(statuses.children_status):
first_column = tree_prefix(i, how_many)+c_status.name

t.add_row(
first_column,
c_status.state,
c_status.sub_state,
format_bool(c_status.in_error, false_is_good=True),
format_bool(c_status.included)
)
obj.print(t)
obj.print_status_summary()
return
from drunc.controller.interface.shell_utils import print_status_table
print_status_table(obj,statuses)

@click.command('connect')
@click.argument('controller_address', type=str)
Expand Down
5 changes: 2 additions & 3 deletions src/drunc/controller/interface/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ def controller_shell(ctx, controller_address:str, log_level:str) -> None:
transitions = ctx.obj.get_driver('controller').describe_fsm(key="all-transitions").data

from drunc.controller.interface.commands import (
list_transitions, ls, status, connect, take_control, surrender_control, who_am_i, who_is_in_charge, fsm, include, exclude, wait
describe, status, connect, take_control, surrender_control, who_am_i, who_is_in_charge, fsm, include, exclude, wait
)

ctx.command.add_command(list_transitions, 'list-transitions')
ctx.command.add_command(ls, 'ls')
ctx.command.add_command(describe, 'describe')
ctx.command.add_command(status, 'status')
ctx.command.add_command(connect, 'connect')
ctx.command.add_command(take_control, 'take-control')
Expand Down
44 changes: 42 additions & 2 deletions src/drunc/controller/interface/shell_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,41 @@
import logging
log = logging.getLogger('controller_shell_utils')


def print_status_table(obj, statuses):
from druncschema.controller_pb2 import Status
if not statuses: return

if type(statuses.data) != Status:
from google.protobuf.any_pb2 import Any
data_type = statuses.data.TypeName() if type(statuses.data) == Any else type(statuses.data)
obj.print(f'Could not get the status of the controller, got a \'{data_type}\' instead')
return

from drunc.controller.interface.shell_utils import format_bool, tree_prefix
from rich.table import Table

t = Table(title=f'Status')
t.add_column('Name')
t.add_column('State')
t.add_column('Substate')
t.add_column('In error', justify='center')
t.add_column('Included', justify='center')

def add_status_to_table(status, table, prefix):
table.add_row(
prefix+status.name,
status.data.state,
status.data.sub_state,
format_bool(status.data.in_error, false_is_good = True),
format_bool(status.data.included),
)
for child in status.children:
add_status_to_table(child, table, prefix=prefix+' ')
add_status_to_table(statuses, t, prefix='')
obj.print(t)
obj.print_status_summary()

def controller_cleanup_wrapper(ctx):
def controller_cleanup():
# remove the shell from the controller broadcast list
Expand Down Expand Up @@ -93,8 +128,8 @@ def controller_setup(ctx, controller_address):

ctx.print('Connected to the controller')

children = ctx.get_driver('controller').ls().data
ctx.print(f'{desc.name}.{desc.session}\'s children :family:: {children.text}')
# children = ctx.get_driver('controller').ls().data
# ctx.print(f'{desc.name}.{desc.session}\'s children :family:: {children.text}')

ctx.info(f'Taking control of the controller as {ctx.get_token()}')
try:
Expand Down Expand Up @@ -313,6 +348,11 @@ def add_to_table(table, response, prefix=''):
add_to_table(t, result)
obj.print(t)

statuses = obj.get_driver('controller').status()

from drunc.controller.interface.shell_utils import print_status_table
print_status_table(obj, statuses)


from druncschema.controller_pb2 import FSMCommandDescription

Expand Down
4 changes: 1 addition & 3 deletions src/drunc/unified_shell/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,9 @@ def cleanup():


from drunc.controller.interface.commands import (
list_transitions, ls, status, connect, take_control, surrender_control, who_am_i, who_is_in_charge, fsm, include, exclude, wait
status, connect, take_control, surrender_control, who_am_i, who_is_in_charge, fsm, include, exclude, wait
)

ctx.command.add_command(list_transitions, 'list-transitions')
ctx.command.add_command(ls, 'ls')
ctx.command.add_command(status, 'status')
ctx.command.add_command(connect, 'connect')
ctx.command.add_command(take_control, 'take-control')
Expand Down
13 changes: 6 additions & 7 deletions src/drunc/utils/shell_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def get_driver(self, name:str=None) -> GRPCDriver:
raise DruncShellException(f'More than one driver in this context')
return list(self._drivers.values())[0]
except KeyError:
self._log.error(f'FSM Commands cannot be sent until the Session is booted')
self._log.error(f'Controller-specific commands cannot be sent until the session is booted')
raise SystemExit(1) # used to avoid having to catch multiple Attribute errors when this function gets called

def get_token(self) -> Token:
Expand Down Expand Up @@ -302,13 +302,12 @@ def critical(self, *args, **kwargs) -> None:


def print_status_summary(self) -> None:
status = self.get_driver('controller').get_status().data.state
available_actions = [command.name.replace("_", "-") for command in self.get_driver('controller').describe_fsm().data.commands]
if status.find('(') == -1:
self.print(f"Current FSM status is [green]{status}[/green]. Available transitions are [green]{'[/green], [green]'.join(available_actions)}[/green].")
else:
status = self.get_driver('controller').status().data
if status.in_error:
self.print(f"[red] FSM is in error ({status})[/red], not currently accepting new commands.")
return
else:
available_actions = [command.name for command in self.get_driver('controller').describe_fsm().data.commands]
self.print(f"Current FSM status is [green]{status.state}[/green]. Available transitions are [green]{'[/green], [green]'.join(available_actions)}[/green].")


def create_dummy_token_from_uname() -> Token:
Expand Down

0 comments on commit 6afa5fd

Please sign in to comment.