Hello community, here is the log from the commit of package openQA for openSUSE:Factory checked in at 2018-03-07 10:39:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Wed Mar 7 10:39:20 2018 rev:14 rq:583662 version:4.5.1520100590.2279151e Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2018-03-04 12:52:20.776154368 +0100 +++ /work/SRC/openSUSE:Factory/.openQA.new/openQA.changes 2018-03-07 10:39:35.027860334 +0100 @@ -1,0 +2,12 @@ +Tue Mar 06 17:29:01 UTC 2018 - [email protected] + +- Update to version 4.5.1520100590.2279151e: + * Fix sort order of the review comments (#1593) + * Expand the serial terminal console documentation (#1586) + * Emit openqa_job_create events when an ISO is posted (#1584) + * Replace die for 500 code and move global constants to OpenQA::Constants + * Avoid circular dependencies when running the tests. + * All the available free workers need to have the same websocket interface version + * Move the interface verification to the worker ack + +------------------------------------------------------------------- Old: ---- openQA-4.5.1519929327.f726adcc.tar.xz New: ---- openQA-4.5.1520100590.2279151e.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.bZvMSP/_old 2018-03-07 10:39:35.711835662 +0100 +++ /var/tmp/diff_new_pack.bZvMSP/_new 2018-03-07 10:39:35.715835518 +0100 @@ -36,7 +36,7 @@ # runtime requirements that also the testsuite needs %define t_requires perl(DBD::Pg) perl(DBIx::Class) perl(Config::IniFiles) perl(SQL::Translator) perl(Date::Format) perl(File::Copy::Recursive) perl(DateTime::Format::Pg) perl(Net::OpenID::Consumer) perl(Mojolicious::Plugin::RenderFile) perl(Mojolicious::Plugin::AssetPack) perl(aliased) perl(Config::Tiny) perl(DBIx::Class::DynamicDefault) perl(DBIx::Class::Schema::Config) perl(DBIx::Class::Storage::Statistics) perl(IO::Socket::SSL) perl(Data::Dump) perl(DBIx::Class::OptimisticLocking) perl(Text::Markdown) perl(Net::DBus) perl(IPC::Run) perl(Archive::Extract) perl(CSS::Minifier::XS) perl(JavaScript::Minifier::XS) perl(Time::ParseDate) perl(Sort::Versions) perl(Mojo::RabbitMQ::Client) perl(BSD::Resource) perl(Cpanel::JSON::XS) perl(Pod::POM) perl(Mojo::IOLoop::ReadWriteProcess) Name: openQA -Version: 4.5.1519929327.f726adcc +Version: 4.5.1520100590.2279151e Release: 0 Summary: The openQA web-frontend, scheduler and tools License: GPL-2.0+ ++++++ openQA-4.5.1519929327.f726adcc.tar.xz -> openQA-4.5.1520100590.2279151e.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/cpanfile new/openQA-4.5.1520100590.2279151e/cpanfile --- old/openQA-4.5.1519929327.f726adcc/cpanfile 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/cpanfile 2018-03-03 19:09:50.000000000 +0100 @@ -1,4 +1,4 @@ -requires 'Archive::Extract'; +requires 'Archive::Extract', '> 0.7'; requires 'BSD::Resource'; requires 'CSS::Minifier::XS', '>= 0.01'; requires 'Carp'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/docs/WritingTests.asciidoc new/openQA-4.5.1520100590.2279151e/docs/WritingTests.asciidoc --- old/openQA-4.5.1519929327.f726adcc/docs/WritingTests.asciidoc 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/docs/WritingTests.asciidoc 2018-03-03 19:09:50.000000000 +0100 @@ -680,8 +680,22 @@ Typically the OS you are testing will boot into a graphical shell e.g. The Gnome desktop environment. This is fine if you wish to test a program with a -GUI, but lets say you want to run some shell scripts then it is not so -convenient. +GUI, but in many situations you will need to enter commands into a textual +shell (e.g Bash), TTY, text terminal, command prompt, TUI etc. + +OpenQA has two basic methods for interacting with a text shell. The first uses +the same input and output methods as when interacting with a GUI, plus a +serial port for getting raw text output from the SUT. This is primarily +implemented with VNC and so I will referrer to it as the VNC text console. + +The second method uses a single serial port for both input and output. The SUT +attaches a TTY to the serial port and all communication is text based. This is +called the serial terminal console (or the virtio console, see implementation +section for details). + +The VNC text console is very slow and expensive relative to the serial +terminal console, but allows you to continue using +assert_screen+ and is more +widely supported. Below is an example of how to use the VNC text console. [caption="Switching to text mode: "] .To access a text based console or TTY, you can do something like the @@ -703,13 +717,15 @@ 1; -------------------------------------------------------------------------------- -This will select a text TTY and login as the root user (you could use -+become_root+ instead in this case). Had +select_console 'root-console'+ been -used before then it would just select the TTY. Now that we are on a text -console it is possible to run scripts and observe their output. Note that -+root-console+ is defined by the distribution, but also that calls to -+select_console+ can have far reaching consequences depending on what console -is being selected and what backend/architecture the SUT is using. +This will select a text TTY and login as the root user (if necessary). Now +that we are on a text console it is possible to run scripts and observe their +output either as raw text or on the video feed. + +Note that +root-console+ is defined by the distribution, so on different +distributions or operating systems this can vary. There are also many utility +functions that wrap +select_console+, so check your distributions utility +library before using it directly. + ==== [caption="Running a script: "] @@ -727,17 +743,20 @@ } -------------------------------------------------------------------------------- -Note that it is usually not necessary to return text from the SUT to the test -module for processing and it is often faster to do the processing in a shell -script on the SUT. However you may find it more convenient, readable or -reliable to do it in the Perl test module. +This returns the contents of the SUT's /proc/cpuinfo file to the test script +and then searches it for the term 'avx2' using a regex. + ==== -The +script_run+ and +script_output+ commands are high level commands which -use +type_string+ and +wait_serial+ underneath. Sometimes you may wish to use +The +script_run+ and +script_output+ are high level commands which use ++type_string+ and +wait_serial+ underneath. Sometimes you may wish to use lower level commands which give you more control, but be warned that it may also make your code less portable. +The command +wait_serial+ watches the SUT's serial port for text output and +matches it against a regex. +type_string+ sends a string to the SUT like it +was typed in by the user over VNC. + ==== Using a serial terminal IMPORTANT: You need a QEMU version >= 2.6.1 and to set the @@ -752,17 +771,197 @@ text commands it is much faster to use a serial port for both sending and receiving TTY commands. +Communicating entirely using text also means that you no longer have to worry +about your needles being invalidated due to a font change or similar. It is +also much cheaper to transfer text and test it against regular expressions +than encode images from a VNC feed and test them against sample images +(needles). + +On the other hand you can no longer use +assert_screen+ or take a screen shot +because the text is never rendered as an image. A lot of programs will also +send ANSI escape sequences which will appear as raw text to the test script +instead of being interpreted by a terminal emulator which then renders the +text. + [source,perl] -------------------------------------------------------------------------------- select_console('root-virtio-terminal'); # Selects a virtio based serial terminal -------------------------------------------------------------------------------- Changing input and output to a serial terminal has the side effect of changing -where +wait_serial+ reads output from. This will cause some distribution -specific utility functions to fail, however they can usually be fixed with the -+is_serial_terminal+ API function. To find out more look at the -+is_serial_terminal+ POD in +testapi.pm+. - -Another consequence of moving to a serial terminal is that none of the needle -based commands will be available because there is no screen image to match -against. +where +wait_serial+ reads output from. On a QEMU VM +wait_serial+ usually +reads from an emulated serial port which is also where the kernel log is +usually output to. + +When switching to a virtio based serial terminal, +wait_serial+ will then read +from the virtio serial port instead. However the emulated serial port still +exists and can receive output. Some utility library functions are hard coded +to redirect output to the emulated serial port and expect that +wait_serial+ +will be able to read it. Usually it is not too difficult to fix the utility +function, you just need to remove some redirection in the shell command. + +Another common problem is that some library or utility function tries to take +a screen shot. The hard part is finding what takes the screen shot, but then +it is just a simple case of checking +is_serial_terminal+ and not taking the +screen shot if we are on a serial terminal. + +Distributions usually wrap +select_console+, so instead of using it directly, +you can use something like the following which is from the OpenSUSE test +suite. + +[source,perl] +-------------------------------------------------------------------------------- +if (select_virtio_console()) { + # Do something which only works, or is necessary, on a serial terminal +} +-------------------------------------------------------------------------------- + +This selects the virtio based serial terminal if possible. If it is available +then it returns true. It is also possible to check if the current console is a +serial terminal by calling +is_serial_terminal+. + +Once you have selected a serial terminal, the video feed will disappear from +the live view, however at the bottom of the live screen there is a separate +text feed. After the test has finished you can view the serial log(s) in the +assets tab. You will probably have two serial logs; +serial0.txt+ and ++serial_terminal.txt+. + +Now that you are on a serial terminal everything will start to go a lot +faster. So much faster in fact that race conditions become a big +issue. Generally these can be avoided by using the higher level functions such +as +script_run+ and +script_output+. + +It is rarely necessary to use the lower level functions, however it helps to +recognise problems caused by race conditions at the lower level, so please +read the following section regardless. + +So if you do need to use +type_string+ and +wait_serial+ directly then try to +use the following pattern: + +1) Wait for the terminal prompt to appear. +2) Send your command +3) Wait for your command text to be echoed by the shell (if applicable) +4) Send enter +5) Wait for your command output (if applicable) + +To illustrate this is a snippet from the LTP test runner which uses the lower +level commands to achieve a little bit more control. I have numbered the lines +which correspond to the steps above. + +[source,perl] +-------------------------------------------------------------------------------- +my $fin_msg = "### TEST $test->{name} COMPLETE >>> "; +my $cmd_text = qq($test->{command}; echo "$fin_msg\$?"); +my $klog_stamp = "echo 'OpenQA::run_ltp.pm: Starting $test->{name}' > /dev/$serialdev"; + +# More variables and other stuff + +if (is_serial_terminal) { + script_run($klog_stamp); + wait_serial(serial_term_prompt(), undef, 0, no_regex => 1); #Step 1 + type_string($cmd_text); #Step 2 + wait_serial($cmd_text, undef, 0, no_regex => 1); #Step 3 + type_string("\n"); #Step 4 +} else { + # The slow path +} +my $test_log = wait_serial(qr/$fin_msg\d+/, $timeout, 0, record_output => 1); #Step 5 +-------------------------------------------------------------------------------- + +The first +wait_serial+ (Step 1) ensures that the shell prompt has +appeared. If we do not wait for the shell prompt then it is possible that we +can send input to whatever command was run before. In this case that command +would be 'echo' which is used by +script_run+ to print a 'finished' message. + +It is possible that echo was able to print the finish message, but was then +suspended by the OS before it could exit. In which case the test script is able +to race ahead and start sending input which will just be dropped by echo once +it is resumed. Waiting for the shell prompt stops this from happening. + +The function +serial_term_prompt+ is a distribution specific function which +returns the characters previously set as the shell prompt (e.g. export PS1="# +", see the bash(1) or dash(1) man pages). If you are adapting a new +distribution to use the serial terminal console, then we recommend setting a +simple shell prompt and keeping track of it with utility functions. + +The +no_regex+ argument tells wait_serial to use simple string matching +instead of regular expressions, see the implementation section for more +details. The other arguments are the timeout (+undef+ means we use the +default) and a boolean which inverts the result of +wait_serial+. These are +explained in the +os-autoinst/testapi.pm+ documentation. + +Then the test script enters our command with +type_string+ (Step 2) and waits +for the command's text to be echoed back by the system under test. Terminals +usually echo back the characters sent to them so that the user can see what +they have typed. + +However this can be disabled (see the stty(1) man page) or possibly even +unimplemented on your terminal. So this step may not be applicable, but it +provides some error checking so you should think carefully before disabling +echo deliberately. + +We then consume the echo text (Step 3) before sending enter, to both check +that the correct text was received and also to separate it from the command +output. It also ensures that the text has been fully processed before sending +the newline character which will cause the shell to change state. + +It is worth reminding oneself that we are sending and receiving data +extremely quickly on an interface usually limited by human typing speed. So +any string which results in a significant state change should be treated as a +potential source of race conditions. + +Finally we send the newline character and wait for our custom finish +message. +record_output+ is set to ensure all the output from the SUT is +saved (see the next section for more info). + +What we do *not* do at this point, is wait for the shell prompt to appear. +That would consume the prompt character breaking the next call to ++script_run+. + +We choose to wait for the prompt just before sending a command, rather than +after it, so that Step 5 can be deferred to a later time. In theory this +allows the test script to perform some other work while the SUT is busy. + +==== The virtio serial terminal implementation + +The os-autoinst package supports several types of 'consoles' of which the +virtio serial terminal is one. The majority of code for this console is +located in consoles/virtio_terminal.pm and consoles/virtio_screen.pm. However +there is also related code in backends/qemu.pm and distribution.pm. + +You may find it useful to read the documentation in virtio_terminal.pm and +virtio_screen.pm if you need to perform some special action on a terminal such +as triggering a signal or simulating the SysRq key. There are also some +console specific arguments to +wait_serial+ and +type_string+ such as ++record_output+. + +The virtio 'screen' essentially reads data from a socket created by QEMU into +a ring buffer and scans it after every read with a regular expression. The +ring buffer is large enough to hold anything you are likely to want to match +against, but not too large as to cause performance issues. Usually the +contents of this ring buffer, up to the end of the match, are returned by ++wait_serial+. This means earlier output will be overwritten once the ring +buffer's length is exceeded. However you can pass +record_output+ which saves +the output to a separate unlimited buffer and returns that instead. + +Like +record_output+, the +no_regex+ argument is a console specific argument +supported by the serial terminal console. It may or may not have some +performance benefits, but more importantly it allows you to easily match +arbitrary strings which may contain regex escape sequences. To be clear, ++no_regex+ hints that +wait_serial+ should just treat its input as a plain +string and use the Perl library function +index+ to search for a match in the +ring buffer. + +Very little of the code (perhaps none) is specific to a virtio based serial +terminal and can be reused with a physical serial port, SSH socket, IPMI or +some other text based interface. It is called the virtio console because the +current implementation just uses a virtio serial device in QEMU (and it could +easily be converted to an emulated port), but it otherwise has nothing to do +with the virtio standard and so you should avoid using the name 'virtio +console' unless specifically referring to the QEMU virtio implementation. + +As mentioned previously, ANSI escape sequences can be a pain. So we try to +avoid them by informing the shell that it is running on a 'dumb' terminal (see +the SUSE distribution's serial terminal utility library). However some +programs ignore this, but piping there output into +tee+ is usually enough to +stop them outputting non-printable characters. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Constants.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Constants.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Constants.pm 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Constants.pm 2018-03-03 19:09:50.000000000 +0100 @@ -0,0 +1,32 @@ +package OpenQA::Constants; +use strict; + +# Minimal worker version that allows them to connect; +# To be modified manuallly when we want to break compability and force workers to update +# If this value differs from server to worker then it won't be able to connect. +use constant WEBSOCKET_API_VERSION => 1; + +# Time threshold used to check active workers +use constant WORKERS_CHECKER_THRESHOLD => 120; + +# Time verification to be use with WORKERS_CHECKER_THRESHOLD. +# It shouldn't be bigger than WORKERS_CHECKER_THRESHOLD +use constant MAX_TIMER => 100; + +# Time verification to be use with WORKERS_CHECKER_THRESHOLD. +use constant MIN_TIMER => 20; + +require Exporter; +our (@ISA, @EXPORT, @EXPORT_OK); + +@ISA = qw(Exporter); +@EXPORT = (); +@EXPORT_OK = qw( + WEBSOCKET_API_VERSION + WORKERS_CHECKER_THRESHOLD + MAX_TIMER + MIN_TIMER +); + + +1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Scheduler/Scheduler.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Scheduler/Scheduler.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Scheduler/Scheduler.pm 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Scheduler/Scheduler.pm 2018-03-03 19:09:50.000000000 +0100 @@ -46,8 +46,7 @@ use OpenQA::IPC; use sigtrap handler => \&normal_signals_handler, 'normal-signals'; use OpenQA::Scheduler; - - +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use Carp; require Exporter; @@ -225,7 +224,8 @@ # NOTE: $worker->connected is too much expensive since is over dbus, prefer dead. # shuffle avoids starvation if a free worker keeps failing. my @free_workers - = shuffle(grep { !$_->dead } schema->resultset("Workers")->search({job_id => undef})->all()); + = shuffle(grep { !$_->dead && $_->get_websocket_api_version() == WEBSOCKET_API_VERSION } + schema->resultset("Workers")->search({job_id => undef})->all()); log_debug("\t Free workers: " . scalar(@free_workers) . "/$all_workers"); log_debug("\t Failure# ${failure}") if OpenQA::Scheduler::CONGESTION_CONTROL(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Schema/Result/Workers.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Schema/Result/Workers.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Schema/Result/Workers.pm 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Schema/Result/Workers.pm 2018-03-03 19:09:50.000000000 +0100 @@ -24,8 +24,7 @@ use OpenQA::Utils 'log_error'; use OpenQA::IPC; use db_helpers; - -use constant WORKERS_CHECKER_THRESHOLD => 120; +use OpenQA::Constants 'WORKERS_CHECKER_THRESHOLD'; use constant COMMANDS => qw(quit abort scheduler_abort cancel obsolete enable_interactive_mode disable_interactive_mode stop_waitforneedle reload_needles_and_retry continue_waitforneedle @@ -133,6 +132,17 @@ $self->t_updated < $dt; } +sub get_websocket_api_version { + my ($self) = @_; + + # Cache this value. To avoid keeping querying the DB. + unless ($self->{_websocket_api_version_}) { + $self->{_websocket_api_version_} = $self->get_property('WEBSOCKET_API_VERSION'); + } + + return $self->{_websocket_api_version_}; +} + sub currentstep { my ($self) = @_; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm 2018-03-03 19:09:50.000000000 +0100 @@ -533,6 +533,9 @@ }); $self->emit_event('openqa_iso_create', $args); + for my $succjob (@successful_job_ids) { + $self->emit_event('openqa_job_create', {id => $succjob}); + } return { successful_job_ids => \@successful_job_ids, failed_job_info => \@failed_job_info, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm 2018-03-03 19:09:50.000000000 +0100 @@ -22,7 +22,7 @@ use DBIx::Class::Timestamps 'now'; use Try::Tiny; use Scalar::Util 'looks_like_number'; - +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; =pod =head1 NAME @@ -83,6 +83,9 @@ sub _register { my ($self, $schema, $host, $instance, $caps) = @_; + die "Incompatible websocket api" + if WEBSOCKET_API_VERSION != ($caps->{websocket_api_version} // 0); + my $worker = $schema->resultset("Workers")->search( { host => $host, @@ -102,7 +105,6 @@ } # store worker's capabilities to database $worker->update_caps($caps) if $caps; - # in case the worker died ... # ... restart job assigned to this worker if (my $job = $worker->job) { @@ -121,6 +123,7 @@ $worker->set_property('INTERACTIVE', 0); $worker->set_property('STOP_WAITFORNEEDLE', 0); $worker->set_property('STOP_WAITFORNEEDLE_REQUESTED', 0); + # $worker->seen(); die "got invalid id" unless $worker->id; return $worker->id; @@ -137,8 +140,7 @@ =cut sub create { - my ($self) = @_; - + my ($self) = @_; my $validation = $self->validation; my @mandatory_params = qw(host instance cpu_arch mem_max worker_class); for my $k (@mandatory_params) { @@ -158,16 +160,32 @@ 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'); + $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'); + $caps->{websocket_api_version} = $self->param('websocket_api_version'); + $caps->{isotovideo_interface_version} = $self->param('isotovideo_interface_version'); + + my $id; + try { + $id = $self->_register($self->db, $host, $instance, $caps); + } + catch { + if (/Incompatible/) { + $self->render(status => 426, json => {error => $_}); + + } + else { + $self->render(status => 500, json => {error => "Failed: $_"}); + } + + return; + }; - my $id = $self->_register($self->db, $host, $instance, $caps); $self->emit_event('openqa_worker_register', {id => $id, host => $host, instance => $instance, caps => $caps}); $self->render(json => {id => $id}); - } =over 4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebAPI/Plugin/Fedmsg.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebAPI/Plugin/Fedmsg.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebAPI/Plugin/Fedmsg.pm 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebAPI/Plugin/Fedmsg.pm 2018-03-03 19:09:50.000000000 +0100 @@ -13,6 +13,11 @@ # You should have received a copy of the GNU General Public License along # with this program; if not, see <http://www.gnu.org/licenses/>. +# An openQA plugin that emits fedmsgs for certain openQA events (by shadowing +# fedmsg internal events). See http://www.fedmsg.com for more on fedmsg. +# Currently quite specific to Fedora usage. Requires daemonize and +# fedmsg-logger. + package OpenQA::WebAPI::Plugin::Fedmsg; use strict; @@ -56,10 +61,12 @@ # do you want to write perl bindings for fedmsg? no? me either. # FIXME: should be some way for plugins to have configuration and then # cert-prefix could be configurable, for now we hard code it - # we use IPC::Run rather than system() as it's easier to mock for testing + # we use IPC::Run rather than system() as it's easier to mock for testing, + # and we daemonize so we don't block until the message is sent (which can + # cause problems when sending hundreds of messages on ISO post) my @command = ( - "fedmsg-logger", "--cert-prefix=openqa", "--modname=openqa", "--topic=$event", - "--json-input", "--message=$event_data" + "/usr/sbin/daemonize", "/usr/bin/fedmsg-logger", "--cert-prefix=openqa", "--modname=openqa", + "--topic=$event", "--json-input", "--message=$event_data" ); my ($stdin, $stderr, $output) = (undef, undef, undef); IPC::Run::run(\@command, \$stdin, \$output, \$stderr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebSockets/Server.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebSockets/Server.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/WebSockets/Server.pm 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/WebSockets/Server.pm 2018-03-03 19:09:50.000000000 +0100 @@ -27,6 +27,7 @@ use Data::Dump 'pp'; use db_profiler; use OpenQA::Schema::Result::Workers (); +use OpenQA::Constants qw(WEBSOCKET_API_VERSION WORKERS_CHECKER_THRESHOLD); require Exporter; our (@ISA, @EXPORT, @EXPORT_OK); @@ -41,12 +42,6 @@ # Will be filled out from worker status messages my $worker_status; -# Minimal worker version that allows them to connect; -# To be modified manuallly when we want to break compability and force workers to update -# If this value differs from server to worker and is lower for the worker than for the server -# Then it won't be able to connect. -use constant INTERFACE_VERSION => 1; - # internal helpers prototypes sub _message; sub _get_worker; @@ -193,7 +188,7 @@ # jobs assigned from scheduler (which will check DB and not WS state) my $dt = DateTime->now(time_zone => 'UTC'); # 2 minutes is long enough for the scheduler not to take it - $dt->subtract(seconds => (OpenQA::Schema::Result::Workers::WORKERS_CHECKER_THRESHOLD() + 20)); + $dt->subtract(seconds => (WORKERS_CHECKER_THRESHOLD + 20)); $worker->{db}->update({t_updated => $dt}); $worker->{socket} = undef; # remove the version as we don't know if the worker is updated while shutdown @@ -216,6 +211,15 @@ return; } + # This is to make sure that no worker can skip the _registration. + if (($worker->{db}->get_websocket_api_version() || 0) != WEBSOCKET_API_VERSION) { + log_warning("Received a message from an incompatible worker"); + $ws->tx->send({json => {type => 'incompatible'}}); + $ws->finish("1008", + "Connection terminated from WebSocket server - incompatible communication protocol version"); + return; + } + $worker->{last_seen} = time(); if ($json->{type} eq 'accepted') { my $jobid = $json->{jobid}; @@ -245,12 +249,10 @@ } } elsif ($json->{type} eq 'worker_status') { - my $current_worker_status = $json->{status}; - my $job_status = $json->{job}->{state}; - my $jobid = $json->{job}->{id}; - my $wid = $worker->{id}; - my $websocket_api_version = $json->{websocket_api_version} // 0; - my $isotovideo_interface_version = $json->{isotovideo_interface_version} // 0; + my $current_worker_status = $json->{status}; + my $job_status = $json->{job}->{state}; + my $jobid = $json->{job}->{id}; + my $wid = $worker->{id}; $worker_status->{$wid} = $json; log_debug(sprintf('Received from worker "%u" worker_status message "%s"', $wid, Dumper($json))); @@ -262,25 +264,12 @@ return unless $w; log_debug("Updated worker seen from worker_status"); $w->seen; - $w->set_property('WEBSOCKET_API_VERSION', $websocket_api_version); - $w->set_property('ISOTOVIDEO_INTERFACE_VERSION', $isotovideo_interface_version); }); } catch { log_error("Failed updating worker seen status: $_"); }; - if (INTERFACE_VERSION != $websocket_api_version) { - log_debug("Received a message from an incompatible worker"); - $ws->tx->send({json => {type => 'incompatible'}}); - # In case the worker haven't been updated to understand the "incompatible" type message, - # we need to force the shutdown - $ws->finish("1008", - "Connection terminated from WebSocket server - incompatible communication protocol version") - if $websocket_api_version == 0; - return; - } - my $registered_job_id; my $registered_job_token; try { @@ -419,7 +408,7 @@ try { $schema->txn_do( sub { - my $stale_jobs = _get_stale_worker_jobs(OpenQA::Schema::Result::Workers::WORKERS_CHECKER_THRESHOLD()); + my $stale_jobs = _get_stale_worker_jobs(WORKERS_CHECKER_THRESHOLD); for my $job ($stale_jobs->all) { next unless _is_job_considered_dead($job); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Worker/Common.pm new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Worker/Common.pm --- old/openQA-4.5.1519929327.f726adcc/lib/OpenQA/Worker/Common.pm 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/lib/OpenQA/Worker/Common.pm 2018-03-03 19:09:50.000000000 +0100 @@ -56,12 +56,12 @@ my ($sysname, $hostname, $release, $version, $machine) = POSIX::uname(); # global constants +use OpenQA::Constants qw(WEBSOCKET_API_VERSION MAX_TIMER MIN_TIMER); + +# local constants use constant { STATUS_UPDATES_SLOW => 10, STATUS_UPDATES_FAST => 0.5, - MAX_TIMER => 100, # It should never be more than OpenQA::WebSockets::Server::_workers_checker threshold - MIN_TIMER => 20, - INTERFACE_VERSION => 1, # Which version the worker follows. Minimal version that will connect to the openqa server }; # the template noted what architecture are known @@ -339,9 +339,7 @@ my $status_message = { json => { - type => 'worker_status', - websocket_api_version => INTERFACE_VERSION, - isotovideo_interface_version => $isotovideo_interface_version + type => 'worker_status' }}; @@ -458,9 +456,11 @@ die unless $host; $hosts->{$host}{accepting_jobs} = 0; - $worker_caps = _get_capabilities; - $worker_caps->{host} = $hostname; - $worker_caps->{instance} = $instance; + $worker_caps = _get_capabilities; + $worker_caps->{host} = $hostname; + $worker_caps->{instance} = $instance; + $worker_caps->{websocket_api_version} = WEBSOCKET_API_VERSION; + $worker_caps->{isotovideo_interface_version} = $isotovideo_interface_version; if ($worker_settings->{WORKER_CLASS}) { $worker_caps->{worker_class} = $worker_settings->{WORKER_CLASS}; } @@ -473,7 +473,7 @@ } log_info( -"registering worker $hostname version $isotovideo_interface_version with openQA $host using protocol version [@{[INTERFACE_VERSION]}]" +"registering worker $hostname version $isotovideo_interface_version with openQA $host using protocol version [@{[WEBSOCKET_API_VERSION]}]" ); if (!$hosts->{$host}) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/04-scheduler.t new/openQA-4.5.1520100590.2279151e/t/04-scheduler.t --- old/openQA-4.5.1519929327.f726adcc/t/04-scheduler.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/04-scheduler.t 2018-03-03 19:09:50.000000000 +0100 @@ -31,7 +31,7 @@ use OpenQA::ResourceAllocator; use OpenQA::Resource::Locks; use OpenQA::Resource::Jobs; - +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use OpenQA::Test::Database; use Net::DBus; use Net::DBus::Test::MockObject; @@ -88,10 +88,12 @@ # New worker my $workercaps = {}; -$workercaps->{cpu_modelname} = 'Rainbow CPU'; -$workercaps->{cpu_arch} = 'x86_64'; -$workercaps->{cpu_opmode} = '32-bit, 64-bit'; -$workercaps->{mem_max} = '4096'; +$workercaps->{cpu_modelname} = 'Rainbow CPU'; +$workercaps->{cpu_arch} = 'x86_64'; +$workercaps->{cpu_opmode} = '32-bit, 64-bit'; +$workercaps->{mem_max} = '4096'; +$workercaps->{websocket_api_version} = WEBSOCKET_API_VERSION; +$workercaps->{isotovideo_interface_version} = WEBSOCKET_API_VERSION; use OpenQA::WebAPI::Controller::API::V1::Worker; my $c = OpenQA::WebAPI::Controller::API::V1::Worker->new; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/05-scheduler-cancel.t new/openQA-4.5.1520100590.2279151e/t/05-scheduler-cancel.t --- old/openQA-4.5.1519929327.f726adcc/t/05-scheduler-cancel.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/05-scheduler-cancel.t 2018-03-03 19:09:50.000000000 +0100 @@ -29,9 +29,9 @@ use Data::Dump qw(pp dd); use OpenQA::Scheduler; use OpenQA::WebSockets; +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use OpenQA::Test::Database; use Net::DBus; - use Test::More; use Test::Warnings; @@ -183,10 +183,12 @@ # we need 3 workers for command issue test my $workercaps = {}; - $workercaps->{cpu_modelname} = 'Rainbow CPU'; - $workercaps->{cpu_arch} = 'x86_64'; - $workercaps->{cpu_opmode} = '32-bit, 64-bit'; - $workercaps->{mem_max} = '4096'; + $workercaps->{cpu_modelname} = 'Rainbow CPU'; + $workercaps->{cpu_arch} = 'x86_64'; + $workercaps->{cpu_opmode} = '32-bit, 64-bit'; + $workercaps->{mem_max} = '4096'; + $workercaps->{websocket_api_version} = WEBSOCKET_API_VERSION; + $workercaps->{isotovideo_interface_version} = WEBSOCKET_API_VERSION; use OpenQA::WebAPI::Controller::API::V1::Worker; my $c = OpenQA::WebAPI::Controller::API::V1::Worker->new; my $w1 = $schema->resultset('Workers')->find($c->_register($schema, "host", "1", $workercaps)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/05-scheduler-capabilities.t new/openQA-4.5.1520100590.2279151e/t/05-scheduler-capabilities.t --- old/openQA-4.5.1519929327.f726adcc/t/05-scheduler-capabilities.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/05-scheduler-capabilities.t 2018-03-03 19:09:50.000000000 +0100 @@ -29,6 +29,7 @@ use Data::Dump qw(pp dd); use OpenQA::Scheduler; use OpenQA::WebSockets; +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use OpenQA::Test::Database; use Test::Mojo; use Test::More; @@ -63,11 +64,13 @@ ); 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'; +$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'; +$workercaps64{websocket_api_version} = WEBSOCKET_API_VERSION; +$workercaps64{isotovideo_interface_version} = WEBSOCKET_API_VERSION; my %workercaps64_server = %workercaps64; $workercaps64_server{worker_class} = 'server,qemu_x86_64'; @@ -76,12 +79,13 @@ $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'; - +$workercaps32{cpu_modelname} = 'Rainbow CPU'; +$workercaps32{cpu_arch} = 'i686'; +$workercaps32{worker_class} = 'qemu_i686'; +$workercaps32{cpu_opmode} = '32-bit'; +$workercaps32{mem_max} = '4096'; +$workercaps32{websocket_api_version} = WEBSOCKET_API_VERSION; +$workercaps32{isotovideo_interface_version} = WEBSOCKET_API_VERSION; my %settingsA = %settings; my %settingsB = %settings; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/05-scheduler-dependencies.t new/openQA-4.5.1520100590.2279151e/t/05-scheduler-dependencies.t --- old/openQA-4.5.1519929327.f726adcc/t/05-scheduler-dependencies.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/05-scheduler-dependencies.t 2018-03-03 19:09:50.000000000 +0100 @@ -29,6 +29,7 @@ use Data::Dump qw(pp dd); use OpenQA::Scheduler::Scheduler; use OpenQA::WebSockets; +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use OpenQA::Test::Database; use Test::Mojo; use Test::More; @@ -75,10 +76,12 @@ NICTYPE => 'tap' ); my %workercaps = ( - cpu_modelname => 'Rainbow CPU', - cpu_arch => 'x86_64', - cpu_opmode => '32-bit, 64-bit', - mem_max => '4096' + cpu_modelname => 'Rainbow CPU', + cpu_arch => 'x86_64', + cpu_opmode => '32-bit, 64-bit', + mem_max => '4096', + isotovideo_interface_version => WEBSOCKET_API_VERSION, + websocket_api_version => WEBSOCKET_API_VERSION ); # parallel dependencies: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/13-joblocks.t new/openQA-4.5.1520100590.2279151e/t/13-joblocks.t --- old/openQA-4.5.1519929327.f726adcc/t/13-joblocks.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/13-joblocks.t 2018-03-03 19:09:50.000000000 +0100 @@ -28,7 +28,7 @@ use OpenQA::Utils; use OpenQA::Test::Database; use OpenQA::ResourceAllocator; - +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use Test::More; use Test::Mojo; use Test::Warnings; @@ -146,11 +146,13 @@ ok($job, "Job $test created with id " . $job->id); is($job->parents->single->parent_job_id, $parent, 'Job has correct parent') if $parent; my %worker = ( - cpu_modelname => 'Rainbow CPU', - cpu_arch => 'x86_64', - worker_class => 'qemu_x86_64,qemu_i686', - cpu_opmode => '32-bit, 64-bit', - mem_max => '4096' + cpu_modelname => 'Rainbow CPU', + cpu_arch => 'x86_64', + worker_class => 'qemu_x86_64,qemu_i686', + cpu_opmode => '32-bit, 64-bit', + mem_max => '4096', + websocket_api_version => WEBSOCKET_API_VERSION, + isotovideo_interface_version => WEBSOCKET_API_VERSION ); use OpenQA::WebAPI::Controller::API::V1::Worker; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/15-assets.t new/openQA-4.5.1520100590.2279151e/t/15-assets.t --- old/openQA-4.5.1519929327.f726adcc/t/15-assets.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/15-assets.t 2018-03-03 19:09:50.000000000 +0100 @@ -35,6 +35,7 @@ use OpenQA::Resource::Jobs 'job_restart'; use OpenQA::WebAPI::Controller::API::V1::Worker; use OpenQA::WebSockets; +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use OpenQA::Test::Database; use OpenQA::Utils; @@ -78,7 +79,19 @@ ## test asset is assigned after grab_job # register worker my $c = OpenQA::WebAPI::Controller::API::V1::Worker->new; -my $w = $c->_register($schema, 'host', '1', $workercaps); +my $w; +eval { $w = $c->_register($schema, 'host', '1', $workercaps); }; +like($@, qr/Incompatible websocket api/, 'Worker no version - incompatible version exception'); +$workercaps->{websocket_api_version} = 999999; +eval { $w = $c->_register($schema, 'host', '1', $workercaps); }; +like($@, qr/Incompatible websocket api/, 'Worker different version - incompatible version exception'); +$workercaps->{websocket_api_version} = WEBSOCKET_API_VERSION; +eval { $w = $c->_register($schema, 'host', '1', $workercaps); }; +ok(!$@, 'Worker correct version'); + +my $worker = $schema->resultset('Workers')->find($w); +is($worker->get_websocket_api_version(), WEBSOCKET_API_VERSION, 'Worker version set correctly'); + # grab job my $job = job_grab(workerid => $w, allocate => 1); is($job->{id}, $jobA->id, 'jobA grabbed'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/18-fedmsg.t new/openQA-4.5.1520100590.2279151e/t/18-fedmsg.t --- old/openQA-4.5.1519929327.f726adcc/t/18-fedmsg.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/18-fedmsg.t 2018-03-03 19:09:50.000000000 +0100 @@ -84,12 +84,14 @@ ARCH => 'x86_64' }; +my $commonexpr = '/usr/sbin/daemonize /usr/bin/fedmsg-logger --cert-prefix=openqa --modname=openqa'; # create a job via API my $post = $t->post_ok("/api/v1/jobs" => form => $settings)->status_is(200); my $job = $post->tx->res->json->{id}; is( $args, - 'fedmsg-logger --cert-prefix=openqa --modname=openqa --topic=job.create --json-input --message=' + $commonexpr + . ' --topic=job.create --json-input --message=' . '{"ARCH":"x86_64","BUILD":"666","DESKTOP":"DESKTOP","DISTRI":"Unicorn","FLAVOR":"pink","ISO":"whatever.iso",' . '"ISO_MAXSIZE":"1","KVM":"KVM","MACHINE":"RainbowPC","TEST":"rainbow","VERSION":"42","id":' . $job @@ -106,7 +108,8 @@ # check plugin called fedmsg-logger correctly is( $args, - 'fedmsg-logger --cert-prefix=openqa --modname=openqa --topic=job.done --json-input --message=' + $commonexpr + . ' --topic=job.done --json-input --message=' . '{"ARCH":"x86_64","BUILD":"666","FLAVOR":"pink","ISO":"whatever.iso","MACHINE":"RainbowPC",' . '"TEST":"rainbow","id":' . $job @@ -124,7 +127,8 @@ # check plugin called fedmsg-logger correctly is( $args, - 'fedmsg-logger --cert-prefix=openqa --modname=openqa --topic=job.duplicate --json-input --message=' + $commonexpr + . ' --topic=job.duplicate --json-input --message=' . '{"ARCH":"x86_64","BUILD":"666","FLAVOR":"pink","ISO":"whatever.iso","MACHINE":"RainbowPC",' . '"TEST":"rainbow","auto":0,"id":' . $job @@ -140,7 +144,8 @@ # check plugin called fedmsg-logger correctly is( $args, - 'fedmsg-logger --cert-prefix=openqa --modname=openqa --topic=job.cancel --json-input --message=' + $commonexpr + . ' --topic=job.cancel --json-input --message=' . '{"ARCH":"x86_64","BUILD":"666","FLAVOR":"pink","ISO":"whatever.iso","MACHINE":"RainbowPC",' . '"TEST":"rainbow","id":' . $newjob @@ -157,8 +162,7 @@ # stash the comment ID my $comment = $post->tx->res->json->{id}; # check plugin called fedmsg-logger correctly -my $commonexpr = 'fedmsg-logger --cert-prefix=openqa --modname=openqa'; -my $dateexpr = '\d{4}-\d{1,2}-\d{1,2}T\d{2}:\d{2}:\d{2}Z'; +my $dateexpr = '\d{4}-\d{1,2}-\d{1,2}T\d{2}:\d{2}:\d{2}Z'; like( $args, qr/$commonexpr --topic=comment.create --json-input --message=\{"created":"$dateexpr","group_id":null,"id":$comment,"job_id":$job,"text":"test comment","updated":"$dateexpr","user":"perci"\}/, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/20-workers-ws.t new/openQA-4.5.1520100590.2279151e/t/20-workers-ws.t --- old/openQA-4.5.1519929327.f726adcc/t/20-workers-ws.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/20-workers-ws.t 2018-03-03 19:09:50.000000000 +0100 @@ -117,8 +117,11 @@ my $buf; redirect_output(\$buf); + OpenQA::Worker::Commands::websocket_commands($ws, {type => 'unknown'}); + like($buf, qr/got unknown command/, 'Unknown command'); + $buf = ''; OpenQA::Worker::Commands::websocket_commands($ws, {type => 'incompatible'}); - like($buf, qr/The worker is running an incompatible version/, 'The worker is running an incompatible version'); + like($buf, qr/The worker is running an incompatible version/, 'incompatible version'); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/24-worker.t new/openQA-4.5.1520100590.2279151e/t/24-worker.t --- old/openQA-4.5.1519929327.f726adcc/t/24-worker.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/24-worker.t 2018-03-03 19:09:50.000000000 +0100 @@ -38,11 +38,7 @@ use OpenQA::Worker::Jobs; use OpenQA::WebSockets::Server; use OpenQA::Schema::Result::Workers (); - -ok( - OpenQA::Worker::Common::INTERFACE_VERSION == OpenQA::WebSockets::Server::INTERFACE_VERSION, -"Worker interface version [@{[OpenQA::Worker::Common::INTERFACE_VERSION]}] compatible with server version [@{[OpenQA::WebSockets::Server::INTERFACE_VERSION]}]" -); +use OpenQA::Constants qw(WORKERS_CHECKER_THRESHOLD MAX_TIMER MIN_TIMER); # api_init (must be called before making other calls anyways) like( @@ -334,10 +330,8 @@ $OpenQA::Worker::Common::worker_settings = {}; # Or we would see workers detected as dead - ok( - (OpenQA::Schema::Result::Workers::WORKERS_CHECKER_THRESHOLD - OpenQA::Worker::Common::MAX_TIMER) >= 20, -"OpenQA::WebSockets::Server::WORKERS_CHECKER_THRESHOLD is bigger than OpenQA::Worker::Common::MAX_TIMER at least by 20s" - ); + ok((WORKERS_CHECKER_THRESHOLD - MAX_TIMER) >= 20, + "WORKERS_CHECKER_THRESHOLD is bigger than MAX_TIMER at least by 20s"); my $instance = 1; my $pop = $instance; do { @@ -363,11 +357,7 @@ for $instance .. 300; $pop = 1; - ok in_range( - test_timer(int(rand_range(1, $pop)), ++$pop), - OpenQA::Worker::Common::MIN_TIMER, - OpenQA::Worker::Common::MAX_TIMER - ), + ok in_range(test_timer(int(rand_range(1, $pop)), ++$pop), MIN_TIMER, MAX_TIMER), "timer in range with worker population of $pop" for 1 .. 999; }; @@ -380,10 +370,8 @@ is($faketx->get(0)->{status}, "working"); is($faketx->get(0)->{job}->{state}, "scheduled"); - ok(exists $faketx->get(0)->{websocket_api_version}); - ok(exists $faketx->get(0)->{isotovideo_interface_version}); - is($faketx->get(0)->{websocket_api_version}, 1); - is($faketx->get(0)->{isotovideo_interface_version}, 0); + is($faketx->get(0)->{type}, "worker_status"); + is(keys %{$faketx->get(0)}, 3); $OpenQA::Worker::Common::job = {}; @@ -391,6 +379,8 @@ is($faketx->get(1)->{status}, "free"); ok(!exists $faketx->get(1)->{job}->{state}); + is($faketx->get(1)->{type}, "worker_status"); + is(keys %{$faketx->get(1)}, 3); $OpenQA::Worker::Common::job = undef; @@ -398,20 +388,22 @@ is($faketx->get(2)->{status}, "free"); ok(!exists $faketx->get(2)->{job}->{state}); + is($faketx->get(2)->{type}, "worker_status"); + is(keys %{$faketx->get(2)}, 3); $OpenQA::Worker::Common::job = {id => 9999, state => "running", settings => {NAME => "Foo"}}; OpenQA::Worker::Common::send_status($faketx); is($faketx->get(3)->{status}, "working"); is($faketx->get(3)->{job}->{state}, "running"); + is($faketx->get(3)->{type}, "worker_status"); + is(keys %{$faketx->get(3)}, 3); OpenQA::Worker::Jobs::_reset_state(); OpenQA::Worker::Common::send_status($faketx); is($faketx->get(4)->{status}, "free"); ok(!exists $faketx->get(4)->{job}->{state}); - ok(exists $faketx->get(4)->{websocket_api_version}); - ok(exists $faketx->get(4)->{isotovideo_interface_version}); - is($faketx->get(4)->{websocket_api_version}, 1); - is($faketx->get(4)->{isotovideo_interface_version}, 0); + is($faketx->get(4)->{type}, "worker_status"); + is(keys %{$faketx->get(4)}, 3); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/27-websockets.t new/openQA-4.5.1520100590.2279151e/t/27-websockets.t --- old/openQA-4.5.1519929327.f726adcc/t/27-websockets.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/27-websockets.t 2018-03-03 19:09:50.000000000 +0100 @@ -23,6 +23,7 @@ use FindBin; use lib ("$FindBin::Bin/lib", "../lib", "lib"); use OpenQA::WebSockets::Server; +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use OpenQA::Test::Utils 'redirect_output'; OpenQA::WebSockets::Server->new(); @@ -82,30 +83,33 @@ monkey_patch "Mojo::Transaction::Websocket", send => sub { undef }; $fake_tx->OpenQA::WebSockets::Server::_message({type => 'worker_status'}); - like $buf, qr/Received a message from an incompatible worker/ or diag explain $buf; - $fake_tx->OpenQA::WebSockets::Server::_message( - {type => 'worker_status', websocket_api_version => OpenQA::WebSockets::Server->INTERFACE_VERSION}); like $buf, qr/Could not be able to send population number to worker/ or diag explain $buf; - $fake_tx->OpenQA::WebSockets::Server::_message( - { - type => 'worker_status', - websocket_api_version => 999999, - isotovideo_interface_version => 9999 - }); - like $buf, qr/Received a message from an incompatible worker/ or diag explain $buf; monkey_patch "OpenQA::WebAPI", schema => sub { undef }; $fake_tx->OpenQA::WebSockets::Server::_message({type => 'worker_status'}); - like $buf, qr/Received a message from an incompatible worker/ or diag explain $buf; - $fake_tx->OpenQA::WebSockets::Server::_message( - { - type => 'worker_status', - websocket_api_version => OpenQA::WebSockets::Server->INTERFACE_VERSION, - isotovideo_interface_version => 9999 - }); like $buf, qr/Failed updating worker seen status/ or diag explain $buf; - $fake_tx->OpenQA::WebSockets::Server::_message({type => 'worker_status', websocket_api_version => 99999}); + + no warnings 'redefine'; + *FooBarWorker::get_websocket_api_version = sub { }; + $fake_tx->OpenQA::WebSockets::Server::_message({type => 'worker_status'}); like $buf, qr/Received a message from an incompatible worker/ or diag explain $buf; + is @{$fake_tx->{out}}[1], + "1008,Connection terminated from WebSocket server - incompatible communication protocol version"; + + $buf = undef; + *FooBarWorker::get_websocket_api_version = sub { 0 }; + $fake_tx->OpenQA::WebSockets::Server::_message({type => 'property_change'}); + like $buf, qr/Received a message from an incompatible worker/ or diag explain $buf; + is @{$fake_tx->{out}}[2], + "1008,Connection terminated from WebSocket server - incompatible communication protocol version"; + + $buf = undef; + *FooBarWorker::get_websocket_api_version = sub { WEBSOCKET_API_VERSION + 1 }; + $fake_tx->OpenQA::WebSockets::Server::_message({type => 'accepted'}); + like $buf, qr/Received a message from an incompatible worker/ or diag explain $buf; + is @{$fake_tx->{out}}[3], + "1008,Connection terminated from WebSocket server - incompatible communication protocol version"; + }; done_testing(); @@ -138,14 +142,15 @@ $singleton->{id} = \&id; $singleton; } -sub id { 1 } -sub update_status { main::_store(shift, "status", @_) } -sub set_property { main::_store(shift, "property", @_) } -sub param { 1 } -sub on { shift } -sub inactivity_timeout { shift } -sub tx { shift } -sub max_websocket_size { shift } -sub name { "Boooo" } +sub id { 1 } +sub update_status { main::_store(shift, "status", @_) } +sub set_property { main::_store(shift, "property", @_) } +sub param { 1 } +sub on { shift } +sub inactivity_timeout { shift } +sub tx { shift } +sub max_websocket_size { shift } +sub name { "Boooo" } +sub get_websocket_api_version { OpenQA::Constants::WEBSOCKET_API_VERSION() } 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/t/api/01-workers.t new/openQA-4.5.1520100590.2279151e/t/api/01-workers.t --- old/openQA-4.5.1519929327.f726adcc/t/api/01-workers.t 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/t/api/01-workers.t 2018-03-03 19:09:50.000000000 +0100 @@ -31,6 +31,7 @@ use OpenQA::Test::Case; use OpenQA::Client; use OpenQA::WebSockets; +use OpenQA::Constants 'WEBSOCKET_API_VERSION'; use OpenQA::Scheduler; # create Test DBus bus and service for fake WebSockets and Scheduler call @@ -132,6 +133,10 @@ $worker_caps->{worker_class} = 'bar'; $ret = $t->post_ok('/api/v1/workers', form => $worker_caps); +is($ret->tx->res->code, 426, "worker informed to upgrade"); +$worker_caps->{websocket_api_version} = WEBSOCKET_API_VERSION; + +$ret = $t->post_ok('/api/v1/workers', form => $worker_caps); is($ret->tx->res->code, 200, "register existing worker with token"); is($ret->tx->res->json->{id}, 1, "worker id is 1"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1519929327.f726adcc/templates/main/group_overview.html.ep new/openQA-4.5.1520100590.2279151e/templates/main/group_overview.html.ep --- old/openQA-4.5.1519929327.f726adcc/templates/main/group_overview.html.ep 2018-03-01 19:35:27.000000000 +0100 +++ new/openQA-4.5.1520100590.2279151e/templates/main/group_overview.html.ep 2018-03-03 19:09:50.000000000 +0100 @@ -45,7 +45,7 @@ <h2>Comments</h2> <div id="comments-preview"> - % for my $comment (reverse @$comments) { + % for my $comment (@$comments) { %= include 'comments/comment_row', comment_id => $comment->id, comment => $comment, user => $comment->user, context => {type => 'group', id => $group->{id}}, put_action => 'apiv1_put_group_comment', delete_action => 'apiv1_delete_group_comment' % } </div>
