__init__.py 20.8 KB
Newer Older
1 2 3
#!/usr/bin/env python
###################################################################################
# LAVA QA tool
4 5
# Copyright (C) 2015, 2016 Collabora Ltd
# Luis Araujo <luis.araujo@collabora.co.uk>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  US
###################################################################################

Andrej Shadura's avatar
Andrej Shadura committed
22 23
from __future__ import unicode_literals

24
import sys
Andrej Shadura's avatar
Andrej Shadura committed
25 26 27 28
try:
    import xmlrpc.client as xmlrpclib
except ImportError:
    import xmlrpclib
29 30
from argparse import ArgumentParser

31
from lqa_api.waitqueue import WAIT_DEFAULT_TIMEOUT
32
from lqa_api.exit_codes import APPLICATION_ERROR
33
from lqa_tool.version import __version__
34
from lqa_tool.commands import Command
35
from lqa_tool.exceptions import ProfileNotFound
Luis Araujo's avatar
Luis Araujo committed
36
from lqa_tool.settings import settings, lqa_logger
37 38 39 40 41

class Cli(object):
    """Command line interface using argparse"""

    def __init__(self):
42
        self.parser = ArgumentParser(description="lqa v{}".format(__version__))
43
        # Add options common to all sub-commands
44 45 46
        self.parser.add_argument('-c', '--config', metavar='CONFIG.yaml',
                                 help="set configuration file")
        self.parser.add_argument('--log-file', type=str, help="set the log file")
47

48
        # Sub-commands
49
        subparsers = self.parser.add_subparsers()
50 51 52

        # Submit
        submit_parser = subparsers.add_parser('submit', help="Submit job files")
53
        submit_parser.add_argument('submit_job', nargs='*', type=str,
54
                                   metavar='JOB_FILE.{yaml,json}',
55 56 57 58 59 60 61 62 63
                                   help="job file to submit")
        submit_parser.add_argument('-g', '--profile-file', metavar='PROFILE.yaml',
                                   help="set profile file")
        submit_parser.add_argument('-n', '--dry-run', action='store_true',
                                   help="Dry-run, do everyting apart from "
                                   "submitting")
        submit_parser.add_argument('-p', '--profile', action='append', type=str,
                                   help="specify the profiles to use "
                                   "(can be given multiple times)")
64
        submit_parser.add_argument('--all-profiles', action='store_true',
65
                                   help="process all the available profiles")
66
        submit_parser.add_argument('-t', '--template-vars', action='append',
67 68 69 70 71 72
                                   type=str, help="set 'field:value' "
                                   "template variables/values "
                                   "(can be given multiple times")
        submit_parser.add_argument('-v', '--verbose', action='store_true',
                                   help="Verbose mode (e.g. print the resulting "
                                   "json)")
73
        submit_parser.add_argument('--wait',  nargs='?', type=str,
74 75 76 77
                                   metavar='TIMEOUT', dest='wait_timeout',
                                   const=WAIT_DEFAULT_TIMEOUT,
                                   help="Wait for submitted jobs to complete using"
                                   " a TIMEOUT value (Default timeout of 3 hours)")
78 79
        submit_parser.add_argument('--debug-vars', action='store_true',
                                   help="Debug undefined template variables")
80 81 82
        submit_parser.add_argument('--priority',
                                   choices=['high', 'medium', 'low'],
                                   help="Set the job priority"),
83 84
        submit_parser.add_argument('--live', action='store_true',
                                   help="show job output live")
85 86 87
        submit_parser.add_argument('--check-image-url', action='store_true',
                                   help="Check that the image url exists before "
                                   "submitting job")
88 89 90 91
        submit_parser.set_defaults(func=submit)

        # Cancel
        cancel_parser = subparsers.add_parser('cancel', help="Cancel job id")
92
        cancel_parser.add_argument('job_ids',  nargs='+', type=str,
93 94 95 96
                                   metavar='JOB_ID', help="job id to cancel")
        cancel_parser.set_defaults(func=cancel)

        # Resubmit
97
        resubmit_parser = subparsers.add_parser('resubmit', help="Resubmit job id")
