openQA allows for a few different workflows. The main entry point is the web UI if you’re wanting to look at builds, relevant jobs, test results and of course to investigate down to the level of the bare logs if all else fails. Eventually there’s a point where you run into limitations of what’s exposed through the browser. Let’s take a look at what openQA has to offer on the command line!

Inspecting the jobs

Starting with the basics, say we want to get an idea of what’s going on in our openQA instance. And I’ll be using here - all of what I’m going to explain later on applies to other instances as well. The jobs API route perhaps unsurprisingly is what we want here:

openqa-cli api --host jobs/overview

You may find that the output isn’t particularly nice to look at - luckily there’s a built-in way to make the JSON tons more readable without extra tooling:

openqa-cli api --host --pretty jobs/overview

Get the details of a specific job

So say we know what job we’re interested in, the next step would be to inspect it further. And where within the web UI we’d be looking at the results view, here we’ll pass the job ID to the jobs API route:

openqa-cli api jobs/1222737

You may have noticed that I didn’t specify the host here. If you tried it you might’ve gotten an error message and wondered what’s wrong. Or perhaps you typed it in with the --host parameter already. The client talks to localhost by default which comes in handy if you’re working on the same machine e.g. when using a development instance.

If that isn’t what you wanted, simply add the host like before:

openqa-cli api --host jobs/1222737

Trigger builds

openqa-cli schedule \
DISTRI=sle VERSION=15 FLAVOR=Desktop-DVD-Updates \
ARCH=x86_64 TEST=qam-all \
FOO=1 BAR=baz
  • Followed by the variables we need
{"error":"no api key","error_status":403}

Oops! Not allowed! 😑️


Some API calls require credentials. client.conf is understood by most OpenQA tools:

key = 1234567890ABCDEF
secret = 1234567890ABCDEF

Or specify the login with the command:

openqa-cli schedule --host \
--apikey 1234567890ABCDEF \
--apisecret 1234567890ABCDEF
  • Note: schedule is analogous to api -X POST isos
  • To make your life easier you can add -m to wait for results

Post jobs

Now that we have authentication working, let’s look at more common use cases!

openqa-cli api --host \
-X POST jobs \
FLAVOR=Online ARCH=x86_64 \
TEST=create_hdd_textmode \
MACHINE=64bit BUILD=189.1
  • Use api -X POST to post
  • jobs is the API route

Post comments

openqa-cli api --host \
-X POST jobs/2/comments text=hello

Let’s delete the comment again:

openqa-cli api --host \
-X DELETE jobs/2/comments/1

Delete a job

openqa-cli api --host \
-X DELETE jobs/67
  • Use api -X DELETE to delete

Getting the YAML for a job template

Job templates are generally defined in YAML, which can be updated via the web UI or using API routes - fun fact, the web UI actually uses those same routes which I’m going to introduce you to! 🤓️

openqa-cli api --host \
-a 'Accept: application/yaml' \
job_templates_scheduling/73 > MicroOS.yaml
cp MicroOS.yaml{,.bak}
  • Save the YAML for the MicroOS job group to a file, using > in the shell.
  • Use -a to say that we want YAML output from the API.
  • Make a backup of the YAML.
  • We can now edit the YAML document. 👷‍♀️️

Updating the YAML

openqa-validate-yaml MicroOS.yaml
  • Validate the YAML locally. This will fail on syntax errors.
  • Note: Test suites and settings are not validated this way!
openqa-cli api -X POST job_templates_scheduling/73 \
schema=JobTemplates-01.yaml \
template="$(cat MicroOS.yaml)" \
reference="$(cat MicroOS.yaml.bak)"
  • Update the job group.
  • Specify the YAML file.
  • Use the reference to avoid editing conflicts - this optional feature allows the update to fail if there was another update to the template. The web UI uses this to detect multiple persons trying to make changes at the same time.

Archive mode

Get all the assets in one fell swoop:

openqa-cli archive 408 /tmp/openqa_job_408

Tip: Optionally add --with-thumbnails


Commands are implemented as simple plug-ins. What this means is that you actually implement a new command simply by creating a new file e.g. in lib/OpenQA/CLI within the openQA source distribution. Be sure to use the according package OpenQA::CLI::clone at the top of your Perl module and openqa-cli foo will just work, as will openqa-cli --help including whatever options you add there.

For a simple example:

package OpenQA::CLI::foo;
use Mojo::Base 'OpenQA::Command';

use Mojo::Util qw(getopt);

has description => 'Download assets and test results from a job';
has usage       => sub { shift->extract_usage };                                            
sub command {
    my ($self, @args) = @_;

    getopt \@args,
      'l|asset-size-limit=i' => \(my $limit),
      't|with-thumbnails'    => \my $thumbnails;

    @args = $self->decode_args(@args);
    die $self->usage unless my $job  = shift @args;
    die $self->usage unless my $path = shift @args;

    my $url = $self->url_for("jobs/$job/details");
    my $client = $self->client($url);
        {url => $url, archive => $path,
         'with-thumbnails' => $thumbnails,
         'asset-size-limit' => $limit});

    return 0;



Say we have a test on O3 i.e. the common abbreviation for but we’re getting a bit bored with typing this out every single time. So it would be rather handy if there was a way around that… fortunately somebody thought of this and added this handy shortcut:

openqa-cli api --o3 --pretty jobs/4078851

Incidentally this also works for, which is an internal openQA instance. I’m not going to go into the details here because it wouldn’t be very interesting unless you have access to that:

openqa-cli api --osd --pretty jobs/1222737

If you’re reading this and thinking “But hold on, can I have this for my instance”, please do reach out and I’m sure we can add another shortcut! 👌️

More features to play with

I can’t possibly show off every single feature here so what I’m going to do instead is I’m going to tease you some more:

  • --data '{"group_id: 2"}'
  • --data-file ./test.json
  • --form --data '{"text":"example"}'
  • Pipes work, too!
  • And full UTF-8 support!

See openqa-cli --help!

I’m all excited, I want to find out even more!

  • You definitely want to check out the openQA docs and play some more with the commands I’ve shown off here.
  • Also, try and open an invalid URL in the openQA web UI - something magical might happen that’ll be useful for working with the RESTful API.
  • Be sure to check out openqa-mon which is a tool based on the API that allows you to monitor your jobs