Ejemplo n.º 1
0
def _find_start_docker_container(container_id):
    docker_info = local.shell(
        'docker container inspect {0}'.format(container_id))
    docker_info = json.loads(docker_info)[0]
    if docker_info['State']['Running'] is False:
        logger.info('Starting stopped container: {0}'.format(container_id))
        local.shell('docker container start {0}'.format(container_id))
Ejemplo n.º 2
0
def connect(state, host, **kwargs):
    logger.info('{0}{1}'.format(
        host.print_prefix,
        click.style('Ready', 'green'),
    ))

    return True
Ejemplo n.º 3
0
    def connect(self, for_fact=None, show_errors=True):
        self._check_state()
        if not self.connection:
            try:
                self.connection = self.executor.connect(self.state, self)
            except ConnectError as e:
                if show_errors:
                    log_message = '{0}{1}'.format(
                        self.print_prefix,
                        click.style(e.args[0], 'red'),
                    )
                    logger.error(log_message)
            else:
                log_message = '{0}{1}'.format(
                    self.print_prefix,
                    click.style('Connected', 'green'),
                )
                if for_fact:
                    log_message = '{0}{1}'.format(
                        log_message,
                        ' (for {0} fact)'.format(for_fact),
                    )

                logger.info(log_message)

        return self.connection
Ejemplo n.º 4
0
    def connect(self, reason=None, show_errors=True):
        self._check_state()
        if not self.connection:
            self.state.trigger_callbacks('host_before_connect', self)

            try:
                self.connection = self.executor.connect(self.state, self)
            except ConnectError as e:
                if show_errors:
                    log_message = '{0}{1}'.format(
                        self.print_prefix,
                        click.style(e.args[0], 'red'),
                    )
                    logger.error(log_message)

                self.state.trigger_callbacks('host_connect_error', self, e)
            else:
                log_message = '{0}{1}'.format(
                    self.print_prefix,
                    click.style('Connected', 'green'),
                )
                if reason:
                    log_message = '{0}{1}'.format(
                        log_message,
                        ' ({0})'.format(reason),
                    )

                logger.info(log_message)
                self.state.trigger_callbacks('host_connect', self)

        return self.connection
Ejemplo n.º 5
0
def print_results(state):
    for hostname, results in six.iteritems(state.results):
        if hostname not in state.inventory.connected_hosts:
            logger.info('[{0}]\tNo connection'.format(
                colored(hostname, 'red', attrs=['bold'])))

        else:
            meta = state.meta[hostname]
            success_ops = results['success_ops']
            error_ops = results['error_ops']

            # If all ops got complete (even with ignored_errors)
            if results['ops'] == meta['ops']:
                # Yellow if ignored any errors, else green
                color = 'green' if error_ops == 0 else 'yellow'
                host_string = colored(hostname, color)

            # Ops did not complete!
            else:
                host_string = colored(hostname, 'red', attrs=['bold'])

            logger.info(
                '[{0}]\tSuccessful: {1}\t    Errors: {2}\t    Commands: {3}/{4}'
                .format(
                    host_string, colored(success_ops, attrs=['bold']),
                    error_ops if error_ops == 0 else colored(
                        error_ops, 'red', attrs=['bold']), results['commands'],
                    meta['commands']))
Ejemplo n.º 6
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.º 7
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.º 8
0
    def connect(self, reason=None, show_errors=True, raise_exceptions=False):
        self._check_state()
        if not self.connection:
            self.state.trigger_callbacks("host_before_connect", self)

            try:
                self.connection = self.executor.connect(self.state, self)
            except ConnectError as e:
                if show_errors:
                    log_message = "{0}{1}".format(
                        self.print_prefix,
                        click.style(e.args[0], "red"),
                    )
                    logger.error(log_message)

                self.state.trigger_callbacks("host_connect_error", self, e)

                if raise_exceptions:
                    raise
            else:
                log_message = "{0}{1}".format(
                    self.print_prefix,
                    click.style("Connected", "green"),
                )
                if reason:
                    log_message = "{0}{1}".format(
                        log_message,
                        " ({0})".format(reason),
                    )

                logger.info(log_message)
                self.state.trigger_callbacks("host_connect", self)

        return self.connection
