コード例 #1
0
def get_ssh_parameters(target):
    """Reads the SSH parameters from ``vagrant ssh`` command output.
    """
    try:
        stdout = check_output(['vagrant', 'ssh-config'],
                              cwd=target.path,
                              stderr=subprocess.PIPE)
    except subprocess.CalledProcessError:
        # Makes sure the VM is running
        subprocess.check_call(['vagrant', 'up'], cwd=target.path)
        # Try again
        stdout = check_output(['vagrant', 'ssh-config'], cwd=target.path)

    info = {}
    for line in stdout.split(b'\n'):
        line = line.strip().split(b' ', 1)
        if len(line) != 2:
            continue
        info[line[0].decode('utf-8').lower()] = line[1].decode('utf-8')

    if 'identityfile' in info:
        key_file = info['identityfile']
    else:
        key_file = Path('~/.vagrant.d/insecure_private_key').expand_user()
    ret = dict(hostname=info.get('hostname', '127.0.0.1'),
               port=int(info.get('port', 2222)),
               username=info.get('user', 'vagrant'),
               key_filename=key_file)
    logging.debug("SSH parameters from Vagrant: %s@%s:%s, key=%s",
                  ret['username'], ret['hostname'], ret['port'],
                  ret['key_filename'])
    return ret
コード例 #2
0
ファイル: __init__.py プロジェクト: aashish24/reprozip
def get_ssh_parameters(target):
    """Reads the SSH parameters from ``vagrant ssh`` command output.
    """
    try:
        stdout = check_output(['vagrant', 'ssh-config'],
                              cwd=target.path,
                              stderr=subprocess.PIPE)
    except subprocess.CalledProcessError:
        # Makes sure the VM is running
        subprocess.check_call(['vagrant', 'up'],
                              cwd=target.path)
        # Try again
        stdout = check_output(['vagrant', 'ssh-config'],
                              cwd=target.path)

    info = {}
    for line in stdout.split(b'\n'):
        line = line.strip().split(b' ', 1)
        if len(line) != 2:
            continue
        info[line[0].decode('utf-8').lower()] = line[1].decode('utf-8')

    if 'identityfile' in info:
        key_file = info['identityfile']
    else:
        key_file = Path('~/.vagrant.d/insecure_private_key').expand_user()
    ret = dict(hostname=info.get('hostname', '127.0.0.1'),
               port=int(info.get('port', 2222)),
               username=info.get('user', 'vagrant'),
               key_filename=key_file)
    logging.debug("SSH parameters from Vagrant: %s@%s:%s, key=%s",
                  ret['username'], ret['hostname'], ret['port'],
                  ret['key_filename'])
    return ret
コード例 #3
0
ファイル: docker.py プロジェクト: hugobowne/reprozip
def get_local_addr(iface='docker0'):
    """Gets the local IP address of the local machine.

    Returns an IPv4 address as a unicode object, in digits-and-dots format.

    >>> get_local_addr('lo')
    '127.0.0.1'
    >>> get_local_addr()
    '172.17.42.1'
    """
    try:
        try:
            out = check_output(['/bin/ip', 'addr', 'show', iface])
        except subprocess.CalledProcessError:
            logging.info(
                "No interface '%s', querying any interface for an IP...",
                iface)
            out = check_output(['/bin/ip', 'addr', 'show'])
    except (OSError, subprocess.CalledProcessError):
        # This is probably going to return '127.0.0.1', and that is bad
        return socket.gethostbyname(socket.gethostname())
    else:
        for line in reversed(out.splitlines()):
            m = _addr_re.search(line)
            if m is not None:
                return m.group(1).decode('ascii')
コード例 #4
0
ファイル: __init__.py プロジェクト: hugobowne/reprozip
def check_vagrant_version():
    try:
        out = check_output(['vagrant', '--version'])
    except (subprocess.CalledProcessError, OSError):
        logging.error("Couldn't run vagrant")
        sys.exit(1)
    out = out.decode('ascii').strip().lower().split()
    if out[0] == 'vagrant':
        if LooseVersion(out[1]) < LooseVersion('1.1'):
            logging.error("Vagrant >=1.1 is required; detected version: %s",
                          out[1])
            sys.exit(1)
    else:
        logging.error("Vagrant >=1.1 is required")
        sys.exit(1)
