Ejemplo n.º 1
0
def _load_private_key_file(filename, key_filename, key_password):
    exception = PyinfraError("Invalid key: {0}".format(filename))

    for key_cls in (RSAKey, DSSKey, ECDSAKey, Ed25519Key):
        try:
            return key_cls.from_private_key_file(filename=filename, )

        except PasswordRequiredException:
            if not key_password:
                # If password is not provided, but we're in CLI mode, ask for it. I'm not a
                # huge fan of having CLI specific code in here, but it doesn't really fit
                # anywhere else without duplicating lots of key related code into cli.py.
                if pyinfra.is_cli:
                    key_password = getpass(
                        "Enter password for private key: {0}: ".format(
                            key_filename, ), )

                # API mode and no password? We can't continue!
                else:
                    raise PyinfraError(
                        "Private key file ({0}) is encrypted, set ssh_key_password to "
                        "use this key".format(key_filename), )

            try:
                return key_cls.from_private_key_file(
                    filename=filename,
                    password=key_password,
                )
            except SSHException as e:  # key does not match key_cls type
                exception = e
        except SSHException as e:  # key does not match key_cls type
            exception = e
    raise exception
Ejemplo n.º 2
0
def _get_private_key(state, key_filename, key_password):
    if key_filename in state.private_keys:
        return state.private_keys[key_filename]

    ssh_key_filenames = [
        # Global from executed directory
        path.expanduser(key_filename),
    ]

    # Relative to the deploy
    if state.deploy_dir:
        ssh_key_filenames.append(path.join(state.deploy_dir, key_filename), )

    for filename in ssh_key_filenames:
        if not path.isfile(filename):
            continue

        # First, lets try the key without a password
        try:
            key = RSAKey.from_private_key_file(filename=filename, )
            break

        # Key is encrypted!
        except PasswordRequiredException:
            # If password is not provided, but we're in CLI mode, ask for it. I'm not a
            # huge fan of having CLI specific code in here, but it doesn't really fit
            # anywhere else without duplicating lots of key related code into cli.py.
            if not key_password:
                if pyinfra.is_cli:
                    key_password = getpass(
                        'Enter password for private key: {0}: '.format(
                            key_filename, ), )

            # API mode and no password? We can't continue!
                else:
                    raise PyinfraError(
                        'Private key file ({0}) is encrypted, set ssh_key_password to '
                        'use this key'.format(key_filename), )

            # Now, try opening the key with the password
            try:
                key = RSAKey.from_private_key_file(
                    filename=filename,
                    password=key_password,
                )
                break

            except SSHException:
                raise PyinfraError(
                    'Incorrect password for private key: {0}'.format(
                        key_filename, ), )

    # No break, so no key found
    else:
        raise IOError('No such private key file: {0}'.format(key_filename))

    state.private_keys[key_filename] = key
    return key
Ejemplo n.º 3
0
def _get_private_key(state, key_filename, key_password):
    if key_filename in state.private_keys:
        return state.private_keys[key_filename]

    ssh_key_filenames = [
        # Global from executed directory
        path.expanduser(key_filename),
    ]

    # Relative to the deploy
    if state.deploy_dir:
        ssh_key_filenames.append(path.join(state.deploy_dir, key_filename), )

    key = False
    key_file_exists = False

    for filename in ssh_key_filenames:
        if not path.isfile(filename):
            continue

        key_file_exists = True

        try:
            key = _load_private_key_file(filename, key_filename, key_password)
            break
        except SSHException:
            pass

    # No break, so no key found
    if not key:
        if not key_file_exists:
            raise PyinfraError(
                'No such private key file: {0}'.format(key_filename))

        # TODO: upgrade min paramiko version to 2.7 and remove this (pyinfra v2)
        extra_info = ''
        from pkg_resources import get_distribution, parse_version
        if get_distribution('paramiko').parsed_version < parse_version('2.7'):
            extra_info = (
                '\n    Paramiko versions under 2.7 do not support the latest OpenSSH key formats,'
                ' upgrading may fix this error.'
                '\n    For more information, see this issue: '
                'https://github.com/Fizzadar/pyinfra/issues/548')
        raise PyinfraError('Invalid private key file: {0}{1}'.format(
            key_filename, extra_info))

    # Load any certificate, names from OpenSSH:
    # https://github.com/openssh/openssh-portable/blob/049297de975b92adcc2db77e3fb7046c0e3c695d/ssh-keygen.c#L2453  # noqa: E501
    for certificate_filename in (
            '{0}-cert.pub'.format(key_filename),
            '{0}.pub'.format(key_filename),
    ):
        if path.isfile(certificate_filename):
            key.load_certificate(certificate_filename)

    state.private_keys[key_filename] = key
    return key
