Skip to content

Commit

Permalink
remove the CPU_ARCH feature and rely on WORKER_CLASS
Browse files Browse the repository at this point in the history
CPU_ARCH just doesn't make sense with s390 backend, so the worker
sends WORKER_CLASS=qemu_$CPU_ARCH as default and we have to set the
ppc machines to rely on qemu_ppc64
  • Loading branch information
coolo committed Mar 26, 2015
1 parent 9e7de37 commit 8caa395
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 80 deletions.
15 changes: 14 additions & 1 deletion lib/OpenQA/Controller/API/V1/Iso.pm
Expand Up @@ -127,19 +127,32 @@ sub _generate_jobs {
for my $job_template (@templates) {
my %settings = map { $_->key => $_->value } $product->settings;

# we need to merge worker classes of all 3
my @classes;
if (my $class = delete $settings{WORKER_CLASS}) {
push @classes, $class;
}

my %tmp_settings = map { $_->key => $_->value } $job_template->machine->settings;
if (my $class = delete $tmp_settings{WORKER_CLASS}) {
push @classes, $class;
}
@settings{keys %tmp_settings} = values %tmp_settings;

%tmp_settings = map { $_->key => $_->value } $job_template->test_suite->settings;
if (my $class = delete $tmp_settings{WORKER_CLASS}) {
push @classes, $class;
}
@settings{keys %tmp_settings} = values %tmp_settings;
$settings{TEST} = $job_template->test_suite->name;
$settings{MACHINE} = $job_template->machine->name;
$settings{BACKEND} = $job_template->machine->backend;
$settings{WORKER_CLASS} = join(',', sort(@classes));

next if $args{TEST} && $args{TEST} ne $settings{TEST};
next if $args{MACHINE} && $args{MACHINE} ne $settings{MACHINE};

for (keys %args) {
for (keys %args) {
$settings{uc $_} = $args{$_};
}
# Makes sure tha the DISTRI is lowercase
Expand Down
40 changes: 24 additions & 16 deletions lib/OpenQA/Controller/API/V1/Worker.pm
Expand Up @@ -35,20 +35,12 @@ sub list {
$self->render(json => { workers => $ret });
}

sub create {
my ($self) = @_;
my $host = $self->param('host');
my $instance = $self->param('instance');
my $caps = {};
# TODO: this function exists purely for unit tests to be able to register
# workers without fixtures. We need to avoid this
sub _register {
my ($self, $schema, $host, $instance, $caps) = @_;

$caps->{cpu_modelname} = $self->param('cpu_modelname');
$caps->{cpu_arch} = $self->param('cpu_arch');
$caps->{cpu_opmode} = $self->param('cpu_opmode');
$caps->{mem_max} = $self->param('mem_max');
$caps->{worker_class} = $self->param('worker_class');


my $worker = $self->db->resultset("Workers")->search(
my $worker = $schema->resultset("Workers")->search(
{
host => $host,
instance => int($instance),
Expand All @@ -59,7 +51,7 @@ sub create {
$worker->update({ t_updated => now() });
}
else {
$worker = schema->resultset("Workers")->create(
$worker = $schema->resultset("Workers")->create(
{
host => $host,
instance => $instance
Expand All @@ -73,7 +65,7 @@ sub create {
# ... restart job assigned to this worker
if (my $job = $worker->job) {
$job->set_property('JOBTOKEN');
job_duplicate(jobid => $job->id);
OpenQA::Scheduler::job_duplicate(jobid => $job->id);
# .. set it incomplete
$job->update(
{
Expand All @@ -90,7 +82,23 @@ sub create {
$worker->set_property('STOP_WAITFORNEEDLE_REQUESTED', 0);

die "got invalid id" unless $worker->id;
$self->render(json => { id => $worker->id} );
return $worker->id;
}

sub create {
my ($self) = @_;
my $host = $self->param('host');
my $instance = $self->param('instance');
my $caps = {};

$caps->{cpu_modelname} = $self->param('cpu_modelname');
$caps->{cpu_arch} = $self->param('cpu_arch');
$caps->{cpu_opmode} = $self->param('cpu_opmode');
$caps->{mem_max} = $self->param('mem_max');
$caps->{worker_class} = $self->param('worker_class');

my $id = $self->_register($self->db, $host, $instance, $caps);
$self->render(json => { id => $id} );

}

Expand Down
79 changes: 38 additions & 41 deletions lib/OpenQA/Scheduler.pm
Expand Up @@ -96,22 +96,6 @@ $worker_commands{continue_waitforneedle} = sub {
$worker->set_property("STOP_WAITFORNEEDLE_REQUESTED", 0);
};

# the template noted what architecture are known
my %cando = (
'i586' => ['i586'],
'i686' => [ 'i586', 'i686' ],
'x86_64' => [ 'x86_64', 'i586', 'i686' ],

'ppc' => ['ppc'],
'ppc64' => [ 'ppc64le', 'ppc64', 'ppc' ],
'ppc64le' => [ 'ppc64le', 'ppc64', 'ppc' ],

's390' => ['s390'],
's390x' => [ 's390x', 's390' ],

'aarch64' => ['aarch64'],
);

sub schema{
CORE::state $schema;
$schema = OpenQA::Schema::connect_db() unless $schema;
Expand Down Expand Up @@ -187,7 +171,7 @@ sub job_create {
}
}

my %new_job_args = (test => $settings{TEST},);
my %new_job_args = (test => $settings{TEST});

if ($settings{NAME}) {
my $njobs = schema->resultset("Jobs")->search({ slug => $settings{NAME} })->count;
Expand Down Expand Up @@ -220,7 +204,9 @@ sub job_create {
}

while(my ($k, $v) = each %settings) {
push @{$new_job_args{settings}}, { key => $k, value => $v };
for my $l (split(m/,/, $v)) { # special case for worker class?
push @{$new_job_args{settings}}, { key => $k, value => $l } if $l;
}
}

for my $a (@assets) {
Expand Down Expand Up @@ -487,42 +473,53 @@ sub job_grab {
);

my $worker = schema->resultset("Workers")->find($workerid);
my $archquery = schema->resultset("JobSettings")->search(

my @available_cond = ( # ids available for this worker
'-and',
{
key => "ARCH",
value => $cando{$worker->get_property('CPU_ARCH')}
}
-not_in => $blocked->get_column('child_job_id')->as_query
},
);

# list of jobs for different worker class
my $classquery = schema->resultset("JobSettings")->search(

my $preferred_parallel = _prefer_parallel(\@available_cond);
push @available_cond, $preferred_parallel if $preferred_parallel;

# check the worker's classes
my %classes = map { $_ => 1 } split /,/, ($worker->get_property('WORKER_CLASS') || '');

This comment has been minimized.

Copy link
@nadvornik

nadvornik Mar 27, 2015

Contributor

I think that classes must be part of @available_cond before calling _prefer_parallel. Now, for example, it would block all s390 jobs during start of parallel group on x86_64.

This comment has been minimized.

Copy link
@coolo

coolo Mar 27, 2015

Author Contributor

then I move the available_cond to the 3rd query

# now get all the ids of possible jobs
# it's a bit stupid to do this manual filtering, but I couldn't find a way
# to do this in the database
my %ids = map { $_->id => 1 } schema->resultset("Jobs")->search(
{
key => "WORKER_CLASS",
value => { '!=', $worker->get_property('WORKER_CLASS')},
'state' => OpenQA::Schema::Result::Jobs::SCHEDULED,
'worker_id' => 0,
id => \@available_cond,
},
{ columns => [qw/id/] }
);

my $available_cond = [ # ids available for this worker
'-and',
{
-not_in => $blocked->get_column('child_job_id')->as_query
},
# and remove those with conflicting classes
my $result = schema->resultset("JobSettings")->search(
{
-in => $archquery->get_column('job_id')->as_query
job_id => { -in => [ keys %ids ] },
key => 'WORKER_CLASS'
},
{
-not_in => $classquery->get_column('job_id')->as_query
},
];
{ columns => [qw/id value job_id/] }
);

my $preferred_parallel = _prefer_parallel($available_cond);
push @$available_cond, $preferred_parallel if $preferred_parallel;
while (my $setting = $result->next) {
if (!defined $classes{$setting->value}) {
delete $ids{$setting->job_id};
}
}

$result = schema->resultset("Jobs")->search(
# now query for the best
my $job = schema->resultset("Jobs")->search(
{
state => OpenQA::Schema::Result::Jobs::SCHEDULED,
worker_id => 0,
id => $available_cond,
id => { -in => [ keys %ids ] }
},
{ order_by => { -asc => [qw/priority id/] }, rows => 1 }
)->update(
Expand Down
2 changes: 1 addition & 1 deletion lib/OpenQA/Worker/Common.pm
Expand Up @@ -335,7 +335,7 @@ sub register_worker {
$worker_caps = _get_capabilities;
$worker_caps->{host} = $hostname;
$worker_caps->{instance} = $instance;
$worker_caps->{worker_class} = $worker_settings->{WORKER_CLASS} if $worker_settings->{WORKER_CLASS};
$worker_caps->{worker_class} = $worker_settings->{WORKER_CLASS} || "qemu_" . $worker_caps->{cpu_arch};

print "registering worker ...\n" if $verbose;

Expand Down
10 changes: 7 additions & 3 deletions t/04-scheduler.t
Expand Up @@ -58,14 +58,18 @@ $workercaps->{cpu_arch} = 'x86_64';
$workercaps->{cpu_opmode} = '32-bit, 64-bit';
$workercaps->{mem_max} = '4096';

my $id = worker_register("host", "1", $workercaps);
use OpenQA::Controller::API::V1::Worker;
my $c = OpenQA::Controller::API::V1::Worker->new;

# this really should be an integration test
my $id = $c->_register($schema, "host", "1", $workercaps);
ok($id == 1, "New worker registered");
my $worker = $schema->resultset("Workers")->find($id)->info();
ok($worker->{id} == $id&& $worker->{host} eq "host"&& $worker->{instance} eq "1", "New worker_get");

# Update worker
sleep(1);
my $id2 = worker_register("host", "1", "backend", $workercaps);
my $id2 = $c->_register($schema, "host", "1", "backend", $workercaps);
ok($id == $id2, "Known worker_register");
my $worker2 = $schema->resultset("Workers")->find($id2)->info();
ok($worker2->{id} == $id2 && $worker2->{host} eq "host"&& $worker2->{instance} == 1, "Known worker_get");
Expand Down Expand Up @@ -245,7 +249,7 @@ $grabed = OpenQA::Scheduler::job_get($job->id);
ok($grabed->{state} eq "running", "Job is in running state"); # After job_grab the job is in running state.

# register worker again while it has a running job
$id2 = worker_register("host", "1", "backend", $workercaps);
$id2 = $c->_register($schema, "host", "1", "backend", $workercaps);
ok($id == $id2, "re-register worker got same id");

# Now it's previous job must be set to done
Expand Down
33 changes: 21 additions & 12 deletions t/05-scheduler-capabilities.t
Expand Up @@ -27,7 +27,7 @@ use OpenQA::Test::Database;
use Test::Mojo;
use Test::More tests => 6;

OpenQA::Test::Database->new->create();
my $schema = OpenQA::Test::Database->new->create; #(skip_fixtures => 1);

#my $t = Test::Mojo->new('OpenQA');

Expand Down Expand Up @@ -55,18 +55,20 @@ my %settings = (
my %workercaps64;
$workercaps64{cpu_modelname} = 'Rainbow CPU';
$workercaps64{cpu_arch} = 'x86_64';
$workercaps64{worker_class} = 'qemu_x86_64,qemu_i686';
$workercaps64{cpu_opmode} = '32-bit, 64-bit';
$workercaps64{mem_max} = '4096';

my %workercaps64_server = %workercaps64;
$workercaps64_server{worker_class} = 'server';
$workercaps64_server{worker_class} = 'server,qemu_x86_64';

my %workercaps64_client = %workercaps64;
$workercaps64_client{worker_class} = 'client';
$workercaps64_client{worker_class} = 'client,qemu_x86_64';

my %workercaps32;
$workercaps32{cpu_modelname} = 'Rainbow CPU';
$workercaps32{cpu_arch} = 'i686';
$workercaps32{worker_class} = 'qemu_i686';
$workercaps32{cpu_opmode} = '32-bit';
$workercaps32{mem_max} = '4096';

Expand All @@ -80,23 +82,27 @@ my %settingsF = %settings;
my %settingsG = %settings;

$settingsA{TEST} = 'A';
$settingsA{WORKER_CLASS} = 'client';
$settingsA{WORKER_CLASS} = 'client,qemu_x86_64';

$settingsB{TEST} = 'B';
$settingsB{WORKER_CLASS} = 'server';
$settingsB{WORKER_CLASS} = 'server,qemu_x86_64';

$settingsC{TEST} = 'C';
$settingsC{ARCH} = 'i686';
$settingsC{WORKER_CLASS} = 'qemu_i686';

# no class for D
$settingsD{TEST} = 'D';

$settingsE{TEST} = 'E';
$settingsE{ARCH} = 'i686';
$settingsE{WORKER_CLASS} = 'qemu_i686';

$settingsF{TEST} = 'F';
$settingsF{WORKER_CLASS} = 'qemu_x86_64';

$settingsG{TEST} = 'G';
$settingsG{WORKER_CLASS} = 'special';
$settingsG{WORKER_CLASS} = 'special,qemu_x86_64';


my $jobA = OpenQA::Scheduler::job_create(\%settingsA);
Expand All @@ -115,12 +121,15 @@ $jobE->set_prio(5);
$jobF->set_prio(4);
$jobG->set_prio(1);

my $w1_id = worker_register("host", "1", \%workercaps64_client);
my $w2_id = worker_register("host", "2", \%workercaps64_server);
my $w3_id = worker_register("host", "3", \%workercaps32);
my $w4_id = worker_register("host", "4", \%workercaps64);
my $w5_id = worker_register("host", "5", \%workercaps64_client);
my $w6_id = worker_register("host", "6", \%workercaps64);
use OpenQA::Controller::API::V1::Worker;
my $c = OpenQA::Controller::API::V1::Worker->new;

my $w1_id = $c->_register($schema, "host", "1", \%workercaps64_client);
my $w2_id = $c->_register($schema, "host", "2", \%workercaps64_server);
my $w3_id = $c->_register($schema, "host", "3", \%workercaps32);
my $w4_id = $c->_register($schema, "host", "4", \%workercaps64);
my $w5_id = $c->_register($schema, "host", "5", \%workercaps64_client);
my $w6_id = $c->_register($schema, "host", "6", \%workercaps64);

my $job = OpenQA::Scheduler::job_grab(workerid => $w1_id);
is($job->{id}, $jobA->id, "'client' worker should get 'client' job even though 'server' job has higher prio");
Expand Down
15 changes: 9 additions & 6 deletions t/05-scheduler-dependencies.t
Expand Up @@ -112,12 +112,15 @@ $jobF->set_prio(1);
#diag "jobE ", $jobE;
#diag "jobF ", $jobF;

my $w1_id = worker_register("host", "1", $workercaps);
my $w2_id = worker_register("host", "2", $workercaps);
my $w3_id = worker_register("host", "3", $workercaps);
my $w4_id = worker_register("host", "4", $workercaps);
my $w5_id = worker_register("host", "5", $workercaps);
my $w6_id = worker_register("host", "6", $workercaps);
use OpenQA::Controller::API::V1::Worker;
my $c = OpenQA::Controller::API::V1::Worker->new;

my $w1_id = $c->_register($schema, "host", "1", $workercaps);
my $w2_id = $c->_register($schema, "host", "2", $workercaps);
my $w3_id = $c->_register($schema, "host", "3", $workercaps);
my $w4_id = $c->_register($schema, "host", "4", $workercaps);
my $w5_id = $c->_register($schema, "host", "5", $workercaps);
my $w6_id = $c->_register($schema, "host", "6", $workercaps);

#websocket
#my $ws1 = $t->websocket_ok("/api/v1/workers/$w1_id/ws");
Expand Down

0 comments on commit 8caa395

Please sign in to comment.