98
        resubmit_parser.add_argument('job_ids',  nargs='+', type=str,
99 100 101
                                     metavar='JOB_ID', help="job id to resubmit")
        resubmit_parser.set_defaults(func=resubmit)

Luis Araujo's avatar
Luis Araujo committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
        # Make stream
        mkstream_parser = subparsers.add_parser('mkstream',
                                                help="Create bundle stream")
        mkstream_parser.add_argument('description', type=str, nargs="?",
                                     default="", metavar='DESCRIPTION',
                                     help="description of the stream")
        # Group mutually exclusive options
        # Access group: public or private
        mkstream_access_group = mkstream_parser.add_mutually_exclusive_group()
        mkstream_access_group.add_argument('--public', action='store_const',
                                           const="public", default="public",
                                           help="create public stream (default)")
        mkstream_access_group.add_argument('--private', action='store_const',
                                           const="private",
                                           help="create private stream")
        # User group: anonymous, personal or team
        mkstream_user_group = mkstream_parser.add_mutually_exclusive_group()
        mkstream_user_group.add_argument('--anonymous', type=str, metavar="NAME",
                                         help="create anonymous stream (this "
                                         "option overrides access options since "
                                         "an anonymous stream is always public)")
        mkstream_user_group.add_argument('--personal', type=str,
                                         nargs='?', metavar="LOGGED_USER/SLUG",
                                         # $USER is replaced by the logged in user
                                         # when creating the bundle.
                                         const="$USER",
                                         help="create personal stream and when "
                                         "not argument is passed it defaults to "
                                         "the logged in username")
        mkstream_user_group.add_argument('--team', type=str,
                                         metavar="TEAM_NAME[/SLUG]",
                                         help="create team stream")
        mkstream_parser.set_defaults(func=mkstream)

136 137
        # Wait
        wait_parser = subparsers.add_parser('wait', help="Wait for job id")
138
        wait_parser.add_argument('job_ids',  nargs='+', type=str,
139
                                 metavar='JOB_ID', help="wait for this job id")
140
        wait_parser.add_argument('--timeout', type=str,
141
                                 default=WAIT_DEFAULT_TIMEOUT,
142 143 144
                                 help="set wait timeout")
        wait_parser.set_defaults(func=wait)

Luis Araujo's avatar
Luis Araujo committed
145 146
        # Status
        status_parser = subparsers.add_parser('status', help="Show job id status")
147
        status_parser.add_argument('job_ids',  nargs='+', type=str,
Luis Araujo's avatar
Luis Araujo committed
148 149 150 151
                                   metavar='JOB_ID',
                                   help="show the status for job id")
        status_parser.set_defaults(func=status)

Luis Araujo's avatar
Luis Araujo committed
152 153 154
        # Job Output
        output_parser = subparsers.add_parser('output',
                                              help="Fetch job id output log")
155
        output_parser.add_argument('job_id', type=int, metavar='JOB_ID',
Luis Araujo's avatar
Luis Araujo committed
156
                                   help="job id")
157 158 159 160 161
        output_group = output_parser.add_mutually_exclusive_group()
        output_group.add_argument('--file', type=str, metavar='FILE',
                                  help="write output to file")
        output_group.add_argument('--live', action='store_true',
                                  help="follow output log live")
Luis Araujo's avatar
Luis Araujo committed
162 163
        output_parser.set_defaults(func=output)

164 165 166
        # Job information
        job_parser = subparsers.add_parser('job',
                                           help="Get information for job id")
167
        job_parser.add_argument('job_ids', nargs='+', type=str, metavar='JOB_ID',
168 169 170
                                help="job id from which to fetch information")
        job_parser.add_argument('--info', action='store_true',
                                help="show job metadata information")
171 172
        job_parser.add_argument('-t', '--tests', action='store_true',
                                help="show the tests list")
173 174
        job_parser.set_defaults(func=job)