Ejemplo n.º 9
0
 def print_host_ready(host):
     logger.info(
         "{0}{1} {2}".format(
             host.print_prefix,
             click.style("Ready:", "green"),
             click.style(original_operations[0], bold=True),
         ),
     )
Ejemplo n.º 10
0
 def loop_hosts():
     # This actually does the op build
     for host in inventory:
         pseudo_host.set(host)
         exec_file(arguments['deploy'])
         logger.info('{0} {1}'.format(
             '[{}]'.format(colored(host.name, attrs=['bold'])),
             colored('Ready', 'green')))
Ejemplo n.º 11
0
def get_vagrant_config(limit=None):
    global VAGRANT_CONFIG

    if VAGRANT_CONFIG is None:
        logger.info('Getting vagrant config...')

        VAGRANT_CONFIG = _get_vagrant_config(limit=limit)

    return VAGRANT_CONFIG
Ejemplo n.º 12
0
def get_mech_config(limit=None):
    logger.info('Getting Mech config...')

    if limit and not isinstance(limit, (list, tuple)):
        limit = [limit]

    # Note: There is no "--machine-readable" option to 'mech status'
    with progress_spinner({'mech ls'}) as progress:
        output = local.shell(
            'mech ls',
            splitlines=True,
        )
        progress('mech ls')

    targets = []

    for line in output:

        address = ''

        data = line.split()
        target = data[0]

        if len(data) == 5:
            address = data[1]

        # Skip anything not in the limit
        if limit is not None and target not in limit:
            continue

        # For each vm that has an address, fetch it's SSH config in a thread
        if address != '' and address[0].isdigit():
            targets.append(target)

    threads = []
    config_queue = Queue()

    with progress_spinner(targets) as progress:
        for target in targets:
            thread = Thread(
                target=_get_mech_ssh_config,
                args=(config_queue, progress, target),
            )
            threads.append(thread)
            thread.start()

    for thread in threads:
        thread.join()

    queue_items = list(config_queue.queue)

    lines = []
    for output in queue_items:
        lines.extend(output)

    return lines
Ejemplo n.º 13
0
def connect(state, host, **kwargs):
    '''
    Connect to a single host. Returns the SSH client if succesful. Stateless by
    design so can be run in parallel.
    '''

    logger.debug('Connecting to: {0} ({1})'.format(host.name, kwargs))

    name = host.name
    hostname = host.data.ssh_hostname or name

    try:
        # Create new client & connect to the host
        client = SSHClient()
        client.set_missing_host_key_policy(MissingHostKeyPolicy())
        client.connect(hostname, **kwargs)

        # Enable SSH forwarding
        session = client.get_transport().open_session()
        AgentRequestHandler(session)

        # Log
        logger.info('{0}{1}'.format(
            host.print_prefix,
            click.style('Connected', 'green'),
        ))

        return client

    except AuthenticationException as e:
        auth_kwargs = {}

        for key, value in kwargs.items():
            if key in ('username', 'password'):
                auth_kwargs[key] = value
                continue

            if key == 'pkey' and value:
                auth_kwargs['key'] = host.data.ssh_key

        auth_args = ', '.join('{0}={1}'.format(key, value)
                              for key, value in auth_kwargs.items())

        _log_connect_error(host, 'Authentication error', auth_args)

    except SSHException as e:
        _log_connect_error(host, 'SSH error', e)

    except gaierror:
        _log_connect_error(host, 'Could not resolve hostname', hostname)

    except socket_error as e:
        _log_connect_error(host, 'Could not connect', e)

    except EOFError as e:
        _log_connect_error(host, 'EOF error', e)
Ejemplo n.º 14
0
 def load_file(local_host):
     with ctx_config.use(state.config.copy()):
         with ctx_host.use(local_host):
             exec_file(filename)
             logger.info(
                 "{0}{1} {2}".format(
                     local_host.print_prefix,
                     click.style("Ready:", "green"),
                     click.style(filename, bold=True),
                 ),
             )
