Esempio n. 1
0
def cmd_shell(c, ce):
    cmdnumargs(c, ce, 1, None)
    if not downtmp:
        bomb("`shell' when not open")
    # runners can provide a hook if they need a special treatment
    try:
        caller.hook_shell(*c[1:])
    except AttributeError:
        adtlog.debug('cmd_shell: using default shell command, dir %s' % c[1])
        cmd = 'cd "%s"; ' % c[1]
        for e in c[2:]:
            cmd += 'export "%s"; ' % e
        # use host's $TERM to provide a sane shell
        try:
            cmd += 'export TERM="%s"; ' % os.environ['TERM']
        except KeyError:
            pass
        cmd += 'bash -i'
        try:
            with open('/dev/tty', 'rb') as sin:
                with open('/dev/tty', 'wb') as sout:
                    with open('/dev/tty', 'wb') as serr:
                        subprocess.call(auxverb + ['sh', '-c', cmd],
                                        stdin=sin,
                                        stdout=sout,
                                        stderr=serr)
        except (OSError, IOError) as e:
            adtlog.error('Cannot run shell: %s' % e)
Esempio n. 2
0
def execute_timeout(instr, timeout, *popenargs, **popenargsk):
    '''Popen wrapper with timeout supervision

    If instr is given, it is fed into stdin, otherwise stdin will be /dev/null.

    Return (status, stdout, stderr)
    '''
    adtlog.debug('execute-timeout: ' + ' '.join(popenargs[0]))
    if instr is None:
        popenargsk['stdin'] = devnull_read
    else:
        instr = instr.encode('UTF-8')
    sp = subprocess.Popen(*popenargs, **popenargsk)
    timeout_start(timeout)
    try:
        (out, err) = sp.communicate(instr)
        if out is not None:
            out = out.decode('UTF-8', 'replace')
        if err is not None:
            err = err.decode('UTF-8', 'replace')
    except Timeout:
        try:
            sp.kill()
            sp.wait()
        except OSError as e:
            adtlog.error('WARNING: Cannot kill timed out process %s: %s' %
                         (popenargs[0], e))
        raise
    timeout_stop()
    status = sp.wait()
    return (status, out, err)
Esempio n. 3
0
def cleanup():
    global downtmp, cleaning
    adtlog.debug("cleanup...")
    sethandlers(signal.SIG_DFL)
    # avoid recursion if something bomb()s in hook_cleanup()
    if not cleaning:
        cleaning = True
        if downtmp:
            caller.hook_cleanup()
        cleaning = False
        downtmp = None
Esempio n. 4
0
def cmd_open(c, ce):
    global auxverb, downtmp, downtmp_open
    cmdnumargs(c, ce)
    if downtmp:
        bomb("`open' when already open")
    caller.hook_open()
    adtlog.debug("auxverb = %s, downtmp = %s" % (str(auxverb), downtmp))
    downtmp = caller.hook_downtmp(downtmp_open)
    if downtmp_open and downtmp_open != downtmp:
        bomb('virt-runner failed to restore downtmp path %s, gave %s instead' %
             (downtmp_open, downtmp))
    downtmp_open = downtmp
    return [downtmp]
Esempio n. 5
0
def cmd_reboot(c, ce):
    global downtmp
    cmdnumargs(c, ce, 0, 1)
    if not downtmp:
        bomb("`reboot' when not open")
    if 'reboot' not in caller.hook_capabilities():
        bomb("`reboot' when `reboot' not advertised")

    # save current downtmp; try a few locations, as /var/cache might be r/o
    # (argh Ubuntu touch)
    directories = '/var/cache /home'
    check_exec([
        'sh', '-ec',
        'for d in %s; do if [ -w $d ]; then '
        '  tar --warning=none --create --absolute-names '
        '''    -f $d/autopkgtest-tmpdir.tar '%s'; '''
        '  rm -f /run/autopkgtest-reboot-prepare-mark; '
        '  exit 0; fi; done; exit 1'
        '' % (directories, downtmp)
    ],
               downp=True,
               timeout=copy_timeout)
    adtlog.debug('cmd_reboot: saved current downtmp, rebooting')

    try:
        caller.hook_prepare_reboot()
    except AttributeError:
        pass

    # reboot
    if len(c) > 1 and c[1] == 'prepare-only':
        adtlog.info('state saved, waiting for testbed to reboot...')
    else:
        execute_timeout(
            None, 30,
            auxverb + ['sh', '-c', '(sleep 3; reboot) >/dev/null 2>&1 &'])
    caller.hook_wait_reboot()

    # restore downtmp
    check_exec([
        'sh', '-ec',
        'for d in %s; do '
        'if [ -e $d/autopkgtest-tmpdir.tar ]; then '
        ' tar --warning=none --extract --absolute-names '
        '     -f $d/autopkgtest-tmpdir.tar;'
        ' rm $d/autopkgtest-tmpdir.tar; exit 0; '
        'fi; done; exit 1' % directories
    ],
               downp=True,
               timeout=copy_timeout)
    adtlog.debug('cmd_reboot: restored downtmp after reboot')