Luis Araujo's avatar
Luis Araujo committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
        # Test information
        test_parser = subparsers.add_parser('test', help="Show test information")
        test_parser.add_argument('job_id', type=int, metavar='JOB_ID',
                                 help="job id")
        test_parser.add_argument('test_name', nargs='*', type=str,
                                 metavar='TEST_NAME',
                                 help="test name or test uuid to get results, if"
                                 " no test is specified it will list all tests")
        test_parser.add_argument('--info', action='store_true',
                                 help="show test metadata information")
        test_parser.add_argument('--show-packages', action='store_true',
                                 help="show the installed packages in the system"
                                 " for the test (it can be a long output)")
        test_parser.add_argument('-e', '--exclude', action='append', type=str,
                                 help="exclude test from the result "
                                 "(can be given multiple times)")
191 192
        test_parser.add_argument('-r', '--results', action='store_true',
                                 help="show test results")
193 194
        test_parser.add_argument('--attachments', type=str, metavar="DIR",
                                 help="save test attachments to DIR")
Luis Araujo's avatar
Luis Araujo committed
195 196
        test_parser.set_defaults(func=test)

Luis Araujo's avatar
Luis Araujo committed
197 198 199 200 201 202 203 204 205 206 207
        # Tests diff
        diff_parser = subparsers.add_parser('diffresults',
                                            help="Show test results differences")
        diff_parser.add_argument('job1_id', type=int, metavar='JOB1_ID',
                                 help="job 1 id")
        diff_parser.add_argument('job2_id', type=int, metavar='JOB2_ID',
                                 help="job 2 id")
        diff_parser.add_argument('--infra', action='store_true',
                                 help="show infra (lava) tests differences")
        diff_parser.set_defaults(func=diffresults)

208 209 210 211 212 213 214
        # Report
        report_parser = subparsers.add_parser('report', help="Generate report"
                                              " for job id's")
        report_parser.add_argument('job_ids', nargs='+', type=str,
                                   metavar='JOB_ID',
                                   help="job id to generate report")
        report_parser.add_argument('-a', '--all-results', action='store_true',
215 216 217 218
                                   help="show all results (not only failed ones)")
        report_parser.add_argument('-l', '--limit', type=int, metavar="LIMIT",
                                   default=500, help="set the number of test "
                                   "results to show (defaults to 500)")
219
        report_parser.set_defaults(func=report)
220 221 222

        # Results
        results_parser = subparsers.add_parser('results', help="Get (raw) results")
223
        results_parser.add_argument('job_ids',  nargs='+', type=str,
224 225 226
                                    metavar='JOB_ID', help="job id to get results")
        results_parser.set_defaults(func=results)

227
        # Jobdef (show job definition)
228
        jobdef_parser = subparsers.add_parser('jobdef',
229
                                              help="Show job definition file")
230
        jobdef_parser.add_argument('job_ids',  nargs='+', type=str,
231 232 233 234
                                   metavar='JOB_ID',
                                   help="show the job definition file for job id")
        jobdef_parser.set_defaults(func=jobdef)

Luis Araujo's avatar
Luis Araujo committed
235 236 237
        # Show running and submitted jobs
        queue_parser = subparsers.add_parser('queue', help="Show the current queue"
                                             " of running and submitted jobs")
238 239 240
        queue_parser.add_argument('-n', '--name', action='append', type=str,
                                  default=[], help="filter jobs with NAME "
                                  "(can be given multiple times)")
241 242
        queue_parser.add_argument('-u', '--user', type=str,
                                  help="filter jobs with user NAME")
243 244 245 246 247 248 249 250 251
        queue_parser.add_argument('-d', '--device', action='append', type=str,
                                  help="filter jobs running in DEVICE "
                                  "(can be given multiple times)")
        queue_parser.add_argument('-t', '--hostname', action='append', type=str,
                                  help="filter jobs running in HOSTNAME "
                                  "(can be given multiple times)")
        queue_parser.add_argument('-w', '--worker-host', action='append', type=str,
                                  help="filter jobs running in WORKER_HOST "
                                  "(can be given multiple times)")
252 253 254
        queue_parser.add_argument('-e', '--date', type=str, metavar="YYYYMMDD",
                                  help="show jobs with date equal or older "
                                  "than YYYYMMDD")