Ejemplo n.º 15
0
def print_meta(state, inventory):
    group_combinations = _get_group_combinations(inventory)

    for i, (groups, hosts) in enumerate(six.iteritems(group_combinations), 1):
        if groups:
            logger.info('Groups: {0}'.format(
                click.style(' / '.join(groups), bold=True), ))
        else:
            logger.info('Ungrouped:')

        for host in hosts:
            meta = state.meta[host.name]

            # Didn't connect to this host?
            if host.name not in state.connected_hosts:
                logger.info('[{0}]\tNo connection'.format(
                    click.style(host.name, 'red', bold=True), ))
                continue

            logger.info(
                '[{0}]\tOperations: {1}\t    Commands: {2}'.format(
                    click.style(host.name, bold=True),
                    meta['ops'],
                    meta['commands'],
                ), )

        if i != len(group_combinations):
            print()
Ejemplo n.º 16
0
Archivo: ssh.py Proyecto: ge-fa/pyinfra
def connect(state, host, **kwargs):
    '''
    Connect to a single host. Returns the SSH client if succesful. Stateless by
    design so can be run in parallel.
    '''

    logger.debug('Connecting to: {0} ({1})'.format(host.name, kwargs))

    name = host.name
    hostname = host.data.ssh_hostname or name

    try:
        # Create new client & connect to the host
        client = SSHClient()
        client.set_missing_host_key_policy(MissingHostKeyPolicy())
        client.connect(hostname, **kwargs)

        # Enable SSH forwarding
        session = client.get_transport().open_session()
        AgentRequestHandler(session)

        # Log
        logger.info('{0}{1}'.format(
            host.print_prefix,
            click.style('Connected', 'green'),
        ))

        return client

    except AuthenticationException as e:
        logger.error('Auth error on: {0}, {1}'.format(name, e))

    except SSHException as e:
        logger.error('SSH error on: {0}, {1}'.format(name, e))

    except gaierror:
        if hostname == name:
            logger.error('Could not resolve {0}'.format(name))
        else:
            logger.error('Could not resolve for {0} (SSH host: {1})'.format(
                name, hostname))

    except socket_error as e:
        logger.error(
            'Could not connect: {0}:{1}, {2}'.format(name,
                                                     kwargs.get('port', 22),
                                                     e), )

    except EOFError as e:
        logger.error('EOF error connecting to {0}: {1}'.format(name, e))
Ejemplo n.º 17
0
def get_vagrant_config(limit=None):
    logger.info("Getting Vagrant config...")

    if limit and not isinstance(limit, (list, tuple)):
        limit = [limit]

    with progress_spinner({"vagrant status"}) as progress:
        output = local.shell(
            "vagrant status --machine-readable",
            splitlines=True,
        )
        progress("vagrant status")

    targets = []

    for line in output:
        line = line.strip()
        _, target, type_, data = line.split(",", 3)

        # Skip anything not in the limit
        if limit is not None and target not in limit:
            continue

        # For each running container - fetch it's SSH config in a thread - this
        # is because Vagrant *really* slow to run each command.
        if type_ == "state" and data == "running":
            targets.append(target)

    threads = []
    config_queue = Queue()

    with progress_spinner(targets) as progress:
        for target in targets:
            thread = Thread(
                target=_get_vagrant_ssh_config,
                args=(config_queue, progress, target),
            )
            threads.append(thread)
            thread.start()

    for thread in threads:
        thread.join()

    queue_items = list(config_queue.queue)

    lines = []
    for output in queue_items:
        lines.extend([ln.strip() for ln in output])

    return lines
Ejemplo n.º 18
0
def _log_operation_start(op_meta):
    op_types = []
    if op_meta['serial']:
        op_types.append('serial')
    if op_meta['run_once']:
        op_types.append('run once')

    logger.info('{0} {1} {2}'.format(
        click.style(
            '--> Starting{0}operation:'.format(
                ' {0} '.format(', '.join(op_types)) if op_types else ' ', ),
            'blue'),
        click.style(', '.join(op_meta['names']), bold=True),
        tuple(op_meta['args']) if op_meta['args'] else '',
    ))