Esempio n. 6
0
def copydown_shareddir(host, tb, is_dir, downtmp_host):
    adtlog.debug(
        'copydown_shareddir: host %s tb %s is_dir %s downtmp_host %s' %
        (host, tb, is_dir, downtmp_host))

    host = os.path.normpath(host)
    tb = os.path.normpath(tb)
    downtmp_host = os.path.normpath(downtmp_host)

    timeout_start(copy_timeout)
    try:
        host_tmp = None
        if host.startswith(downtmp_host):
            # translate into tb path
            host = downtmp + host[len(downtmp_host):]
        else:
            host_tmp = os.path.join(downtmp_host, os.path.basename(tb))
            if is_dir:
                if os.path.exists(host_tmp):
                    try:
                        shutil.rmtree(host_tmp)
                    except OSError as e:
                        adtlog.warning('cannot remove old %s, moving it '
                                       'instead: %s' % (host_tmp, e))
                        # some undeletable files? hm, move it aside instead
                        counter = 0
                        while True:
                            p = host_tmp + '.old%i' % counter
                            if not os.path.exists(p):
                                os.rename(host_tmp, p)
                                break
                            counter += 1

                shutil.copytree(host, host_tmp, symlinks=True)
            else:
                shutil.copy(host, host_tmp)
            # translate into tb path
            host = os.path.join(downtmp, os.path.basename(tb))

        if host == tb:
            host_tmp = None
        else:
            check_exec(['rm', '-rf', tb], downp=True)
            check_exec(['cp', '-r', '--preserve=timestamps,links', host, tb],
                       downp=True)
        if host_tmp:
            (is_dir and shutil.rmtree or os.unlink)(host_tmp)
    finally:
        timeout_stop()
Esempio n. 7
0
def cmd_revert(c, ce):
    global auxverb, downtmp, downtmp_open
    cmdnumargs(c, ce)
    if not downtmp:
        bomb("`revert' when not open")
    if 'revert' not in caller.hook_capabilities():
        bomb("`revert' when `revert' not advertised")
    caller.hook_revert()
    downtmp = caller.hook_downtmp(downtmp_open)
    if downtmp_open and downtmp_open != downtmp:
        bomb('virt-runner failed to restore downtmp path %s, gave %s instead' %
             (downtmp_open, downtmp))
    adtlog.debug("auxverb = %s, downtmp = %s" % (str(auxverb), downtmp))

    return [downtmp]
Esempio n. 8
0
def expect(sock, search_bytes, timeout_sec, description=None, echo=False):
    adtlog.debug('expect: "%s"' % (search_bytes or b'<none>').decode())
    what = '"%s"' % (description or search_bytes or 'data')
    out = b''
    with timeout(timeout_sec,
                 description and ('timed out waiting for %s' % what) or None):
        while True:
            block = sock.recv(4096)
            if not block:
                time.sleep(0.1)
                continue
            if echo:
                sys.stderr.buffer.write(block)
            out += block
            if search_bytes is None or search_bytes in out:
                adtlog.debug('expect: found "%s"' % what)
                break

    return out
Esempio n. 9
0
def command():
    sys.stdout.flush()
    while True:
        try:
            ce = sys.stdin.readline().strip()
            # FIXME: This usually means EOF (as checked below), but with Python
            # 3 we often get empty strings here even though this is supposed to
            # block for new input.
            if ce == '':
                time.sleep(0.1)
                continue
            break
        except IOError as e:
            if e.errno == errno.EAGAIN:
                time.sleep(0.1)
                continue
            else:
                raise
    if not ce:
        bomb('end of file - caller quit?')
    ce = ce.rstrip().split()
    c = list(map(url_unquote, ce))
    if not c:
        bomb('empty commands are not permitted')
    adtlog.debug('executing ' + ' '.join(ce))
    c_lookup = c[0].replace('-', '_')
    try:
        f = globals()['cmd_' + c_lookup]
    except KeyError:
        bomb("unknown command `%s'" % ce[0])
    try:
        r = f(c, ce)
        if not r:
            r = []
        r.insert(0, 'ok')
    except FailedCmd as fc:
        r = fc.e
    print(' '.join(r))
Esempio n. 10
0
def copyup_shareddir(tb, host, is_dir, downtmp_host):
    adtlog.debug('copyup_shareddir: tb %s host %s is_dir %s downtmp_host %s' %
                 (tb, host, is_dir, downtmp_host))

    host = os.path.normpath(host)
    tb = os.path.normpath(tb)
    downtmp_host = os.path.normpath(downtmp_host)

    timeout_start(copy_timeout)
    try:
        tb_tmp = None
        if tb.startswith(downtmp):
            # translate into host path
            tb = downtmp_host + tb[len(downtmp):]
        else:
            tb_tmp = os.path.join(downtmp, os.path.basename(host))
            adtlog.debug('copyup_shareddir: tb path %s is not already in '
                         'downtmp, copying to %s' % (tb, tb_tmp))
            check_exec(['cp', '-r', '--preserve=timestamps,links', tb, tb_tmp],
                       downp=True)
            # translate into host path
            tb = os.path.join(downtmp_host, os.path.basename(host))

        if tb == host:
            tb_tmp = None
        else:
            adtlog.debug('copyup_shareddir: tb(host) %s is not already at '
                         'destination %s, copying' % (tb, host))
            if is_dir:
                copytree(tb, host)
            else:
                shutil.copy(tb, host)

        if tb_tmp:
            adtlog.debug('copyup_shareddir: rm intermediate copy: %s' % tb)
            check_exec(['rm', '-rf', tb_tmp], downp=True)
    finally:
        timeout_stop()
