X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Ftools%2Fscripts%2Ftopo_reservation.py;h=77d84efebadcdfd8645de9b77942db884c498b6d;hb=4929e57e9c8d721000adcbdf2bcbe0dc6952a831;hp=bf31918c7308abc8d1cff38840ddf624d8fa753d;hpb=e4091a25520e8cf1c62254df74b7ccf57f2ce1c7;p=csit.git diff --git a/resources/tools/scripts/topo_reservation.py b/resources/tools/scripts/topo_reservation.py index bf31918c73..77d84efeba 100755 --- a/resources/tools/scripts/topo_reservation.py +++ b/resources/tools/scripts/topo_reservation.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 -# Copyright (c) 2018 Cisco and/or its affiliates. +# Copyright (c) 2019 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -22,48 +22,105 @@ As source of truth, TG node from the topology file is used. import sys import argparse -from resources.libraries.python.ssh import SSH -from yaml import load +import yaml + +from resources.libraries.python.ssh import exec_cmd + RESERVATION_DIR = "/tmp/reservation_dir" + +def diag_cmd(node, cmd): + """Execute cmd, print cmd and stdout, ignore stderr and rc; return None. + + :param node: Node object as parsed from topology file to execute cmd on. + :param cmd: Command to execute. + :type ssh: dict + :type cmd: str + """ + print "+", cmd + _, stdout, _ = exec_cmd(node, cmd) + print stdout + + def main(): + """Parse arguments, perform the action, write useful output, propagate RC. + + If the intended action is cancellation, reservation dir is deleted. + + If the intended action is reservation, the list is longer: + 1. List contents of reservation dir. + 2. List contents of test.url file in the dir. + 3. Create reservation dir. + 4. Touch file according to -r option. + From these 4 steps, 1 and 2 are performed always, their RC ignored. + RC of step 3 gives the overall result. + If the result is success, step 4 is executed without any output, + their RC is ignored. + + The "run tag" as a filename is useful for admins accessing the testbed + via a graphical terminal, which does not allow copying of text, + as they need less keypresses to identify the test run holding the testbed. + Also, the listing shows timestamps, which is useful for both audiences. + + This all assumes the target system accepts ssh connections. + If it does not, the caller probably wants to stop trying + to reserve this system. Therefore this script can return 3 different codes. + Return code 0 means the reservation was successful. + Return code 1 means the system is inaccessible (or similarly unsuitable). + Return code 2 means the system is accessible, but already reserved. + The reason unsuitable systems return 1 is because that is also the value + Python returns on encountering and unexcepted exception. + """ parser = argparse.ArgumentParser() parser.add_argument("-t", "--topo", required=True, help="Topology file") parser.add_argument("-c", "--cancel", help="Cancel reservation", action="store_true") + parser.add_argument("-r", "--runtag", required=False, default="Unknown", + help="Identifier for test run suitable as filename") args = parser.parse_args() - topology_file = args.topo - cancel_reservation = args.cancel - work_file = open(topology_file) - topology = load(work_file.read())['nodes'] + with open(args.topo, "r") as topo_file: + topology = yaml.load(topo_file.read())['nodes'] # Even if TG is not guaranteed to be a Linux host, # we are using it, because testing shows SSH access to DUT # during test affects its performance (bursts of lost packets). try: - tg_node = topology["TG"] + tgn = topology["TG"] except KeyError: print "Topology file does not contain 'TG' node" return 1 - ssh = SSH() - ssh.connect(tg_node) - # For system reservation we use mkdir it is an atomic operation and we can # store additional data (time, client_ID, ..) within reservation directory. - if cancel_reservation: - ret, _, err = ssh.exec_command("rm -r {}".format(RESERVATION_DIR)) - else: - ret, _, err = ssh.exec_command("mkdir {}".format(RESERVATION_DIR)) - - if ret != 0: - print("{} unsuccessful:\n{}". - format(("Cancellation " if cancel_reservation else "Reservation"), - err)) - return ret + if args.cancel: + ret, _, err = exec_cmd(tgn, "rm -r {}".format(RESERVATION_DIR)) + if ret: + print "Cancellation unsuccessful:\n{}".format(err) + return ret + # Before critical section, output can be outdated already. + print("Diagnostic commands:") + # -d and * are to supress "total ", see https://askubuntu.com/a/61190 + diag_cmd(tgn, "ls --full-time -cd '{dir}'/*".format(dir=RESERVATION_DIR)) + print("Attempting reservation.") + # Entering critical section. + ret, _, err = exec_cmd(tgn, "mkdir '{dir}'".format(dir=RESERVATION_DIR)) + # Critical section is over. + if ret: + print("Already reserved by another job:\n{}".format(err)) + return 2 + # Here the script knows it is the only owner of the testbed. + print("Success, writing test run info to reservation dir.") + ret2, _, err = exec_cmd( + tgn, "touch '{dir}/{runtag}'"\ + .format(dir=RESERVATION_DIR, runtag=args.runtag)) + if ret2: + print("Writing test run info failed, but continuing anyway:\n{}".format( + err)) + return 0 + if __name__ == "__main__": sys.exit(main())