Skip to content

Commit 37adf28

Browse files
services: validate-reinstall
* Closes #526 * Add basic support for the `cylc vr` command.
1 parent 57405fc commit 37adf28

File tree

2 files changed

+105
-12
lines changed

2 files changed

+105
-12
lines changed

cylc/uiserver/resolvers.py

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ class Services:
216216
# log file stream lag
217217
CAT_LOG_SLEEP = 1
218218

219+
# command timeout for commands which start schedulers
220+
START_TIMEOUT = 120
221+
219222
@staticmethod
220223
def _error(message: Union[Exception, str]):
221224
"""Format error case response."""
@@ -235,9 +238,9 @@ def _return(message: str):
235238
@classmethod
236239
async def clean(
237240
cls,
241+
workflows_mgr: 'WorkflowsManager',
238242
workflows: Iterable['Tokens'],
239243
args: dict,
240-
workflows_mgr: 'WorkflowsManager',
241244
executor: 'Executor',
242245
log: 'Logger'
243246
):
@@ -278,20 +281,21 @@ async def scan(
278281
return cls._return("Scan requested")
279282

280283
@classmethod
281-
async def play(
284+
async def run_command(
282285
cls,
286+
command: tuple[str],
283287
workflows: Iterable[Tokens],
284288
args: Dict[str, Any],
285-
workflows_mgr: 'WorkflowsManager',
286289
log: 'Logger',
287-
) -> List[Union[bool, str]]:
288-
"""Calls `cylc play`."""
290+
timeout: int,
291+
) -> List[bool | str]:
292+
"""Calls the specified Cylc command."""
289293
cylc_version = args.pop('cylc_version', None)
290294
results: Dict[str, str] = {}
291295
failed = False
292296
for tokens in workflows:
293297
try:
294-
cmd = _build_cmd(['cylc', 'play', '--color=never'], args)
298+
cmd = _build_cmd(['cylc', *command, '--color=never'], args)
295299

296300
if tokens['user'] and tokens['user'] != getuser():
297301
return cls._error(
@@ -322,7 +326,7 @@ async def play(
322326
stderr=PIPE,
323327
text=True
324328
)
325-
ret_code = proc.wait(timeout=120)
329+
ret_code = proc.wait(timeout=timeout)
326330

327331
if ret_code:
328332
msg = f"Command failed ({ret_code}): {cmd_repr}"
@@ -335,7 +339,7 @@ async def play(
335339
)
336340
failed = True
337341
else:
338-
results[wflow] = 'started'
342+
results[wflow] = 'Command succeeded'
339343

340344
except Exception as exc: # unexpected error
341345
log.exception(exc)
@@ -351,10 +355,53 @@ async def play(
351355
)
352356
)
353357

358+
return []
359+
360+
@classmethod
361+
async def play(
362+
cls, workflows_mgr: 'WorkflowsManager', *args, **kwargs
363+
) -> List[Union[bool, str]]:
364+
"""Calls `cylc play`."""
365+
# run `cylc play`
366+
ret = await cls.run_command(
367+
('play',),
368+
*args,
369+
**kwargs,
370+
timeout=cls.START_TIMEOUT,
371+
)
372+
354373
# trigger a re-scan
355374
await workflows_mgr.scan()
356-
# send a success message
357-
return cls._return('Workflow(s) started')
375+
376+
# return results
377+
if ret:
378+
return ret
379+
else:
380+
# send a success message
381+
return cls._return('Workflow(s) started')
382+
383+
@classmethod
384+
async def validate_reinstall(
385+
cls, workflows_mgr: 'WorkflowsManager', *args, **kwargs
386+
) -> List[Union[bool, str]]:
387+
"""Calls `cylc validate-reinstall`."""
388+
# run `cylc play`
389+
ret = await cls.run_command(
390+
('validate-reinstall', '--yes'),
391+
*args,
392+
**kwargs,
393+
timeout=cls.START_TIMEOUT,
394+
)
395+
396+
# trigger a re-scan
397+
await workflows_mgr.scan()
398+
399+
# return results
400+
if ret:
401+
return ret
402+
else:
403+
# send a success message
404+
return cls._return('Workflow(s) reinstalled')
358405

359406
@staticmethod
360407
async def enqueue(stream, queue):
@@ -592,19 +639,26 @@ async def service(
592639

593640
if command == 'clean': # noqa: SIM116
594641
return await Services.clean(
642+
self.workflows_mgr,
595643
workflows,
596644
kwargs,
597-
self.workflows_mgr,
598645
log=self.log,
599646
executor=self.executor
600647
)
601648
elif command == 'play':
602649
return await Services.play(
650+
self.workflows_mgr,
603651
workflows,
604652
kwargs,
605-
self.workflows_mgr,
606653
log=self.log
607654
)
655+
elif command == 'validate_reinstall':
656+
return await Services.validate_reinstall(
657+
self.workflows_mgr,
658+
workflows,
659+
kwargs,
660+
log=self.log,
661+
)
608662
elif command == 'scan':
609663
return await Services.scan(
610664
kwargs,

cylc/uiserver/schema.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,44 @@ class Arguments:
241241
result = GenericScalar()
242242

243243

244+
class ValidateReinstall(graphene.Mutation):
245+
class Meta:
246+
description = sstrip('''
247+
Validate, reinstall, then reload or restart as appropriate.
248+
249+
This command updates a workflow to reflect any new changes made in
250+
the workflow source directory since it was installed.
251+
252+
The workflow will be reinstalled, then either:
253+
* Reloaded (if the workflow is running),
254+
* or restarted (if it is stopped).
255+
''')
256+
# Note we have the "resume" mutation for paused workflows.
257+
resolver = partial(mutator, command='validate_reinstall')
258+
259+
class Arguments:
260+
workflows = graphene.List(WorkflowID, required=True)
261+
cylc_version = CylcVersion(
262+
description=sstrip('''
263+
Set the Cylc version that the workflow starts with.
264+
''')
265+
)
266+
set = graphene.List( # noqa: A003 (graphql field name)
267+
graphene.String,
268+
description=sstrip('''
269+
Set the value of a Jinja2 template variable in the workflow
270+
definition. Values should be valid Python literals so strings
271+
must be quoted e.g. `STR="string"`, `INT=43`, `BOOL=True`.
272+
This option can be used multiple times on the command line.
273+
NOTE: these settings persist across workflow restarts, but can
274+
be set again on the `cylc play` command line if they need to be
275+
overridden.
276+
''')
277+
)
278+
279+
result = GenericScalar()
280+
281+
244282
class Clean(graphene.Mutation):
245283
class Meta:
246284
description = sstrip('''
@@ -894,6 +932,7 @@ class Logs(graphene.ObjectType):
894932

895933
class UISMutations(Mutations):
896934
play = _mut_field(Play)
935+
validate_reinstall = _mut_field(ValidateReinstall)
897936
clean = _mut_field(Clean)
898937
scan = _mut_field(Scan)
899938

0 commit comments

Comments
 (0)