コード例 #5
0
def check_vagrant_version():
    try:
        stdout = check_output(['vagrant', '--version'])
    except subprocess.CalledProcessError:
        logging.error("Couldn't run vagrant")
        sys.exit(1)
    stdout = stdout.decode('ascii').strip().lower().split()
    if stdout[0] == 'vagrant':
        if LooseVersion(stdout[1]) < LooseVersion('1.1'):
            logging.error("Vagrant >=1.1 is required; detected version: %s",
                          stdout[1])
            sys.exit(1)
    else:
        logging.error("Vagrant >=1.1 is required")
        sys.exit(1)
コード例 #6
0
ファイル: __init__.py プロジェクト: hugobowne/reprozip
def test_has_vagrant(pack, **kwargs):
    """Compatibility test: has vagrant (ok) or not (maybe).
    """
    if not _executable_in_path('vagrant'):
        return COMPAT_MAYBE, "vagrant not found in PATH"

    try:
        out = check_output(['vagrant', '--version'])
    except subprocess.CalledProcessError:
        return COMPAT_NO, ("vagrant was found in PATH but doesn't seem to "
                           "work properly")
    out = out.decode('ascii').strip().lower().split()
    if out[0] == 'vagrant':
        if LooseVersion(out[1]) >= LooseVersion('1.1'):
            return COMPAT_OK
        else:
            return COMPAT_NO, ("Vagrant >=1.1 is required; detected version: "
                               "%s" % out[1])
    else:
        return COMPAT_NO, "Vagrant >=1.1 is required"
コード例 #7
0
def test_has_vagrant(pack, **kwargs):
    """Compatibility test: has vagrant (ok) or not (maybe).
    """
    if not _executable_in_path('vagrant'):
        return COMPAT_MAYBE, "vagrant not found in PATH"

    try:
        stdout = check_output(['vagrant', '--version'])
    except subprocess.CalledProcessError:
        return COMPAT_NO, ("vagrant was found in PATH but doesn't seem to "
                           "work properly")
    stdout = stdout.decode('ascii').strip().lower().split()
    if stdout[0] == 'vagrant':
        if LooseVersion(stdout[1]) >= LooseVersion('1.1'):
            return COMPAT_OK
        else:
            return COMPAT_NO, ("Vagrant >=1.1 is required; detected version: "
                               "%s" % stdout[1])
    else:
        return COMPAT_NO, "Vagrant >=1.1 is required"
コード例 #8
0
ファイル: __init__.py プロジェクト: hugobowne/reprozip
def machine_setup(target, use_chroot):
    """Prepare the machine and get SSH parameters from ``vagrant ssh``.
    """
    try:
        out = check_output(['vagrant', 'ssh-config'],
                           cwd=target.path,
                           stderr=subprocess.PIPE)
    except subprocess.CalledProcessError:
        # Makes sure the VM is running
        logging.info("Calling 'vagrant up'...")
        try:
            retcode = subprocess.check_call(['vagrant', 'up'], cwd=target.path)
        except OSError:
            logging.critical("vagrant executable not found")
            sys.exit(1)
        else:
            if retcode != 0:
                logging.critical("vagrant up failed with code %d", retcode)
                sys.exit(1)
        # Try again
        out = check_output(['vagrant', 'ssh-config'],
                           cwd=target.path)

    vagrant_info = {}
    for line in out.split(b'\n'):
        line = line.strip().split(b' ', 1)
        if len(line) != 2:
            continue
        value = line[1].decode('utf-8')
        if len(value) >= 2 and value[0] == '"' and value[-1] == '"':
            # Vagrant should really be escaping special characters here, but
            # it's not -- https://github.com/mitchellh/vagrant/issues/6428
            value = value[1:-1]
        vagrant_info[line[0].decode('utf-8').lower()] = value

    if 'identityfile' in vagrant_info:
        key_file = vagrant_info['identityfile']
    else:
        key_file = Path('~/.vagrant.d/insecure_private_key').expand_user()
    info = dict(hostname=vagrant_info.get('hostname', '127.0.0.1'),
                port=int(vagrant_info.get('port', 2222)),
                username=vagrant_info.get('user', 'vagrant'),
                key_filename=key_file)
    logging.debug("SSH parameters from Vagrant: %s@%s:%s, key=%s",
                  info['username'], info['hostname'], info['port'],
                  info['key_filename'])

    if use_chroot:
        # Mount directories
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(IgnoreMissingKey())
        ssh.connect(**info)
        chan = ssh.get_transport().open_session()
        chan.exec_command(
            '/usr/bin/sudo /bin/sh -c %s' % shell_escape(
                'for i in dev proc; do '
                'if ! grep "^/experimentroot/$i$" /proc/mounts; then '
                'mount -o rbind /$i /experimentroot/$i; '
                'fi; '
                'done'))
        ssh.close()

    return info