255 256
        queue_parser.add_argument('-s', '--show-time', action='store_true',
                                  help="show time in the queue for the jobs")
Luis Araujo's avatar
Luis Araujo committed
257 258
        queue_parser.set_defaults(func=queue)

Luis Araujo's avatar
Luis Araujo committed
259 260 261
        # Clean the job queue
        cleanqueue_parser = subparsers.add_parser('cleanqueue',
                                                  help="Clean jobs queue")
262 263 264
        cleanqueue_parser.add_argument('-n', '--name', action='append', type=str,
                                       default=[], help="clean jobs with NAME "
                                       "(can be given multiple times)")
265 266
        cleanqueue_parser.add_argument('-u', '--user', type=str,
                                       help="clean jobs with user NAME")
Luis Araujo's avatar
Luis Araujo committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
        cleanqueue_parser.add_argument('-d', '--device', action='append', type=str,
                                       help="clean jobs running in DEVICE "
                                       "(can be given multiple times)")
        cleanqueue_parser.add_argument('-t', '--hostname', action='append',
                                       type=str,
                                       help="clean jobs running in HOSTNAME "
                                       "(can be given multiple times)")
        cleanqueue_parser.add_argument('-w', '--worker-host', action='append',
                                       type=str,
                                       help="clean jobs running in WORKER_HOST "
                                       "(can be given multiple times)")
        cleanqueue_parser.add_argument('-e', '--date', type=str,
                                       metavar="YYYYMMDD",
                                       help="clean jobs with date equal or older "
                                       "than YYYYMMDD")
        cleanqueue_parser.set_defaults(func=cleanqueue)

284 285 286 287 288 289 290 291 292 293 294
        # Maintenance
        maint_parser = subparsers.add_parser('maint', help="Put the given "
                                             "device in maintenance mode")
        maint_parser.add_argument('HOSTNAME', type=str, help="Name of the device")
        maint_parser.add_argument('REASON', type=str, help="Reason to put the "
                                  "device in maintenance mode.")
        maint_parser.add_argument('--email', type=str, default='',
                                  help="Email address of the user to notify "
                                  "when the job has finished")
        maint_parser.set_defaults(func=maint)

295 296 297 298 299 300 301 302 303 304
        # Online
        online_parser = subparsers.add_parser('online', help="Put the given "
                                              "device into online mode")
        online_parser.add_argument('HOSTNAME', type=str, help="Name of the device")
        online_parser.add_argument('REASON', type=str, help="Reason to put the "
                                   "device into online mode.")
        online_parser.add_argument('--skip-health-check', action='store_true',
                                   default=False, help="Skip health check")
        online_parser.set_defaults(func=online)

Luis Araujo's avatar
Luis Araujo committed
305 306 307 308 309
        # Show devices
        devices_parser = subparsers.add_parser('devices', help="Show status of all"
                                               " available devices")
        devices_parser.set_defaults(func=devices)

Luis Araujo's avatar
Luis Araujo committed
310 311 312 313 314
        # List streams
        streams_parser = subparsers.add_parser('liststreams', help="Show streams "
                                               "the user has access to")
        streams_parser.set_defaults(func=liststreams)

Luis Araujo's avatar
Luis Araujo committed
315 316 317 318 319
        # Who am I?
        whoami_parser = subparsers.add_parser('whoami', help="Show authenticated "
                                              "user name")
        whoami_parser.set_defaults(func=whoami)

Luis Araujo's avatar
Luis Araujo committed
320 321 322 323 324
        # Server version
        sversion_parser = subparsers.add_parser('sversion',
                                                help="Show LAVA server version")
        sversion_parser.set_defaults(func=sversion)

325 326 327 328
    def run(self):
        args = self._parse_args()
        # Catch any high level exception at this point
        try:
Luis Araujo's avatar
Luis Araujo committed
329
            settings.load_config(config_file=args.config, log_file=args.log_file)
330 331 332
            args.func(args)
        except ProfileNotFound:
            self.parser.error('Please specify a profile file using the -g option')
