diff --git a/README.md b/README.md index 4d9d397..19b3da6 100644 --- a/README.md +++ b/README.md @@ -500,6 +500,45 @@ request: when: null ``` +#### Option `--continue`, `-C` + +This option is useful e.g. when a user wants to continue with a previously terminated `newa execute` session. It is assumed that a user will use this option together with `--state-dir` option because `newa` is going to re-use former data. + +Example: + +``` +$ newa event --compose CentOS-Stream-9 jira --job-recipe path/to/recipe.yaml schedule execute report +Using --state-dir /var/tmp/newa/run-123 +... +Ctrl+C # during the execute step +$ newa --state-dir /var/tmp/newa/run-123 execute --continue report +``` + +#### Option `--no-wait` + +This option instructs `newa` to not to wait for TF request finishing. It is expected that a user will eventually follow up on this `newa` session later. + +Example: + +``` +$ newa event --compose CentOS-Stream-9 jira --job-recipe path/to/recipe.yaml schedule execute --no-wait +Using --state-dir /var/tmp/newa/run-123 +... +$ newa --state-dir /var/tmp/newa/run-123 execute --continue report +``` + +#### Option `--restart-request`, `-R` +This option can be used to reschedule specific NEWA request, specified by the request ID (e.g. `--restart-request REQ-1.2.1`). This option can be used multiple times. Implies `--continue`. + +Example: +``` +newa --prev-state-dir execute -R REQ-1.2.1 -R REQ-2.2.2 report +``` + +#### Option `--restart-result` +This option can be used to reschedule NEWA request that have ended with a particular result - `passed, failed, error`. For example, `--restart-result error`. This option can be used multiple times. Implies `--continue`. + + ### Subcommand `report` This subcommand updates RP launch with recipe status and updates the respective Jira issue with a comment and a link to RP launch containing all test results. diff --git a/newa/__init__.py b/newa/__init__.py index 0070cc8..9dee28f 100644 --- a/newa/__init__.py +++ b/newa/__init__.py @@ -1733,7 +1733,9 @@ class CLIContext: timestamp: str = '' continue_execution: bool = False no_wait: bool = False + restart_request: list[str] = field(factory=list) restart_result: list[str] = field(factory=list) + new_state_dir: bool = False def enter_command(self, command: str) -> None: self.logger.handlers[0].formatter = logging.Formatter( diff --git a/newa/cli.py b/newa/cli.py index 126abbe..ecefe60 100644 --- a/newa/cli.py +++ b/newa/cli.py @@ -200,11 +200,13 @@ def main(click_context: click.Context, ctx.logger.info(f'Using --state-dir={ctx.state_dirpath}') if not ctx.state_dirpath.exists(): + ctx.new_state_dir = True ctx.logger.debug(f'State directory {ctx.state_dirpath} does not exist, creating...') ctx.state_dirpath.mkdir(parents=True) # extract YAML files from the given archive to state-dir if extract_state_dir: + ctx.new_state_dir = False if re.match('^https?://', extract_state_dir): data = urllib.request.urlopen(extract_state_dir).read() tf = tarfile.open(fileobj=io.BytesIO(data), mode='r:*') @@ -938,16 +940,25 @@ def cmd_cancel(ctx: CLIContext) -> None: ) @click.option( '--continue', + '-C', '_continue', is_flag=True, default=False, help='Continue with the previous execution, expects --state-dir usage.', ) +@click.option('--restart-request', + '-R', + default=[], + multiple=True, + help=('Restart NEWA request with the given request ID. ' + 'Can be specified multiple times. Implies --continue. ' + 'Example: --restart-request REQ-1.2.1'), + ) @click.option('--restart-result', default=[], multiple=True, - help=('Restart finished TF jobs having the specified result.' - 'Can be specified multiple times. Implies --continue.' + help=('Restart finished TF jobs having the specified result. ' + 'Can be specified multiple times. Implies --continue. ' 'Example: --restart-result error'), ) @click.option( @@ -962,15 +973,25 @@ def cmd_execute( workers: int, _continue: bool, no_wait: bool, + restart_request: list[str], restart_result: list[str]) -> None: ctx.enter_command('execute') ctx.continue_execution = _continue ctx.no_wait = no_wait + if restart_request: + ctx.restart_request = restart_request + ctx.continue_execution = True + if restart_result: ctx.restart_result = restart_result ctx.continue_execution = True + if ctx.continue_execution and ctx.new_state_dir: + ctx.logger.error( + 'NEWA state-dir was not specified! Use --state-dir or similar option.') + sys.exit(1) + # initialize RP connection rp_project = ctx.settings.rp_project rp_url = ctx.settings.rp_url @@ -1084,6 +1105,13 @@ def cmd_execute( rp.finish_launch(launch_uuid) +def test_patterns_match(s: str, patterns: list[str]) -> tuple[bool, str]: + for pattern in patterns: + if s.strip() == pattern.strip(): + return (True, pattern) + return (False, '') + + def worker(ctx: CLIContext, schedule_file: Path) -> None: # modify log message so it contains name of the processed file @@ -1106,11 +1134,14 @@ def worker(ctx: CLIContext, schedule_file: Path) -> None: if execute_job.execution.result and execute_job.execution.result in ctx.restart_result: log(f'Restarting request {execute_job.request.id}' f' with result {execute_job.execution.result}') + elif ctx.restart_request: + (match, pattern) = test_patterns_match(execute_job.request.id, ctx.restart_request) + if match: + log(f'Restarting request {execute_job.request.id} with ID matching {pattern}') + else: + start_new_request = False else: - tf_request = TFRequest(api=execute_job.execution.request_api, - uuid=execute_job.execution.request_uuid) start_new_request = False - skip_initial_sleep = True if start_new_request: log('initiating TF request') @@ -1138,6 +1169,11 @@ def worker(ctx: CLIContext, schedule_file: Path) -> None: command=command), ) ctx.save_execute_job('execute-', execute_job) + else: + log(f'Re-using existing request {execute_job.request.id}') + tf_request = TFRequest(api=execute_job.execution.request_api, + uuid=execute_job.execution.request_uuid) + skip_initial_sleep = True if ctx.no_wait: log(f'Not waiting for TF request {tf_request.uuid} to finish (--no-wait set).')