def test_add_offset(): """Test socket start.""" orig_point = '20200202T0000Z' plus_offset = '+PT02H02M' print(add_offset(orig_point, plus_offset)) assert str(add_offset(orig_point, plus_offset)) == '20200202T0202Z' minus_offset = '-P1MT22H59M' assert str(add_offset(orig_point, minus_offset)) == '20200101T0101Z' bad_offset = '+foo' with pytest.raises(ValueError, match=r'ERROR, bad offset format') as exc: bad_point = add_offset(orig_point, bad_offset)
def suite_state(suite, task, point, offset=None, status='succeeded', message=None, cylc_run_dir=None, debug=False): """Connect to a suite DB and query the requested task state. Reports satisfied only if the remote suite state has been achieved. Returns all suite state args to pass on to triggering tasks. """ cylc_run_dir = os.path.expandvars( os.path.expanduser(cylc_run_dir or glbl_cfg().get_host_item('run directory'))) if offset is not None: point = str(add_offset(point, offset)) try: checker = CylcSuiteDBChecker(cylc_run_dir, suite) except (OSError, sqlite3.Error): # Failed to connect to DB; target suite may not be started. return (False, None) fmt = checker.get_remote_point_format() if fmt: my_parser = TimePointParser() point = str(my_parser.parse(point, dump_format=fmt)) if message is not None: satisfied = checker.task_state_met(task, point, message=message) else: satisfied = checker.task_state_met(task, point, status=status) results = { 'suite': suite, 'task': task, 'point': point, 'offset': offset, 'status': status, 'message': message, 'cylc_run_dir': cylc_run_dir } return (satisfied, results)
def suite_state(suite, task, point, offset=None, status='succeeded', message=None, cylc_run_dir=None, debug=False): """Connect to a suite DB and query the requested task state. Reports satisfied only if the remote suite state has been achieved. Returns all suite state args to pass on to triggering tasks. """ cylc_run_dir = os.path.expandvars( os.path.expanduser( cylc_run_dir or glbl_cfg().get_host_item('run directory'))) if offset is not None: point = str(add_offset(point, offset)) try: checker = CylcSuiteDBChecker(cylc_run_dir, suite) except (OSError, sqlite3.Error): # Failed to connect to DB; target suite may not be started. return (False, None) fmt = checker.get_remote_point_format() if fmt: my_parser = TimePointParser() point = str(my_parser.parse(point, dump_format=fmt)) if message is not None: satisfied = checker.task_state_met(task, point, message=message) else: satisfied = checker.task_state_met(task, point, status=status) results = { 'suite': suite, 'task': task, 'point': point, 'offset': offset, 'status': status, 'message': message, 'cylc_run_dir': cylc_run_dir } return (satisfied, results)
def workflow_state(workflow, task, point, offset=None, status='succeeded', message=None, cylc_run_dir=None): """Connect to a workflow DB and query the requested task state. * Reports satisfied only if the remote workflow state has been achieved. * Returns all workflow state args to pass on to triggering tasks. Arguments: workflow (str): The workflow to interrogate. task (str): The name of the task to query. point (str): The cycle point. offset (str): The offset between the cycle this xtrigger is used in and the one it is querying for as an ISO8601 time duration. e.g. PT1H (one hour). status (str): The task status required for this xtrigger to be satisfied. message (str): The custom task output required for this xtrigger to be satisfied. .. note:: This cannot be specified in conjunction with ``status``. cylc_run_dir (str): The directory in which the workflow to interrogate. .. note:: This only needs to be supplied if the workflow is running in a different location to what is specified in the global configuration (usually ``~/cylc-run``). Returns: tuple: (satisfied, results) satisfied (bool): True if ``satisfied`` else ``False``. results (dict): Dictionary containing the args / kwargs which were provided to this xtrigger. """ if cylc_run_dir: cylc_run_dir = expand_path(cylc_run_dir) else: cylc_run_dir = get_workflow_run_dir('') if offset is not None: point = str(add_offset(point, offset)) try: checker = CylcWorkflowDBChecker(cylc_run_dir, workflow) except (OSError, sqlite3.Error): # Failed to connect to DB; target workflow may not be started. return (False, None) fmt = checker.get_remote_point_format() if fmt: my_parser = TimePointParser() point = str(my_parser.parse(point, dump_format=fmt)) if message is not None: satisfied = checker.task_state_met(task, point, message=message) else: satisfied = checker.task_state_met(task, point, status=status) results = { 'workflow': workflow, 'task': task, 'point': point, 'offset': offset, 'status': status, 'message': message, 'cylc_run_dir': cylc_run_dir } return satisfied, results
def main(parser, options, suite): if options.use_task_point and options.cycle: raise UserInputError( "cannot specify a cycle point and use environment variable") if options.use_task_point: if "CYLC_TASK_CYCLE_POINT" in os.environ: options.cycle = os.environ["CYLC_TASK_CYCLE_POINT"] else: raise UserInputError("CYLC_TASK_CYCLE_POINT is not defined") if options.offset and not options.cycle: raise UserInputError( "You must target a cycle point to use an offset") if options.template: print("WARNING: ignoring --template (no longer needed)", file=sys.stderr) # Attempt to apply specified offset to the targeted cycle if options.offset: options.cycle = str(add_offset(options.cycle, options.offset)) # Exit if both task state and message are to being polled if options.status and options.msg: raise UserInputError("cannot poll both status and custom output") if options.msg and not options.task and not options.cycle: raise UserInputError("need a taskname and cyclepoint") # Exit if an invalid status is requested if (options.status and options.status not in TASK_STATUSES_ORDERED and options.status not in CylcSuiteDBChecker.STATE_ALIASES): raise UserInputError("invalid status '" + options.status + "'") # this only runs locally run_dir = os.path.expandvars( os.path.expanduser( options.run_dir or get_platform()['run directory'] ) ) pollargs = {'suite': suite, 'run_dir': run_dir, 'task': options.task, 'cycle': options.cycle, 'status': options.status, 'message': options.msg, } spoller = SuitePoller("requested state", options.interval, options.max_polls, args=pollargs) connected, formatted_pt = spoller.connect() if not connected: raise CylcError("cannot connect to the suite DB") if options.status and options.task and options.cycle: # check a task status spoller.condition = options.status if not spoller.poll(): sys.exit(1) elif options.msg: # Check for a custom task output spoller.condition = "output: %s" % options.msg if not spoller.poll(): sys.exit(1) else: # just display query results spoller.checker.display_maps( spoller.checker.suite_state_query( task=options.task, cycle=formatted_pt, status=options.status))
def main(parser: COP, options: 'Values', workflow: str) -> None: workflow, _ = parse_reg(workflow) if options.use_task_point and options.cycle: raise UserInputError( "cannot specify a cycle point and use environment variable") if options.use_task_point: if "CYLC_TASK_CYCLE_POINT" not in os.environ: raise UserInputError("CYLC_TASK_CYCLE_POINT is not defined") options.cycle = os.environ["CYLC_TASK_CYCLE_POINT"] if options.offset and not options.cycle: raise UserInputError( "You must target a cycle point to use an offset") # Attempt to apply specified offset to the targeted cycle if options.offset: options.cycle = str(add_offset(options.cycle, options.offset)) # Exit if both task state and message are to being polled if options.status and options.msg: raise UserInputError("cannot poll both status and custom output") if options.msg and not options.task and not options.cycle: raise UserInputError("need a taskname and cyclepoint") # Exit if an invalid status is requested if (options.status and options.status not in TASK_STATUSES_ORDERED and options.status not in CylcWorkflowDBChecker.STATE_ALIASES): raise UserInputError(f"invalid status '{options.status}'") # this only runs locally if options.run_dir: run_dir = expand_path(options.run_dir) else: run_dir = get_cylc_run_dir() pollargs = { 'workflow': workflow, 'run_dir': run_dir, 'task': options.task, 'cycle': options.cycle, 'status': options.status, 'message': options.msg, } spoller = WorkflowPoller("requested state", options.interval, options.max_polls, args=pollargs) connected, formatted_pt = spoller.connect() if not connected: raise CylcError("cannot connect to the workflow DB") if options.status and options.task and options.cycle: # check a task status spoller.condition = options.status if not spoller.poll(): sys.exit(1) elif options.msg: # Check for a custom task output spoller.condition = "output: %s" % options.msg if not spoller.poll(): sys.exit(1) else: # just display query results spoller.checker.display_maps( spoller.checker.workflow_state_query( task=options.task, cycle=formatted_pt, status=options.status))