333 334 335 336
        except xmlrpclib.ProtocolError as e:
            # Catch any XMLRPC protocol error at this point.
            lqa_logger.error("xmlrpc error: {}".format(e))
            exit(APPLICATION_ERROR)
337 338
        except KeyboardInterrupt:
            pass
Luis Araujo's avatar
Luis Araujo committed
339

340 341
    def _parse_args(self, args=sys.argv[1:]):
        return self.parser.parse_args(args)
342 343


Andrej Shadura's avatar
Andrej Shadura committed
344 345 346 347
def main():
    lqa = Cli()
    lqa.run()

348
def submit(args):
349 350
    from lqa_tool.commands.submit import SubmitCmd
    SubmitCmd(args).run()
351

352
def cancel(args):
353 354
    from lqa_tool.commands.cancel import CancelCmd
    CancelCmd(args).run()
355

356
def resubmit(args):
357 358
    from lqa_tool.commands.resubmit import ReSubmitCmd
    ReSubmitCmd(args).run()
359

Luis Araujo's avatar
Luis Araujo committed
360 361 362 363
def mkstream(args):
    from lqa_tool.commands.mkstream import MkStreamCmd
    MkStreamCmd(args).run()

364
def wait(args):
365 366
    from lqa_tool.commands.wait import WaitCmd
    WaitCmd(args).run()
367

Luis Araujo's avatar
Luis Araujo committed
368 369 370 371
def status(args):
    from lqa_tool.commands.status import StatusCmd
    StatusCmd(args).run()

Luis Araujo's avatar
Luis Araujo committed
372 373 374 375
def output(args):
    from lqa_tool.commands.output import OutputCmd
    OutputCmd(args).run()

376 377 378 379
def job(args):
    from lqa_tool.commands.job import JobCmd
    JobCmd(args).run()

Luis Araujo's avatar
Luis Araujo committed
380 381 382 383
def test(args):
    from lqa_tool.commands.test import TestCmd
    TestCmd(args).run()

Luis Araujo's avatar
Luis Araujo committed
384 385 386 387
def diffresults(args):
    from lqa_tool.commands.diffresults import DiffResultsCmd
    DiffResultsCmd(args).run()

388 389 390
def report(args):
    from lqa_tool.commands.report import ReportCmd
    ReportCmd(args).run()
391

392
def results(args):
393 394
    from lqa_tool.commands.results import ResultsCmd
    ResultsCmd(args).run()
395 396 397 398

def jobdef(args):
    from lqa_tool.commands.jobdef import JobDefCmd
    JobDefCmd(args).run()
Luis Araujo's avatar
Luis Araujo committed
399

Luis Araujo's avatar
Luis Araujo committed
400 401 402 403
def queue(args):
    from lqa_tool.commands.queue import QueueCmd
    QueueCmd(args).run()

Luis Araujo's avatar
Luis Araujo committed
404 405 406 407
def cleanqueue(args):
    from lqa_tool.commands.cleanqueue import CleanQueueCmd
    CleanQueueCmd(args).run()

408 409 410 411
def maint(args):
    from lqa_tool.commands.maint import MaintCmd
    MaintCmd(args).run()

412 413 414 415
def online(args):
    from lqa_tool.commands.online import OnlineCmd
    OnlineCmd(args).run()

Luis Araujo's avatar
Luis Araujo committed
416 417 418
def devices(args):
    from lqa_tool.commands.devices import DevicesCmd
    DevicesCmd(args).run()
Luis Araujo's avatar
Luis Araujo committed
419

Luis Araujo's avatar
Luis Araujo committed
420 421 422 423
def liststreams(args):
    from lqa_tool.commands.liststreams import ListStreamsCmd
    ListStreamsCmd(args).run()

Luis Araujo's avatar
Luis Araujo committed
424 425 426
def whoami(args):
    from lqa_tool.commands.whoami import WhoAmICmd
    WhoAmICmd(args).run()
Luis Araujo's avatar
Luis Araujo committed
427 428 429 430

def sversion(args):
    from lqa_tool.commands.sversion import SVersionCmd
    SVersionCmd(args).run()