Ejemplo n.º 4
0
def _run_server_ops(state, host, progress=None):
    '''
    Run all ops for a single server.
    '''

    logger.debug('Running all ops on {0}'.format(host))

    for op_hash in state.get_op_order():
        op_meta = state.op_meta[op_hash]

        logger.info('--> {0} {1} on {2}'.format(
            click.style('--> Starting operation:', 'blue'),
            click.style(', '.join(op_meta['names']), bold=True),
            click.style(host.name, bold=True),
        ))

        result = _run_server_op(state, host, op_hash)

        # Trigger CLI progress if provided
        if progress:
            progress((host, op_hash))

        if result is False:
            raise PyinfraError('Error in operation {0} on {1}'.format(
                ', '.join(op_meta['names']),
                host,
            ))

        if pyinfra.is_cli:
            print()
Ejemplo n.º 5
0
def get_file(state,
             host,
             remote_filename,
             filename_or_io,
             remote_temp_filename=None,
             **command_kwargs):
    raise PyinfraError("Not implemented")
Ejemplo n.º 6
0
def _run_server_ops(state, host, progress=None):
    name = host.name

    logger.debug('Running all ops on {0}'.format(name))

    for op_hash in state.op_order:
        op_meta = state.op_meta[op_hash]

        logger.info('--> {0} {1} on {2}'.format(
            click.style('--> Starting operation:', 'blue'),
            click.style(', '.join(op_meta['names']), bold=True),
            click.style(name, bold=True),
        ))

        result = _run_op(state, host, op_hash)

        # Trigger CLI progress if provided
        if progress:
            progress()

        if result is False:
            raise PyinfraError('Error in operation {0} on {1}'.format(
                ', '.join(op_meta['names']),
                name,
            ))

        if state.print_lines:
            print()
Ejemplo n.º 7
0
def _get_private_key(state, key_filename, key_password):
    if key_filename in state.private_keys:
        return state.private_keys[key_filename]

    ssh_key_filenames = [
        # Global from executed directory
        path.expanduser(key_filename),
    ]

    if state.cwd:
        # Relative to the CWD
        path.join(state.cwd, key_filename)

    key = False
    key_file_exists = False

    for filename in ssh_key_filenames:
        if not path.isfile(filename):
            continue

        key_file_exists = True

        try:
            key = _load_private_key_file(filename, key_filename, key_password)
            break
        except SSHException:
            pass

    # No break, so no key found
    if not key:
        if not key_file_exists:
            raise PyinfraError(
                "No such private key file: {0}".format(key_filename))
        raise PyinfraError(
            "Invalid private key file: {0}".format(key_filename))

    # Load any certificate, names from OpenSSH:
    # https://github.com/openssh/openssh-portable/blob/049297de975b92adcc2db77e3fb7046c0e3c695d/ssh-keygen.c#L2453  # noqa: E501
    for certificate_filename in (
            "{0}-cert.pub".format(key_filename),
            "{0}.pub".format(key_filename),
    ):
        if path.isfile(certificate_filename):
            key.load_certificate(certificate_filename)

    state.private_keys[key_filename] = key
    return key
Ejemplo n.º 8
0
def fake_docker_shell(command, splitlines=None):
    if command == 'docker run -d not-an-image sleep 10000':
        return ['containerid']

    elif command == 'docker commit containerid':
        return ['sha256:blahsomerandomstringdata']

    elif command == 'docker rm -f containerid':
        return []

    raise PyinfraError('Invalid command: {0}'.format(command))
Ejemplo n.º 9
0
def fake_docker_shell(command, splitlines=None):
    if command == "docker run -d not-an-image tail -f /dev/null":
        return ["containerid"]

    elif command == "docker commit containerid":
        return ["sha256:blahsomerandomstringdata"]

    elif command == "docker rm -f containerid":
        return []

    raise PyinfraError("Invalid command: {0}".format(command))
