Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Introduce new initial job state "new" #6157

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions assets/assetpack.def
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@
! logo-scheduled-16.png
< images/logo-scheduled-16.png

! logo-new-16.png
< images/logo-blocked-16.png

! logo-blocked-16.png
< images/logo-blocked-16.png

Expand Down Expand Up @@ -223,6 +226,9 @@
! logo-scheduled.svg
< images/logo-scheduled.svg

! logo-new.svg
< images/logo-blocked.svg

! logo-blocked.svg
< images/logo-blocked.svg

Expand Down
2 changes: 1 addition & 1 deletion assets/javascripts/create_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function createTests(form) {
success: function (response) {
const id = response.scheduled_product_id;
const url = `${form.dataset.productlogUrl}?id=${id}`;
addFlash('info', `Tests have been scheduled, checkout the <a href="${url}">product log</a> for details.`);
addFlash('info', `Tests have been created, checkout the <a href="${url}">product log</a> for details.`);
},
error: function (xhr, ajaxOptions, thrownError) {
addFlash('danger', 'Unable to create tests: ' + (xhr.responseJSON?.error ?? xhr.responseText ?? thrownError));
Expand Down
4 changes: 2 additions & 2 deletions assets/javascripts/job_next_previous.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function renderJobResults(data, type, row) {
// job status
html += '<span id="res-' + row.id + '">';
html += '<a href="' + urlWithBase('/tests/' + row.id) + '">';
if (row.result == 'none' && (row.state == 'running' || row.state == 'scheduled')) {
if (row.result == 'none' && (row.state === 'running' || row.state === 'scheduled' || row.state === 'new')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we keep the state "new" as a substate internally but treat it the same as scheduled for the whole UI layer including here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add yet another column to the jobs table (besides the relation for referencing Gru tasks) that allows us to flag jobs as not ready to be scheduled (without already having to assign a gru job ID).

Maybe we could also create a dummy Gru task without Minion job and assign that initially. This approach would avoid the extra column but also be a bit hacky.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about forward compatibility and options to extend for potential future use cases. job->state is already a flexible "varchar" in the schema so we can also reflect "new" there but here and in other cases we are in the UI layer so I thought that maybe we can translate from internal states to external states. We already have layed the groundwork with lib/OpenQA/Jobs/Constants.pm the past years where we have meta results and meta results. How about keeping "state" strictly internal – or maybe only reflect over the API for expert usage – and keep the UI layer strictly bound to the meta states?

html += '<i class="status fa fa-circle state_' + row.state + '" title="' + row.state + '"></i>';
} else {
html += '<i class="status fa fa-circle result_' + row.result + '" title="Done: ' + row.result + '"></i>';
Expand Down Expand Up @@ -130,7 +130,7 @@ function renderFinishTime(data, type, row) {
html += '<abbr class="timeago" title="' + data + '">' + jQuery.timeago(data) + ' </abbr>';
html += '( ' + row.duration + ' )';
} else {
if (row.state == 'running' || row.state == 'scheduled') {
if (row.state === 'running' || row.state === 'scheduled' || row.state === 'new') {
html += 'Not yet: ' + row.state;
}
}
Expand Down
2 changes: 1 addition & 1 deletion assets/javascripts/openqa.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ function renderSearchResults(query, url) {
function testStateHTML(job) {
var className = 'status fa fa-circle';
var title;
if (job.state === 'running' || job.state === 'scheduled') {
if (job.state === 'running' || job.state === 'scheduled' || job.state === 'new') {
if (job.state === 'scheduled' && job.blocked_by_id) {
className += ' state_blocked';
title = 'blocked';
Expand Down
2 changes: 2 additions & 0 deletions assets/javascripts/overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ function setupOverview() {
$('.cancel').bind('ajax:success', function (event, xhr, status) {
$(this).text(''); // hide the icon
var icon = $(this).parents('td').find('.status');
// FIXME
icon.removeClass('state_scheduled').removeClass('state_running');
icon.addClass('state_cancelled');
icon.attr('title', 'Cancelled');
Expand All @@ -147,6 +148,7 @@ function setupOverview() {
restarted.text(''); // hide the icon
var icon = restarted.parents('td').find('.status');
icon.removeClass('state_done').removeClass('state_cancelled');
// FIXME
icon.addClass('state_scheduled');
icon.attr('title', 'Scheduled');
// remove the result class
Expand Down
10 changes: 6 additions & 4 deletions assets/javascripts/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,13 @@ function renderTestName(data, type, row) {
html += '<a href="' + urlWithBase('/tests/' + row.id) + '">';
if (row.result !== 'none') {
html += '<i class="status fa fa-circle result_' + row.result + '" title="Done: ' + row.result + '"></i>';
} else if (row.state === 'scheduled') {
} else if (row.state === 'new' || row.state === 'scheduled') {
if (typeof row.blocked_by_id === 'number') {
html += '<i class="status fa fa-circle state_blocked" title="Blocked"></i>';
} else {
} else if (row.state === 'scheduled') {
html += '<i class="status fa fa-circle state_scheduled" title="Scheduled"></i>';
} else {
html += '<i class="status fa fa-circle state_new" title="New"></i>';
}
} else if (row.state === 'assigned') {
html += '<i class="status fa fa-circle state_running" title="Assigned"></i>';
Expand Down Expand Up @@ -255,7 +257,7 @@ function renderTestLists() {
}
});

// initialize data tables for running, scheduled and finished jobs
// initialize data tables for running, new/scheduled/blocked and finished jobs
var runningTable = $('#running').DataTable({
order: [], // no initial resorting
ajax: {
Expand Down Expand Up @@ -307,7 +309,7 @@ function renderTestLists() {
++blockedCount;
}
});
var text = json.data.length + ' scheduled jobs';
var text = json.data.length + ' new or scheduled jobs';
if (blockedCount > 0) {
text += ' (' + blockedCount + ' blocked by other jobs)';
}
Expand Down
2 changes: 1 addition & 1 deletion assets/stylesheets/dependency_graph.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
color: white;
background-color: $color-incomplete;
}
&.blocked {
&.new, &.blocked {
background-color: $color-state-blocked;
}
&.scheduled {
Expand Down
2 changes: 1 addition & 1 deletion assets/stylesheets/test-details.scss
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ div.flags {
.state_scheduled.fa {
color: $color-state-scheduled;
}
.state_blocked.fa {
.state_new.fa, .state_blocked.fa {
color: $color-state-blocked;
}
.state_obsolete.fa, .state_cancelled.fa {
Expand Down
7 changes: 4 additions & 3 deletions docs/GettingStarted.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,9 @@ Every job is labeled with a numeric identifier and has several associated
A job goes through several states. Here is (an incomplete list) of these
states:

* *scheduled* Initial state for newly created jobs. Queued for future
execution.
* *new* Initial state for newly created jobs. Those jobs will transition to the
scheduled state as soon as all required preparation tasks have been completed.
* *scheduled* Queued for future execution.
* *setup*/*running*/*uploading* In progress.
* *cancelled* The job was explicitly cancelled by the user or was
replaced by a clone (see below) and the worker has not acknowledged the
Expand Down Expand Up @@ -378,7 +379,7 @@ clone a subdirectory under `/var/lib/openqa/tests` for each test distribution
you need, e.g. `/var/lib/openqa/tests/opensuse` for openSUSE tests.

The repositories will be kept up-to-date if `git_auto_update` is enabled in
`openqa.ini`. The updating is triggered when new tests are scheduled. For a
`openqa.ini`. The updating is triggered when new tests are created. For a
periodic update (to avoid getting too far behind) you can enable the systemd
unit `openqa-enqueue-git-auto-update.timer`.

Expand Down
3 changes: 1 addition & 2 deletions docs/UsersGuide.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -1407,8 +1407,7 @@ If the size limit for assets of a group is exceeded, openQA will remove
assets which belong to that group:

* Assets belonging to old jobs are preferred.
* Assets belonging to jobs which are still scheduled or running are not
considered.
* Assets belonging to jobs which are still pending are not considered.
* Assets which have been accounted to another group that has still space
left are not considered.

Expand Down
13 changes: 8 additions & 5 deletions lib/OpenQA/Jobs/Constants.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use Exporter 'import';

# job states
use constant {
# initial job state; the job is supposed to be assigned to a worker by the scheduler
# initial job state; the job has been created but not ready to be scheduled due to pending tasks
NEW => 'new',
# the job is supposed to be assigned to a worker by the scheduler
SCHEDULED => 'scheduled',
# the job has been sent to worker but worker has not acknowledged yet; the state might be reverted to
# SCHEDULED in some conditions
Expand All @@ -27,7 +29,7 @@ use constant {
# or the job has been cancelled due to failed parallel dependencies (result PARALLEL_FAILED is set)
DONE => 'done',
};
use constant STATES => (SCHEDULED, ASSIGNED, SETUP, RUNNING, UPLOADING, DONE, CANCELLED);
use constant STATES => (NEW, SCHEDULED, ASSIGNED, SETUP, RUNNING, UPLOADING, DONE, CANCELLED);

# note regarding CANCELLED vs. DONE:
# There is an overlap between CANCELLED and DONE (considering that some results are possibly assigned in either of these
Expand All @@ -37,10 +39,10 @@ use constant STATES => (SCHEDULED, ASSIGNED, SETUP, RUNNING, UPLOADING, DONE, CA
# That is usually the case for jobs SKIPPED due to failed chained dependencies (*not* directly chained dependencies).

# "meta" states
use constant PENDING_STATES => (SCHEDULED, ASSIGNED, SETUP, RUNNING, UPLOADING);
use constant PENDING_STATES => (NEW, SCHEDULED, ASSIGNED, SETUP, RUNNING, UPLOADING);
use constant EXECUTION_STATES => (ASSIGNED, SETUP, RUNNING, UPLOADING);
use constant PRE_EXECUTION_STATES => (SCHEDULED);
use constant PRISTINE_STATES => (SCHEDULED, ASSIGNED); # no worker reported any updates/results so far
use constant PRE_EXECUTION_STATES => (NEW, SCHEDULED);
use constant PRISTINE_STATES => (NEW, SCHEDULED, ASSIGNED); # no worker reported any updates/results so far
use constant FINAL_STATES => (DONE, CANCELLED);
use constant {
PRE_EXECUTION => 'pre_execution',
Expand Down Expand Up @@ -135,6 +137,7 @@ our @EXPORT = qw(
USER_CANCELLED
USER_RESTARTED
MODULE_RESULTS
NEW
COMMON_RESULT_FILES
TIMEOUT_EXCEEDED
DEFAULT_JOB_PRIORITY
Expand Down
2 changes: 2 additions & 0 deletions lib/OpenQA/Schema.pm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use OpenQA::Utils qw(:DEFAULT prjdir);
# after bumping the version please look at the instructions in the docs/Contributing.asciidoc file
# on what scripts should be run and how
our $VERSION = $ENV{OPENQA_SCHEMA_VERSION_OVERRIDE} // 100;
# FIXME: bump this and generate deployment files
# to change `state character varying DEFAULT 'scheduled' NOT NULL,` to `state character varying DEFAULT 'new' NOT NULL,`

__PACKAGE__->load_namespaces;

Expand Down
22 changes: 11 additions & 11 deletions lib/OpenQA/Schema/Result/Jobs.pm
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ __PACKAGE__->add_columns(
},
state => {
data_type => 'varchar',
default_value => SCHEDULED,
default_value => NEW,
},
priority => {
data_type => 'integer',
Expand Down Expand Up @@ -975,7 +975,8 @@ sub auto_duplicate ($self, $args = {}) {
while (my $j = $jobs->next) {
if (my $sp_id = $j->related_scheduled_product_id) { $related_scheduled_product_ids{$sp_id} = 1 }
next if $j->abort;
next unless $j->state eq SCHEDULED || $j->state eq ASSIGNED;
my $state = $j->state;
next unless any { $_ eq $state } PRISTINE_STATES;
$j->release_networks;
$j->update({state => CANCELLED});
}
Expand Down Expand Up @@ -1809,7 +1810,8 @@ sub _job_stop_cluster ($self, $job) {
$job = $rset->search({id => $job, result => NONE}, {rows => 1})->first;
return 0 unless $job;

if ($job->state eq SCHEDULED || $job->state eq ASSIGNED) {
my $state = $j->state;
if (any { $_ eq $state } PRISTINE_STATES) {
$job->release_networks;
$job->update({result => SKIPPED, state => CANCELLED});
}
Expand Down Expand Up @@ -2349,22 +2351,20 @@ sub _overview_result_done ($self, $jobid, $job_labels, $aggregated, $failed_modu

sub overview_result ($self, $job_labels, $aggregated, $failed_modules, $actually_failed_modules, $todo = undef) {
my $jobid = $self->id;
if ($self->state eq OpenQA::Jobs::Constants::DONE) {
my $state = $self->state;
if ($state eq DONE) {
return $self->_overview_result_done($jobid, $job_labels, $aggregated, $failed_modules,
$actually_failed_modules, $todo);
}
return undef if $todo;
my $result = {
state => $self->state,
jobid => $jobid,
};
if ($self->state eq OpenQA::Jobs::Constants::RUNNING) {
my $result = {state => $state, jobid => $jobid};
if ($state eq RUNNING) {
$aggregated->{running}++;
}
else {
$result->{priority} = $self->priority;
if ($self->state eq OpenQA::Jobs::Constants::SCHEDULED) {
$aggregated->{scheduled}++;
if ($state eq NEW || $state eq SCHEDULED) {
$aggregated->{$state}++;
$result->{blocked} = 1 if defined $self->blocked_by_id;
}
else {
Expand Down
2 changes: 1 addition & 1 deletion lib/OpenQA/WebAPI/Controller/API/V1/Mm.pm
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ sub get_children_status {
$state = OpenQA::Jobs::Constants::RUNNING;
}
elsif ($state eq 'scheduled') {
$state = OpenQA::Jobs::Constants::SCHEDULED;
$state = OpenQA::Jobs::Constants::SCHEDULED; # FIXME: does this need adjustment?
}
else {
$state = OpenQA::Jobs::Constants::DONE;
Expand Down
2 changes: 1 addition & 1 deletion lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ sub _incomplete_previous_job {
my $job_id = $job->id;
return 0 if $jobs_worker_says_it_works_on->{$job_id};
my $job_state = $job->state;
return 1 if $job_state eq OpenQA::Jobs::Constants::SCHEDULED;
return 1 if $job_state eq NEW || $job_state eq SCHEDULED;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in all logic we should avoid "this state || that state" and instead use aggregated states where we would need to check for more than one state. Same as you did in https://github.com/os-autoinst/openQA/pull/6157/files#diff-1c4e8d9bc0096026bc67314675374924c7a5da02359b426a1c6401eac9e90abeR1814


# set jobs which were only assigned anyways back to scheduled
if ($job_state eq OpenQA::Jobs::Constants::ASSIGNED) {
Expand Down
6 changes: 4 additions & 2 deletions lib/OpenQA/WebAPI/Controller/Admin/Influxdb.pm
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ sub jobs ($self) {

my $schema = $self->schema;
my $jobs = $schema->resultset('Jobs');
my $rs = $jobs->search({state => OpenQA::Jobs::Constants::SCHEDULED, blocked_by_id => undef});
my $rs = $jobs->search({state => NEW, blocked_by_id => undef});
_queue_sub_stats($rs, 'new', $result);
$rs = $jobs->search({state => SCHEDULED, blocked_by_id => undef});
_queue_sub_stats($rs, 'scheduled', $result);
$rs = $jobs->search({state => OpenQA::Jobs::Constants::SCHEDULED, -not => {blocked_by_id => undef}});
$rs = $jobs->search({state => [NEW, SCHEDULED], -not => {blocked_by_id => undef}});
_queue_sub_stats($rs, 'blocked', $result);
$rs = $jobs->search({state => [OpenQA::Jobs::Constants::EXECUTION_STATES]});
_queue_sub_stats($rs, 'running', $result);
Expand Down
2 changes: 2 additions & 0 deletions lib/OpenQA/WebAPI/Controller/Test.pm
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ my %BADGE_RESULT_COLORS = (
incomplete => '#AF1E11',
timeout_exceeded => '#AF1E11',
blocked => '#9167b7',
new => '#9167b7',
scheduled => '#67A2B7',
cancelled => '#aaaaaa',
user_cancelled => '#aaaaaa',
Expand Down Expand Up @@ -697,6 +698,7 @@ sub _prepare_job_results ($self, $all_jobs, $limit) {
failed => 0,
not_complete => 0,
aborted => 0,
new => 0,
scheduled => 0,
running => 0,
unknown => 0
Expand Down
2 changes: 1 addition & 1 deletion templates/webapi/test/list.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</div>

<div>
<h2 id="scheduled_jobs_heading">Scheduled jobs</h2>
<h2 id="scheduled_jobs_heading">New and Scheduled jobs</h2>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as my comment in https://github.com/os-autoinst/openQA/pull/6157/files#diff-6937e1376520bc4c4992d9cf39d5a3522676f0ae07e4be058fe88407e717f266R78 I think it would be good to distinguish between UI facing states and sub-states in the implementation unless there is a difference for the user. So far I don't see that difference for the user.

<table id="scheduled" class="display table table-striped" style="width: 100%">
<thead>
<tr>
Expand Down
4 changes: 2 additions & 2 deletions templates/webapi/test/overview.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
</button>
% }
% my @badges = qw(success secondary warning danger info primary light light);
% my @labels = qw(Passed Incomplete Soft-Failed Failed Scheduled Running Aborted None);
% my @labels = qw(Passed Incomplete Soft-Failed Failed New Scheduled Running Aborted None);
% my $index = 0;
% for my $category (qw(passed not_complete softfailed failed scheduled running aborted none)) {
% for my $category (qw(passed not_complete softfailed failed new scheduled running aborted none)) {
% my ($label, $badge) = ($labels[$index], $badges[$index++]);
% next unless my $count = delete $aggregated->{$category};
<%= $label %>: <span class="badge text-bg-<%= $badge %>"><%= $count %></span>
Expand Down
4 changes: 2 additions & 2 deletions templates/webapi/test/tr_job_result.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
<i class="status fa fa-circle result_<%= $res->{overall} %>" title="Done: <%= $res->{overall} %>"></i>
</a>
% }
% elsif ($state eq SCHEDULED) {
% my $substate = $res->{blocked} ? 'blocked' : 'scheduled';
% elsif ($state eq NEW || $state eq SCHEDULED) {
% my $substate = $res->{blocked} ? 'blocked' : $state;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO this "substate" is already a better approach for the UI level

<a href="<%= url_for('test', 'testid' => $jobid) %>">
<i class="status state_<%= $substate %> fa fa-circle" title="<%= $substate %>@<%= $res->{priority} %>"></i>
</a>
Expand Down