-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Log Authenticated User from UI-Server in Workflow Log #4522
Changes from all commits
fffb911
304de78
70115dc
6bf4444
91d86d6
1568cd0
a59bcf8
cb41941
baab059
fbe1768
75d6799
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -159,7 +159,13 @@ def _socket_options(self): | |
self.poller = zmq.Poller() | ||
self.poller.register(self.socket, zmq.POLLIN) | ||
|
||
async def async_request(self, command, args=None, timeout=None): | ||
async def async_request( | ||
self, | ||
command, | ||
args=None, | ||
timeout=None, | ||
req_meta=None | ||
): | ||
"""Send an asynchronous request using asyncio. | ||
|
||
Has the same arguments and return values as ``serial_request``. | ||
|
@@ -177,6 +183,9 @@ async def async_request(self, command, args=None, timeout=None): | |
# send message | ||
msg = {'command': command, 'args': args} | ||
msg.update(self.header) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Here: msg.update(self.header)
msg['meta']['auth_user'] = auth_user |
||
# add the request metadata | ||
if req_meta: | ||
msg['meta'].update(req_meta) | ||
LOG.debug('zmq:send %s', msg) | ||
message = encode_(msg) | ||
self.socket.send_string(message) | ||
|
@@ -205,7 +214,13 @@ async def async_request(self, command, args=None, timeout=None): | |
error = response['error'] | ||
raise ClientError(error['message'], error.get('traceback')) | ||
|
||
def serial_request(self, command, args=None, timeout=None): | ||
def serial_request( | ||
self, | ||
command, | ||
args=None, | ||
timeout=None, | ||
req_meta=None | ||
): | ||
"""Send a request. | ||
|
||
For convenience use ``__call__`` to call this method. | ||
|
@@ -225,7 +240,7 @@ def serial_request(self, command, args=None, timeout=None): | |
|
||
""" | ||
task = self.loop.create_task( | ||
self.async_request(command, args, timeout)) | ||
self.async_request(command, args, timeout, req_meta)) | ||
self.loop.run_until_complete(task) | ||
oliver-sanders marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return task.result() | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
from uuid import uuid4 | ||
|
||
from graphene.utils.str_converters import to_snake_case | ||
from cylc.flow import LOG | ||
|
||
from cylc.flow.data_store_mgr import ( | ||
EDGES, FAMILY_PROXIES, TASK_PROXIES, WORKFLOW, | ||
|
@@ -592,60 +593,21 @@ def __init__(self, data: 'DataStoreMgr', schd: 'Scheduler') -> None: | |
# Mutations | ||
async def mutator(self, *m_args): | ||
"""Mutate workflow.""" | ||
_, command, w_args, args = m_args | ||
_, command, w_args, args, meta = m_args | ||
w_ids = [flow[WORKFLOW].id | ||
for flow in await self.get_workflows_data(w_args)] | ||
if not w_ids: | ||
workflows = list(self.data_store_mgr.data.keys()) | ||
return [{ | ||
'response': (False, f'No matching workflow in {workflows}')}] | ||
w_id = w_ids[0] | ||
result = await self._mutation_mapper(command, args) | ||
if result is None: | ||
result = (True, 'Command queued') | ||
return [{'id': w_id, 'response': result}] | ||
|
||
async def nodes_mutator(self, *m_args): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was picked up when adding the unpacking of the meta and was discussed with @oliver-sanders, who looked at codecov for verification. It is seemingly dead code and was asked to remove it. Pinged @dwsutherland on the sibling to verify it is indeed unused code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was in use, until: And the idea behind it was that mutations being multi-workflow could be given node ids from different workflows, and then these ids would be parsed and mutations sent to the appropriate workflow.. The fact that we moved away from this, means we are happy with not using this functionality... i.e. a node mutation will always be associated with only one workflow and/or the workflow parsing happens somewhere else. |
||
"""Mutate node items of associated workflows.""" | ||
_, command, tokens_list, w_args, args = m_args | ||
w_ids = [ | ||
workflow[WORKFLOW].id | ||
for workflow in await self.get_workflows_data(w_args) | ||
] | ||
if not w_ids: | ||
workflows = list(self.data_store_mgr.data.keys()) | ||
return [{ | ||
'response': (False, f'No matching workflow in {workflows}')}] | ||
w_id = w_ids[0] | ||
# match proxy ID args with workflows | ||
items = [] | ||
for tokens in tokens_list: | ||
owner = tokens.get('user') | ||
workflow = tokens.get('workflow') | ||
if workflow and owner is None: | ||
owner = "*" | ||
if ( | ||
not (owner and workflow) | ||
or fnmatchcase( | ||
w_id, | ||
tokens.workflow_id, | ||
) | ||
): | ||
items.append( | ||
tokens.relative_id | ||
) | ||
if items: | ||
if command == 'put_messages': | ||
args['task_job'] = items[0] | ||
else: | ||
args['tasks'] = items | ||
result = await self._mutation_mapper(command, args) | ||
result = await self._mutation_mapper(command, args, meta) | ||
if result is None: | ||
result = (True, 'Command queued') | ||
return [{'id': w_id, 'response': result}] | ||
|
||
async def _mutation_mapper( | ||
self, command: str, kwargs: Dict[str, Any] | ||
self, command: str, kwargs: Dict[str, Any], meta: Dict[str, Any] | ||
) -> Optional[Tuple[bool, str]]: | ||
"""Map between GraphQL resolvers and internal command interface.""" | ||
method = getattr(self, command, None) | ||
oliver-sanders marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
@@ -655,7 +617,16 @@ async def _mutation_mapper( | |
self.schd.get_command_method(command) | ||
except AttributeError: | ||
raise ValueError(f"Command '{command}' not found") | ||
self.schd.command_queue.put((command, tuple(kwargs.values()), {})) | ||
if command != "put_messages": | ||
log_msg = f"[command] {command}" | ||
user = meta.get('auth_user', self.schd.owner) | ||
if user != self.schd.owner: | ||
log_msg += (f" (issued by {user})") | ||
LOG.info(log_msg) | ||
self.schd.queue_command( | ||
command, | ||
kwargs | ||
) | ||
return None | ||
|
||
def broadcast( | ||
|
@@ -678,7 +649,11 @@ def broadcast( | |
cutoff) | ||
raise ValueError('Unsupported broadcast mode') | ||
|
||
def put_ext_trigger(self, message, id): # noqa: A002 (graphql interface) | ||
def put_ext_trigger( | ||
self, | ||
message, | ||
id # noqa: A002 (graphql interface) | ||
): | ||
"""Server-side external event trigger interface. | ||
|
||
Args: | ||
|
@@ -697,7 +672,12 @@ def put_ext_trigger(self, message, id): # noqa: A002 (graphql interface) | |
self.schd.ext_trigger_queue.put((message, id)) | ||
return (True, 'Event queued') | ||
|
||
def put_messages(self, task_job=None, event_time=None, messages=None): | ||
def put_messages( | ||
self, | ||
task_job=None, | ||
event_time=None, | ||
messages=None | ||
): | ||
"""Put task messages in queue for processing later by the main loop. | ||
|
||
Arguments: | ||
|
@@ -768,7 +748,7 @@ def force_spawn_children( | |
{ | ||
"outputs": outputs, | ||
"flow_num": flow_num | ||
} | ||
}, | ||
) | ||
) | ||
return (True, 'Command queued') | ||
|
@@ -779,7 +759,7 @@ def stop( | |
cycle_point: Optional[str] = None, | ||
clock_time: Optional[str] = None, | ||
task: Optional[str] = None, | ||
flow_num: Optional[int] = None | ||
flow_num: Optional[int] = None, | ||
) -> Tuple[bool, str]: | ||
"""Stop the workflow or specific flow from spawning any further. | ||
|
||
|
@@ -805,11 +785,17 @@ def stop( | |
'clock_time': clock_time, | ||
'task': task, | ||
'flow_num': flow_num, | ||
}) | ||
)) | ||
}), | ||
) | ||
) | ||
return (True, 'Command queued') | ||
|
||
def force_trigger_tasks(self, tasks=None, reflow=False, flow_descr=None): | ||
def force_trigger_tasks( | ||
self, | ||
tasks=None, | ||
reflow=False, | ||
flow_descr=None, | ||
): | ||
"""Trigger submission of task jobs where possible. | ||
|
||
Args: | ||
|
@@ -831,11 +817,12 @@ def force_trigger_tasks(self, tasks=None, reflow=False, flow_descr=None): | |
""" | ||
self.schd.command_queue.put( | ||
( | ||
"force_trigger_tasks", (tasks or [],), | ||
"force_trigger_tasks", | ||
(tasks or [],), | ||
{ | ||
"reflow": reflow, | ||
"flow_descr": flow_descr | ||
} | ||
) | ||
), | ||
) | ||
return (True, 'Command queued') |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,16 +21,13 @@ | |
export REQUIRE_PLATFORM='loc:remote comms:ssh' | ||
. "$(dirname "$0")/test_header" | ||
#------------------------------------------------------------------------------- | ||
set_test_number 3 | ||
set_test_number 2 | ||
install_workflow "${TEST_NAME_BASE}" "${TEST_NAME_BASE}" | ||
|
||
run_ok "${TEST_NAME_BASE}-validate" \ | ||
cylc validate "${WORKFLOW_NAME}" | ||
workflow_run_ok "${TEST_NAME_BASE}-run" \ | ||
cylc play --debug --no-detach --reference-test "${WORKFLOW_NAME}" | ||
|
||
grep_ok "\[client-command\] graphql ssh" \ | ||
"$RUN_DIR/${WORKFLOW_NAME}/log/workflow/log" | ||
|
||
Comment on lines
-32
to
-34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was a safety test to ensure that the comms method is logged. Perhaps we could add a Cylc client command into the workflow e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, are you happy if I do this in the ssh async request PR as this test is broken anyway? |
||
purge | ||
exit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oliver-sanders, just thinking about removing this line. It does remove the
comms_method
which may be useful for debugging in future? Want me to put any logging information about the comms method to replace this, or are you happy with the info loss from the removal?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can pass the comms_method down with the metadata and log it with the command.