Ejemplo n.º 19
0
def disconnect(state, host):
    container_id = host.host_data['docker_container_id'][:12]

    with progress_spinner({'docker commit'}):
        image_id = local.shell(
            'docker commit {0}'.format(container_id),
            splitlines=True,
        )[-1][7:19]  # last line is the image ID, get sha256:[XXXXXXXXXX]...

    with progress_spinner({'docker rm'}):
        local.shell('docker rm -f {0}'.format(container_id), )

    logger.info('{0}docker build complete, image ID: {1}'.format(
        host.print_prefix,
        click.style(image_id, bold=True),
    ))
Ejemplo n.º 20
0
def connect(state, host, for_fact=None):
    # Log
    log_message = '{0}{1}'.format(
        host.print_prefix,
        click.style('Connected', 'green'),
    )

    if for_fact:
        log_message = '{0}{1}'.format(
            log_message,
            ' (for {0} fact)'.format(for_fact),
        )

    logger.info(log_message)

    return True
Ejemplo n.º 21
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.º 22
0
def get_ansible_inventory(inventory_filename=None):
    if not inventory_filename:  # pragma: no cover
        raise InventoryError('No Ansible inventory filename provided!')

    if not path.exists(inventory_filename):
        raise InventoryError(('Could not find Ansible inventory file: {0}'
                              ).format(inventory_filename))

    logger.info('Parsing Ansible inventory...')

    config = ConfigParser(
        delimiters=(' '),  # we only handle the hostnames for now
        allow_no_value=True,  # we don't by default have = values
        interpolation=None,  # remove any Python interpolation
    )
    config.read(inventory_filename)
    return config
Ejemplo n.º 23
0
def load_deploy_file(state, filename):
    state.current_deploy_filename = filename

    # Copy the inventory hosts (some might be removed during deploy)
    hosts = list(state.inventory.iter_active_hosts())

    for host in hosts:
        pseudo_host.set(host)

        exec_file(filename)

        logger.info('{0}{1} {2}'.format(
            host.print_prefix,
            click.style('Ready:', 'green'),
            click.style(filename, bold=True),
        ))

    # Remove any pseudo host
    pseudo_host.reset()
Ejemplo n.º 24
0
def disconnect(state, host):
    container_id = host.host_data["docker_container_id"][:12]

    with progress_spinner({"docker commit"}):
        image_id = ssh.run_shell_command(
            state, host, "docker commit {0}".format(container_id))[1][-1][
                7:19]  # last line is the image ID, get sha256:[XXXXXXXXXX]...

    with progress_spinner({"docker rm"}):
        ssh.run_shell_command(
            state,
            host,
            "docker rm -f {0}".format(container_id),
        )

    logger.info(
        "{0}docker build complete, image ID: {1}".format(
            host.print_prefix,
            click.style(image_id, bold=True),
        ), )
Ejemplo n.º 25
0
def load_deploy_file(state, filename):
    # Copy the inventory hosts (some might be removed during deploy)
    hosts = list(state.inventory)

    for host in hosts:
        if not state.is_host_in_limit(host):
            continue

        pseudo_host.set(host)

        exec_file(filename)

        logger.info('{0}{1} {2}'.format(
            host.print_prefix,
            click.style('Ready:', 'green'),
            click.style(filename, bold=True),
        ))

    # Remove any pseudo host
    pseudo_host.reset()
Ejemplo n.º 26
0
def load_deploy_file(state, filename, progress):
    for host in state.inventory:
        pseudo_host.set(host)

        exec_file(filename)

        state.ready_host(host)
        progress()

        logger.info('{0} {1} {2}'.format(
            '[{}]'.format(click.style(host.name, bold=True)),
            click.style('Ready:', 'green'),
            click.style(filename, bold=True),
        ))

    # Remove any pseudo host
    pseudo_host.reset()

    # Un-ready the hosts - this is so that any hooks or callbacks during the
    # deploy can still use facts as expected.
    state.ready_host_names = set()