Esempio n. 11
0
def copyupdown_internal(wh, sd, upp):
    '''Copy up/down a file or dir.

    wh: 'copyup' or 'copydown'
    sd: (source, destination) paths
    upp: True for copyup, False for copydown
    '''
    if not downtmp:
        bomb("%s when not open" % wh)
    if not sd[0] or not sd[1]:
        bomb("%s paths must be nonempty" % wh)
    dirsp = sd[0][-1] == '/'
    if dirsp != (sd[1][-1] == '/'):
        bomb("%s paths must agree about directoryness"
             " (presence or absence of trailing /)" % wh)

    # if we have a shared directory, we just need to copy it from/to there; in
    # most cases, it's testbed end is already in the downtmp dir
    downtmp_host = get_downtmp_host()
    if downtmp_host:
        try:
            if upp:
                copyup_shareddir(sd[0], sd[1], dirsp, downtmp_host)
            else:
                copydown_shareddir(sd[0], sd[1], dirsp, downtmp_host)
            return
        except Timeout:
            raise FailedCmd(['timeout'])
        except (shutil.Error, subprocess.CalledProcessError) as e:
            adtlog.debug(
                'Cannot copy %s to %s through shared dir: %s, falling back to tar'
                % (sd[0], sd[1], str(e)))

    isrc = 0
    idst = 1
    ilocal = 0 + upp
    iremote = 1 - upp

    deststdout = devnull_read
    srcstdin = devnull_read
    remfileq = pipes.quote(sd[iremote])
    if not dirsp:
        rune = 'cat %s%s' % ('><'[upp], remfileq)
        if upp:
            deststdout = open(sd[idst], 'wb')
        else:
            srcstdin = open(sd[isrc], 'rb')
            status = os.fstat(srcstdin.fileno())
            if status.st_mode & 0o111:
                rune += '; chmod +x -- %s' % (remfileq)
        localcmdl = ['cat']
    else:
        taropts = [None, None]
        taropts[isrc] = '--warning=none -c .'
        taropts[idst] = '--warning=none --preserve-permissions --extract ' \
                        '--no-same-owner'

        rune = 'cd %s; tar %s -f -' % (remfileq, taropts[iremote])
        if upp:
            try:
                os.mkdir(sd[ilocal])
            except (IOError, OSError) as oe:
                if oe.errno != errno.EEXIST:
                    raise
        else:
            rune = ('if ! test -d %s; then mkdir -- %s; fi; ' %
                    (remfileq, remfileq)) + rune

        localcmdl = ['tar', '--directory', sd[ilocal]] + (
            ('%s -f -' % taropts[ilocal]).split())
    downcmdl = auxverb + ['sh', '-ec', rune]

    if upp:
        cmdls = (downcmdl, localcmdl)
    else:
        cmdls = (localcmdl, downcmdl)

    adtlog.debug(str(["cmdls", str(cmdls)]))
    adtlog.debug(
        str([
            "srcstdin",
            str(srcstdin), "deststdout",
            str(deststdout), "devnull_read", devnull_read
        ]))

    subprocs = [None, None]
    adtlog.debug(" +< %s" % ' '.join(cmdls[0]))
    subprocs[0] = subprocess.Popen(cmdls[0],
                                   stdin=srcstdin,
                                   stdout=subprocess.PIPE)
    adtlog.debug(" +> %s" % ' '.join(cmdls[1]))
    subprocs[1] = subprocess.Popen(cmdls[1],
                                   stdin=subprocs[0].stdout,
                                   stdout=deststdout)
    subprocs[0].stdout.close()
    try:
        timeout_start(copy_timeout)
        for sdn in [1, 0]:
            adtlog.debug(" +" + "<>"[sdn] + "?")
            status = subprocs[sdn].wait()
            if not (status == 0 or (sdn == 0 and status == -13)):
                timeout_stop()
                bomb("%s %s failed, status %d" %
                     (wh, ['source', 'destination'][sdn], status))
        timeout_stop()
    except Timeout:
        for sdn in [1, 0]:
            subprocs[sdn].kill()
            subprocs[sdn].wait()
        raise FailedCmd(['timeout'])
Esempio n. 12
0
 def bomb(self, m, _type=adtlog.TestbedFailure):
     adtlog.debug('%s %s' % (_type.__name__, m))
     #self.stop() # don't stop when bombing, so we can control it via no_clean_on_error
     raise _type(m)