Skip to content

Commit 1a72265

Browse files
committed
Rewrite openqa-advanced-retrigger-jobs in python
1 parent deca0b6 commit 1a72265

1 file changed

Lines changed: 95 additions & 116 deletions

File tree

openqa-advanced-retrigger-jobs

Lines changed: 95 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,98 @@
1-
#!/bin/bash -e
2-
host="${host:-"openqa.opensuse.org"}"
3-
failed_since="${failed_since:-"$(date -I)"}"
4-
instance_string="${INSTANCE+" and instance='$INSTANCE'"}"
5-
worker_string="${WORKER+"assigned_worker_id in (select id from workers where (host='$WORKER'$instance_string)) and "}"
6-
result="${result:-"result='incomplete'"}"
7-
additional_filters="${additional_filters+" and $additional_filters"}"
8-
comment="${comment:-""}"
9-
max_jobs_per_request=25
10-
dry_run="${dry_run:-"0"}"
11-
12-
usage() {
13-
cat << EOF
14-
Usage: $0 [OPTIONS]
1+
#!/usr/bin/env python3
152

3+
"""
164
Retrigger openQA jobs based on database queries.
175
18-
By default retriggers openQA jobs with result '$result' since '$failed_since'
19-
on '$host'.
20-
21-
Can be restricted to jobs that ran on worker by setting the variable 'WORKER'
22-
and optionally 'INSTANCE'.
23-
24-
Needs SSH access to the target openQA host '$host'.
25-
26-
Options:
27-
-h, --help display this help
28-
EOF
29-
exit "$1"
30-
}
31-
32-
opts=$(getopt -o h -l help -n "$0" -- "$@") || usage 1
33-
eval set -- "$opts"
34-
while true; do
35-
case "$1" in
36-
-h | --help) usage 0 ;;
37-
--)
38-
shift
39-
break
40-
;;
41-
*) break ;;
42-
esac
43-
done
44-
45-
[ "$dry_run" = "1" ] && client_prefix="echo"
46-
sql_command="select id from jobs where (${worker_string}${result} and clone_id is null and t_finished >= '$failed_since'$additional_filters);"
47-
# shellcheck disable=SC2029
48-
job_ids=${JOB_IDS:-$(ssh "$host" "sudo -u geekotest psql --no-align --tuples-only --command=\"$sql_command\" openqa")}
49-
50-
usage() {
51-
cat << EOF
52-
Usage: $0 [OPTIONS]
53-
54-
Retrigger openQA jobs based on database queries.
55-
56-
By default retriggers openQA jobs with '$result' since '$failed_since' on
57-
'$host'.
58-
59-
Needs SSH access to the target openQA host '$host' to query the database
60-
unless 'JOB_IDS' is provided.
61-
62-
Options:
63-
-h, --help display this help
64-
65-
Environment variables:
66-
host target openQA host (default: $host)
67-
failed_since retrigger jobs finished since this date (default: $failed_since)
68-
result retrigger jobs with this result (default: $result)
69-
additional_filters additional SQL filters for the job query
70-
comment comment to add to retriggered jobs
71-
dry_run set to 1 to only print what would be done
72-
WORKER restrict to jobs that ran on this worker host
73-
INSTANCE restrict to jobs that ran on this worker instance
74-
sql_command custom SQL command to fetch job IDs
75-
JOB_IDS comma or space separated list of job IDs to retrigger
76-
cli_protocol protocol for openqa-cli (e.g. https)
77-
cli_port port for openqa-cli
78-
EOF
79-
exit "$1"
80-
}
81-
82-
restart-jobs() {
83-
[[ ${#query_params[@]} -lt 1 ]] && return
84-
[[ $comment ]] && query_params+=("comment=$comment")
85-
$client_prefix openqa-cli api --host "$host" -X POST jobs/restart "${query_params[@]}"
86-
query_params=()
87-
}
88-
89-
main() {
90-
opts=$(getopt -o h -l help -n "$0" -- "$@") || usage 1
91-
eval set -- "$opts"
92-
while true; do
93-
case "$1" in
94-
-h | --help) usage 0 ;;
95-
--)
96-
shift
97-
break
98-
;;
99-
*) break ;;
100-
esac
101-
done
102-
103-
[ "$dry_run" = "1" ] && client_prefix="echo"
104-
sql_command=${sql_command:-"select id from jobs where (${worker_string}${result} and clone_id is null and t_finished >= '$failed_since'$additional_filters);"}
105-
# shellcheck disable=SC2029
106-
job_ids=${JOB_IDS:-$(ssh "$host" "sudo -u geekotest psql --no-align --tuples-only --command=\"$sql_command\" openqa")}
107-
108-
query_params=()
109-
[[ $cli_protocol ]] && host=$cli_protocol://$host
110-
[[ $cli_port ]] && host+=:$cli_port
111-
112-
for job_id in $job_ids; do
113-
query_params+=("jobs=$job_id")
114-
[[ ${#query_params[@]} -ge "$max_jobs_per_request" ]] && restart-jobs
115-
done
116-
restart-jobs
117-
}
118-
119-
caller 0 > /dev/null || main "$@"
6+
Needs SSH access to the specified target openQA host.
7+
8+
Simple example call retriggering all recent incompletes on the default host:
9+
%(prog)s
10+
11+
Advanced example retriggering failed instead of incompletes, verbose output, with custom starting date,
12+
custom host and excluding jobs with \":investigate:\" in the name, executed as dry-run:
13+
%(prog)s -vvvv --host openqa.example.org --failed-since '2000-01-01T10:00' --result failed \
14+
--additional-filters \"test not like '%%:investigate:%%'\" --dry-run
15+
"""
16+
17+
import argparse
18+
import logging
19+
import subprocess
20+
import sys
21+
from datetime import datetime
22+
23+
logging.basicConfig()
24+
log = logging.getLogger(sys.argv[0] if __name__ == "__main__" else __name__)
25+
26+
27+
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
28+
"""Preserve multi-line __doc__ and provide default arguments in help strings."""
29+
30+
pass
31+
32+
33+
def parse_args():
34+
parser = argparse.ArgumentParser(description=__doc__, formatter_class=CustomFormatter)
35+
parser.add_argument(
36+
"-v",
37+
"--verbose",
38+
help="Increase verbosity level, specify multiple times to increase verbosity",
39+
action="count",
40+
default=1,
41+
)
42+
parser.add_argument("-H", "--host", default="openqa.opensuse.org", help="Target openQA host")
43+
parser.add_argument(
44+
"-s",
45+
"--failed-since",
46+
default=datetime.today().isoformat(),
47+
help="Filter jobs failed since this date",
48+
)
49+
parser.add_argument("-w", "--worker", default=None, help="Filter jobs assigned to this worker")
50+
parser.add_argument("-i", "--instance", default=None, help="Instance of the worker")
51+
parser.add_argument("-r", "--result", default="incomplete", help="Filter jobs with this result")
52+
parser.add_argument(
53+
"-a",
54+
"--additional-filters",
55+
default=None,
56+
help="Additional filters for the SQL query",
57+
)
58+
parser.add_argument("-c", "--comment", default=None, help="Comment to add to the retriggered jobs")
59+
parser.add_argument(
60+
"-d",
61+
"--dry-run",
62+
action="store_true",
63+
help="If set, only print the actions without executing",
64+
)
65+
args = parser.parse_args()
66+
logging_level = (5 - min(args.verbose, 4)) * 10
67+
log.setLevel(logging_level)
68+
return args
69+
70+
def post(dry_run: bool, host: str, route: str, *args):
71+
cmd=('openqa-cli', 'api', '--host', host, '-X', 'POST', route, *args)
72+
if dry_run:
73+
return print(f"dry run: {cmd}")
74+
subprocess.run(cmd, check=True)
75+
76+
def main(args):
77+
log.debug(args)
78+
instance_string = f" and instance='{args.instance}'" if args.instance else ""
79+
worker_string = f"assigned_worker_id in (select id from workers where (host='{args.worker}'{instance_string})) and " if args.worker else ""
80+
additional_filters = f" and {args.additional_filters}" if args.additional_filters else ""
81+
82+
query = (
83+
f"select id from jobs where ({worker_string}result='{args.result}' "
84+
f"and clone_id is null and t_finished >= '{args.failed_since}'{additional_filters});"
85+
)
86+
87+
log.debug(f"Using SQL query: '{query}' on {args.host}")
88+
ssh_command = ('ssh', args.host, f"sudo -u geekotest psql --no-align --tuples-only --command=\"{query}\" openqa")
89+
job_ids = subprocess.check_output(ssh_command).decode().splitlines()
90+
91+
for job_id in job_ids:
92+
post(args.dry_run, args.host, f"jobs/{job_id}/restart")
93+
if args.comment:
94+
post(args.dry_run, args.host, f"jobs/{job_id}/comments", f'text={args.comment}')
95+
96+
97+
if __name__ == "__main__":
98+
main(parse_args())

0 commit comments

Comments
 (0)