Ejemplo n.º 10
0
def fake_ssh_docker_shell(
    state,
    host,
    command,
    get_pty=False,
    timeout=None,
    stdin=None,
    success_exit_codes=None,
    print_output=False,
    print_input=False,
    return_combined_output=False,
    use_sudo_password=False,
    **command_kwargs,
):
    if host.data.ssh_hostname not in ("somehost", "anotherhost"):
        raise PyinfraError("Invalid host", host.data.ssh_hostname)

    if command == "docker run -d not-an-image tail -f /dev/null":
        return (True, ["containerid"], [])

    elif command == "docker commit containerid":
        return (True, ["sha256:blahsomerandomstringdata"], [])

    elif command == "docker rm -f containerid":
        return (True, [], [])

    elif str(command).startswith("rm -f"):
        return (True, [], [])

    # This is a bit messy. But it's easier than trying to swap out a mock
    # when it needs to be used...
    elif fake_ssh_docker_shell.custom_command:
        custom_command, status, stdout, stderr = fake_ssh_docker_shell.custom_command
        if str(command) == custom_command:
            fake_ssh_docker_shell.ran_custom_command = True
            return (status, stdout, stderr)

    raise PyinfraError("Invalid Command: {0}".format(command))
Ejemplo n.º 11
0
def include(filename):
    """
    Executes a local python file within the ``pyinfra.state.cwd``
    directory.
    """

    if not pyinfra.is_cli:
        raise PyinfraError("local.include is only available in CLI mode.")

    filename = get_file_path(state, filename)

    logger.debug("Including local file: %s", filename)

    config_state = config.get_current_state()

    try:
        # Fixes a circular import because `pyinfra.local` is really a CLI
        # only thing (so should be `pyinfra_cli.local`). It is kept here
        # to maintain backwards compatibility and the nicer public import
        # (ideally users never need to import from `pyinfra_cli`).

        from pyinfra_cli.util import exec_file

        with host.deploy(path.relpath(filename, state.cwd),
                         None,
                         None,
                         in_deploy=False):
            exec_file(filename)

        # One potential solution to the above is to add local as an actual
        # module, ie `pyinfra.operations.local`.

    except Exception as e:
        raise PyinfraError(
            "Could not include local file: {0}:\n{1}".format(filename, e), )

    finally:
        config.set_current_state(config_state)
Ejemplo n.º 12
0
def shell(commands,
          splitlines=False,
          ignore_errors=False,
          print_output=False,
          print_input=False):
    """
    Subprocess based implementation of pyinfra/api/ssh.py's ``run_shell_command``.

    Args:
        commands (string, list): command or list of commands to execute
        spltlines (bool): optionally have the output split by lines
        ignore_errors (bool): ignore errors when executing these commands
    """

    if isinstance(commands, str):
        commands = [commands]

    all_stdout = []

    # Checking for state context being set means this function works outside a deploy
    # e.g.: the vagrant connector.
    if ctx_state.isset():
        print_output = state.print_output
        print_input = state.print_input

    for command in commands:
        print_prefix = "localhost: "

        if print_input:
            click.echo("{0}>>> {1}".format(print_prefix, command), err=True)

        return_code, combined_output = run_local_process(
            command,
            print_output=print_output,
            print_prefix=print_prefix,
        )
        stdout, stderr = split_combined_output(combined_output)

        if return_code > 0 and not ignore_errors:
            raise PyinfraError(
                "Local command failed: {0}\n{1}".format(command, stderr), )

        all_stdout.extend(stdout)

    if not splitlines:
        return "\n".join(all_stdout)

    return all_stdout
Ejemplo n.º 13
0
def _run_server_ops(state, hostname):
    logger.debug('Running all ops on {}'.format(hostname))
    for op_hash in state.op_order:
        op_meta = state.op_meta[op_hash]

        logger.info('{0} {1} on {2}'.format(
            colored('Starting operation:', 'blue'),
            colored(', '.join(op_meta['names']), attrs=['bold']),
            colored(hostname, attrs=['bold'])))

        result = _run_op(state, hostname, op_hash)
        if result is False:
            raise PyinfraError('Error in operation {0} on {1}'.format(
                ', '.join(op_meta['names']), hostname))

        if state.print_lines:
            print()
Ejemplo n.º 14
0
def put_file(
    state, host, filename_or_io, remote_filename,
    **command_kwargs
):
    raise PyinfraError('Not implemented')
Ejemplo n.º 15
0
def fake_chroot_shell(command, splitlines=None):
    if command == 'chroot /not-a-chroot ls':
        return True

    raise PyinfraError('Invalid command: {0}'.format(command))