Skip to content

Commit

Permalink
Split monitoring of jobs via openqa-cli into a separate command
Browse files Browse the repository at this point in the history
This allows to monitor a set of job which will be useful for further
CI-related use cases like cloning existing jobs and monitoring them (see
https://progress.opensuse.org/issues/130934).

Of course the existing `openqa-cli schedule` command will continue to
support the `--monitor` parameter.
  • Loading branch information
Martchus committed Feb 20, 2024
1 parent 05b36bd commit 4904382
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 34 deletions.
73 changes: 73 additions & 0 deletions lib/OpenQA/CLI/monitor.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright SUSE LLC
# SPDX-License-Identifier: GPL-2.0-or-later

package OpenQA::CLI::monitor;
use OpenQA::Jobs::Constants;
use Mojo::Base 'OpenQA::Command', -signatures;
use Mojo::Util qw(encode getopt);

has description => 'Monitors a set of jobs';
has usage => sub { shift->extract_usage };

sub _monitor_jobs ($self, $client, $poll_interval, $job_ids, $job_results) {
while (@$job_results < @$job_ids) {
my $job_id = $job_ids->[@$job_results];
my $tx = $client->build_tx(GET => $self->url_for("experimental/jobs/$job_id/status"), {});
my $res = $self->retry_tx($client, $tx);
return $res if $res != 0;
my $job = $tx->res->json;
my $job_state = $job->{state} // NONE;
if (OpenQA::Jobs::Constants::meta_state($job_state) eq OpenQA::Jobs::Constants::FINAL) {
push @$job_results, $job->{result} // NONE;
next;
}
print encode('UTF-8', "Job state of job ID $job_id: $job_state, waiting …\n");
sleep $poll_interval;
}
}

sub _compute_return_code ($self, $job_results) {
for my $job_result (@$job_results) {
return 2 unless OpenQA::Jobs::Constants::is_ok_result($job_result);
}
return 0;
}

sub _monitor_and_return ($self, $client, $poll_interval, $job_ids) {
my @job_results;
my $monitor_res = $self->_monitor_jobs($client, $poll_interval // 10, $job_ids, \@job_results);
return $monitor_res if $monitor_res != 0;
return $self->_compute_return_code(\@job_results);
}

sub command ($self, @args) {
die $self->usage unless getopt \@args, 'i|poll-interval=i' => \my $poll_interval;
@args = $self->decode_args(@args);
$self->_monitor_and_return($self->client($self->url_for('tests')), $poll_interval, \@args);
}

1;

=encoding utf8
=head1 SYNOPSIS
Usage: openqa-cli monitor [OPTIONS] [job_id…]
Options:
--apibase <path> API base, defaults to /api/v1
--apikey <key> API key
--apisecret <secret> API secret
--host <host> Target host, defaults to http://localhost
-h, --help Show this summary of available options
--osd Set target host to http://openqa.suse.de
--o3 Set target host to https://openqa.opensuse.org
--name <name> Name of this client, used by openQA to
identify different clients via User-Agent
header, defaults to "openqa-cli"
-i, --poll-interval Specifies the poll interval
-p, --pretty Pretty print JSON content
-q, --quiet Do not print error messages to STDERR
-v, --verbose Print HTTP response headers
=cut
33 changes: 2 additions & 31 deletions lib/OpenQA/CLI/schedule.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later

package OpenQA::CLI::schedule;
use OpenQA::Jobs::Constants;
use Mojo::Base 'OpenQA::Command', -signatures;
use Mojo::Base 'OpenQA::CLI::monitor', -signatures;
use Mojo::Util qw(encode getopt);
use Term::ANSIColor qw(colored);

Expand All @@ -29,30 +28,6 @@ sub _create_jobs ($self, $client, $args, $param_file, $job_ids) {
return 1;
}

sub _monitor_jobs ($self, $client, $poll_interval, $job_ids, $job_results) {
while (@$job_results < @$job_ids) {
my $job_id = $job_ids->[@$job_results];
my $tx = $client->build_tx(GET => $self->url_for("experimental/jobs/$job_id/status"), {});
my $res = $self->retry_tx($client, $tx);
return $res if $res != 0;
my $job = $tx->res->json;
my $job_state = $job->{state} // NONE;
if (OpenQA::Jobs::Constants::meta_state($job_state) eq OpenQA::Jobs::Constants::FINAL) {
push @$job_results, $job->{result} // NONE;
next;
}
print encode('UTF-8', "Job state of job ID $job_id: $job_state, waiting …\n");
sleep $poll_interval;
}
}

sub _compute_return_code ($self, $job_results) {
for my $job_result (@$job_results) {
return 2 unless OpenQA::Jobs::Constants::is_ok_result($job_result);
}
return 0;
}

sub command ($self, @args) {
die $self->usage
unless getopt \@args,
Expand All @@ -66,11 +41,7 @@ sub command ($self, @args) {
my @job_ids;
my $create_res = $self->_create_jobs($client, \@args, \@param_file, \@job_ids);
return $create_res if $create_res != 0 || !$monitor;

my @job_results;
my $monitor_res = $self->_monitor_jobs($client, $poll_interval // 10, \@job_ids, \@job_results);
return $monitor_res if $monitor_res != 0;
return $self->_compute_return_code(\@job_results);
return $self->_monitor_and_return($client, $poll_interval, \@job_ids);
}

1;
Expand Down
22 changes: 19 additions & 3 deletions t/43-cli-schedule.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use lib "$FindBin::Bin/lib", "$FindBin::Bin/../external/os-autoinst-common/lib";

use OpenQA::Test::TimeLimit '7';
use OpenQA::CLI;
use OpenQA::CLI::monitor;
use OpenQA::CLI::schedule;
use OpenQA::Jobs::Constants;
use OpenQA::Test::Case;
Expand All @@ -18,9 +19,10 @@ use Mojo::File qw(tempdir tempfile);
use Test::Output qw(combined_like);
use Test::MockModule;

my $schedule = OpenQA::CLI::schedule->new;
$ENV{OPENQA_CLI_RETRIES} = 0;
OpenQA::Test::Case->new->init_data(fixtures_glob => '03-users.pl');

my $schema = OpenQA::Test::Case->new->init_data(fixtures_glob => '03-users.pl');
my $schedule = OpenQA::CLI::schedule->new;

# change API to simulate job state/result changes
my $job_controller_mock = Test::MockModule->new('OpenQA::WebAPI::Controller::API::V1::Job');
Expand Down Expand Up @@ -50,7 +52,8 @@ subtest 'unknown options' => sub {
};

# define different sets of CLI args to be used in further tests
my @options = ('--apikey', 'ARTHURKEY01', '--apisecret', 'EXCALIBUR', '--host', $host, '-m', '-i', 0);
my @basic_options = ('--apikey', 'ARTHURKEY01', '--apisecret', 'EXCALIBUR', '--host', $host, '-i', 0);
my @options = (@basic_options, '-m');
my @scenarios = ('--param-file', "SCENARIO_DEFINITIONS_YAML=$FindBin::Bin/data/09-schedule_from_file.yaml");
my @settings1 = (qw(DISTRI=example VERSION=0 FLAVOR=DVD ARCH=x86_64 TEST=simple_boot));
my @settings2 = (qw(DISTRI=opensuse VERSION=13.1 FLAVOR=DVD ARCH=i586 BUILD=0091 TEST=autoyast_btrfs));
Expand Down Expand Up @@ -85,4 +88,17 @@ subtest 'scheduling and monitoring set of two jobs' => sub {
is $res, 2, 'non-zero return-code if at least one job is not ok';
};

subtest 'monitor jobs as a separate command' => sub {
my $res;
my $monitor = OpenQA::CLI::monitor->new;
my $jobs = $schema->resultset('Jobs');
$jobs->create({id => $_, TEST => "test-$_"}) for (100 .. 103);
@job_mock_results = (PASSED, SOFTFAILED);
combined_like { $res = $monitor->run(@basic_options, 100, 101) } qr/100.*101/s, 'status logged (passing case)';
is $res, 0, 'zero return-code if all jobs ok';
@job_mock_results = (PASSED, FAILED);
combined_like { $res = $monitor->run(@basic_options, 102, 103) } qr/102.*103/s, 'status logged (failing case)';
is $res, 2, 'none-zero return-code if one job failed';
};

done_testing();

0 comments on commit 4904382

Please sign in to comment.