コード例 #9
0
ファイル: docker.py プロジェクト: JosuaKrause/reprozip
def docker_run(args):
    """Runs the experiment in the container.
    """
    target = Path(args.target[0])
    unpacked_info = read_dict(target / '.reprounzip')
    cmdline = args.cmdline

    # Loads config
    runs, packages, other_files = load_config(target / 'config.yml', True)

    selected_runs = get_runs(runs, args.run, cmdline)

    # Get current image name
    if 'current_image' in unpacked_info:
        image = unpacked_info['current_image']
        logging.debug("Running from image %s", image.decode('ascii'))
    else:
        logging.critical("Image doesn't exist yet, have you run setup/build?")
        sys.exit(1)

    # Name of new container
    container = make_unique_name(b'reprounzip_run_')

    hostname = runs[selected_runs[0]].get('hostname', 'reprounzip')

    # Get the local bridge IP
    ip_str = get_iface_addr('docker0')

    # X11 handler
    x11 = X11Handler(args.x11, ('internet', ip_str), args.x11_display)

    cmds = []
    for run_number in selected_runs:
        run = runs[run_number]
        cmd = 'cd %s && ' % shell_escape(run['workingdir'])
        cmd += '/busybox env -i '
        environ = x11.fix_env(run['environ'])
        cmd += ' '.join('%s=%s' % (k, shell_escape(v))
                        for k, v in iteritems(environ))
        cmd += ' '
        # FIXME : Use exec -a or something if binary != argv[0]
        if cmdline is None:
            argv = [run['binary']] + run['argv'][1:]
        else:
            argv = cmdline
        cmd += ' '.join(shell_escape(a) for a in argv)
        uid = run.get('uid', 1000)
        gid = run.get('gid', 1000)
        cmd = '/rpzsudo \'#%d\' \'#%d\' /busybox sh -c %s\n' % (
            uid, gid,
            shell_escape(cmd))
        cmds.append(cmd)
    cmds = x11.init_cmds + cmds
    cmds = ' && '.join(cmds)

    signals.pre_run(target=target)

    # Creates forwarders
    forwarders = []
    for port, connector in x11.port_forward:
        forwarders.append(LocalForwarder(connector, port))

    # Run command in container
    logging.info("Starting container %s", container.decode('ascii'))
    retcode = interruptible_call(['docker', 'run', b'--name=' + container,
                                  '-h', hostname,
                                  '-i', '-t', image,
                                  '/busybox', 'sh', '-c', cmds])
    if retcode != 0:
        logging.critical("docker run failed with code %d", retcode)
        subprocess.call(['docker', 'rm', '-f', container])
        sys.exit(1)

    # Get exit status from "docker inspect"
    out = check_output(['docker', 'inspect', container])
    outjson = json.loads(out.decode('ascii'))
    if (outjson[0]["State"]["Running"] is not False or
            outjson[0]["State"]["Paused"] is not False):
        logging.error("Invalid container state after execution:\n%s",
                      json.dumps(outjson[0]["State"]))
    retcode = outjson[0]["State"]["ExitCode"]
    stderr.write("\n*** Command finished, status: %d\n" % retcode)

    # Commit to create new image
    new_image = make_unique_name(b'reprounzip_image_')
    logging.info("Committing container %s to image %s",
                 container.decode('ascii'), new_image.decode('ascii'))
    subprocess.check_call(['docker', 'commit', container, new_image])

    # Update image name
    unpacked_info['current_image'] = new_image
    write_dict(target / '.reprounzip', unpacked_info)

    # Remove the container
    logging.info("Destroying container %s", container.decode('ascii'))
    retcode = subprocess.call(['docker', 'rm', container])
    if retcode != 0:
        logging.error("Error deleting container %s", container.decode('ascii'))

    # Untag previous image, unless it is the initial_image
    if image != unpacked_info['initial_image']:
        logging.info("Untagging previous image %s", image.decode('ascii'))
        subprocess.check_call(['docker', 'rmi', image])

    signals.post_run(target=target, retcode=retcode)