Ejemplo n.º 27
0
def load_ansible_ini_inventory(inventory_filename):
    logger.info('Trying Ansible inventory format...')

    config = ConfigParser(
        delimiters=(' '),  # we only handle the hostnames for now
        allow_no_value=True,  # we don't by default have = values
        interpolation=None,  # remove any Python interpolation
    )
    config.read(inventory_filename)

    groups = {}

    # First pass - load hosts/groups of hosts
    for section in config.sections():
        if ':' in section:  # ignore :children and :vars sections this time
            continue

        all_hosts = []
        options = config.options(section)
        for option in options:
            all_hosts.extend(_parse_ansible_hosts(options))

        groups[section] = all_hosts

    # Second pass - load any children groups
    for section in config.sections():
        if not section.endswith(
                ':children'):  # we only support :children for now
            continue

        group_name = section.replace(':children', '')

        all_hosts = []
        options = config.options(section)
        for option in options:
            all_hosts.extend(groups[option])

        groups[group_name] = all_hosts

    return groups
Ejemplo n.º 28
0
def load_deploy_file(state, filename):
    # Copy the inventory hosts (some might be removed during deploy)
    hosts = list(state.inventory)

    for host in hosts:
        # Don't load for anything within our (top level, --limit) limit
        if (isinstance(state.limit_hosts, list)
                and host not in state.limit_hosts):
            continue

        pseudo_host.set(host)

        exec_file(filename)

        logger.info('{0}{1} {2}'.format(
            host.print_prefix,
            click.style('Ready:', 'green'),
            click.style(filename, bold=True),
        ))

    # Remove any pseudo host
    pseudo_host.reset()
Ejemplo n.º 29
0
def log_operation_start(op_meta, op_types=None, prefix="--> "):
    op_types = op_types or []
    if op_meta["serial"]:
        op_types.append("serial")
    if op_meta["run_once"]:
        op_types.append("run once")

    args = ""
    if op_meta["args"]:
        args = "({0})".format(", ".join(str(arg) for arg in op_meta["args"]))

    logger.info(
        "{0} {1} {2}".format(
            click.style(
                "{0}Starting{1}operation:".format(
                    prefix,
                    " {0} ".format(", ".join(op_types)) if op_types else " ",
                ),
                "blue",
            ),
            click.style(", ".join(op_meta["names"]), bold=True),
            args,
        ),
    )
Ejemplo n.º 30
0
def print_results(state, inventory):
    group_combinations = _get_group_combinations(inventory)

    for i, (groups, hosts) in enumerate(six.iteritems(group_combinations), 1):
        if groups:
            logger.info('Groups: {0}'.format(
                click.style(' / '.join(groups), bold=True), ))
        else:
            logger.info('Ungrouped:')

        for host in hosts:
            # Didn't conenct to this host?
            if host.name not in state.connected_hosts:
                logger.info('[{0}]\tNo connection'.format(
                    click.style(host.name, 'red', bold=True), ))
                continue

            results = state.results[host.name]

            meta = state.meta[host.name]
            success_ops = results['success_ops']
            error_ops = results['error_ops']

            # If all ops got complete (even with ignored_errors)
            if results['ops'] == meta['ops']:
                # Yellow if ignored any errors, else green
                color = 'green' if error_ops == 0 else 'yellow'
                host_string = click.style(host.name, color)

            # Ops did not complete!
            else:
                host_string = click.style(host.name, 'red', bold=True)

            logger.info(
                '[{0}]\tSuccessful: {1}\t    Errors: {2}\t    Commands: {3}/{4}'
                .format(
                    host_string,
                    click.style(six.text_type(success_ops), bold=True),
                    error_ops if error_ops == 0 else click.style(
                        six.text_type(error_ops), 'red', bold=True),
                    results['commands'],
                    meta['commands'],
                ))

        if i != len(group_combinations):
            print()