コード例 #10
0
ファイル: docker.py プロジェクト: hugobowne/reprozip
def docker_run(args):
    """Runs the experiment in the container.
    """
    target = Path(args.target[0])
    unpacked_info = read_dict(target)
    cmdline = args.cmdline

    # Loads config
    config = load_config(target / 'config.yml', True)
    runs = config.runs

    selected_runs = get_runs(runs, args.run, cmdline)

    # Get current image name
    if 'current_image' in unpacked_info:
        image = unpacked_info['current_image']
        logging.debug("Running from image %s", image.decode('ascii'))
    else:
        logging.critical("Image doesn't exist yet, have you run setup/build?")
        sys.exit(1)

    # Name of new container
    container = make_unique_name(b'reprounzip_run_')

    hostname = runs[selected_runs[0]].get('hostname', 'reprounzip')

    # X11 handler
    if args.x11:
        local_ip = get_local_addr()

        docker_host = local_ip
        if os.environ.get('DOCKER_HOST'):
            m = _dockerhost_re.match(os.environ['DOCKER_HOST'])
            if m is not None:
                docker_host = m.group(1)

        if args.tunneled_x11:
            x11 = X11Handler(True, ('internet', docker_host), args.x11_display)
        else:
            x11 = X11Handler(True, ('internet', local_ip), args.x11_display)

            if (docker_host != local_ip and docker_host != 'localhost' and
                    not docker_host.startswith('127.') and
                    not docker_host.startswith('192.168.99.')):
                ssh_cmdline = ' '.join(
                    '-R*:%(p)d:127.0.0.1:%(p)d' % {'p': port}
                    for port, connector in x11.port_forward)
                logging.warning(
                    "You requested X11 forwarding but the Docker container "
                    "appears to be running remotely. It is probable that it "
                    "won't be able to connect to the local display. Creating "
                    "a remote SSH tunnel and running with --tunneled-x11 "
                    "might help (%s).",
                    ssh_cmdline)
    else:
        x11 = X11Handler(False, ('local', hostname), args.x11_display)

    cmds = []
    for run_number in selected_runs:
        run = runs[run_number]
        cmd = 'cd %s && ' % shell_escape(run['workingdir'])
        cmd += '/busybox env -i '
        environ = x11.fix_env(run['environ'])
        environ = fixup_environment(environ, args)
        cmd += ' '.join('%s=%s' % (k, shell_escape(v))
                        for k, v in iteritems(environ))
        cmd += ' '
        # FIXME : Use exec -a or something if binary != argv[0]
        if cmdline is None:
            argv = [run['binary']] + run['argv'][1:]
        else:
            argv = cmdline
        cmd += ' '.join(shell_escape(a) for a in argv)
        uid = run.get('uid', 1000)
        gid = run.get('gid', 1000)
        cmd = '/rpzsudo \'#%d\' \'#%d\' /busybox sh -c %s' % (
            uid, gid,
            shell_escape(cmd))
        cmds.append(cmd)
    cmds = x11.init_cmds + cmds
    cmds = ' && '.join(cmds)

    signals.pre_run(target=target)

    # Creates forwarders
    forwarders = []
    for port, connector in x11.port_forward:
        forwarders.append(LocalForwarder(connector, port))

    # Run command in container
    logging.info("Starting container %s", container.decode('ascii'))
    retcode = interruptible_call(['docker', 'run', b'--name=' + container,
                                  '-h', hostname,
                                  '-i', '-t', image,
                                  '/busybox', 'sh', '-c', cmds])
    if retcode != 0:
        logging.critical("docker run failed with code %d", retcode)
        subprocess.call(['docker', 'rm', '-f', container])
        sys.exit(1)

    # Get exit status from "docker inspect"
    out = check_output(['docker', 'inspect', container])
    outjson = json.loads(out.decode('ascii'))
    if (outjson[0]["State"]["Running"] is not False or
            outjson[0]["State"]["Paused"] is not False):
        logging.error("Invalid container state after execution:\n%s",
                      json.dumps(outjson[0]["State"]))
    retcode = outjson[0]["State"]["ExitCode"]
    stderr.write("\n*** Command finished, status: %d\n" % retcode)

    # Commit to create new image
    new_image = make_unique_name(b'reprounzip_image_')
    logging.info("Committing container %s to image %s",
                 container.decode('ascii'), new_image.decode('ascii'))
    subprocess.check_call(['docker', 'commit', container, new_image])

    # Update image name
    unpacked_info['current_image'] = new_image
    write_dict(target, unpacked_info)

    # Remove the container
    logging.info("Destroying container %s", container.decode('ascii'))
    retcode = subprocess.call(['docker', 'rm', container])
    if retcode != 0:
        logging.error("Error deleting container %s", container.decode('ascii'))

    # Untag previous image, unless it is the initial_image
    if image != unpacked_info['initial_image']:
        logging.info("Untagging previous image %s", image.decode('ascii'))
        subprocess.check_call(['docker', 'rmi', image])

    # Update input file status
    metadata_update_run(config, unpacked_info, selected_runs)
    write_dict(target, unpacked_info)

    signals.post_run(target=target, retcode=retcode)