Ejemplo n.º 1
0
def main():
    """Check Cumin aliases for inconsistencies.

    Note:
    Those are the performed checks
      - each alias should return some hosts.
      - the sum of all DC-related aliases should return all hosts.
      - the sum of all the other aliases should return all hosts.

    Returns:
        int: zero on success, positive integer on failure.

    """
    ret = 0
    config = Config()
    dc_hosts = NodeSet()
    alias_hosts = NodeSet()
    all_hosts = query.Query(config).execute('*')

    for alias in config['aliases']:
        try:
            match = query.Query(config).execute('A:' + alias)
        except InvalidQueryError as e:
            print('Unable to execute query for alias {alias}: {msg}'.format(
                alias=alias, msg=e))
            ret = 1
            continue

        if not match:
            print('Alias {alias} matched 0 hosts'.format(alias=alias))
            ret = 1

        if alias in DCS:
            dc_hosts |= match
        else:
            alias_hosts |= match

        time.sleep(2)  # Go gentle on PuppetDB

    base_ret = 2
    for hosts, name in ((dc_hosts, 'DC'), (alias_hosts, 'Other')):
        if all_hosts - hosts:
            print('{name} aliases do not cover all hosts: {hosts}'.format(
                name=name, hosts=(all_hosts - hosts)))
            ret += base_ret
        elif dc_hosts - all_hosts:
            print('{name} aliases have unknown hosts: {hosts}'.format(
                name=name, hosts=(hosts - all_hosts)))
            ret += base_ret * 2

        base_ret *= 4

    return ret
Ejemplo n.º 2
0
def run_cumin(label, hosts_query, commands, timeout=30, installer=False, ignore_exit=False):
    """Run a remote command via Cumin.

    Arguments:
    label       -- label to identify the caller in messages and logs
    hosts_query -- the query for the hosts selection to pass to cumin
    commands    -- the list of commands to be executed
    timeout     -- a timeout in seconds for each command. [optional, default: 30]
    installer   -- whether the host will reboot into the installer or not,
    """
    if installer:
        config = cumin_config_installer
        if 'SSH_AUTH_SOCK' in os.environ:
            del os.environ['SSH_AUTH_SOCK']
    else:
        config = cumin_config

    hosts = query.Query(config).execute(hosts_query)
    target = transports.Target(hosts)
    worker = transport.Transport.new(config, target)

    ok_codes = None
    if ignore_exit:
        ok_codes = []
    worker.commands = [transports.Command(command, timeout=timeout, ok_codes=ok_codes)
                       for command in commands]
    worker.handler = 'async'
    exit_code = worker.execute()

    if exit_code != 0:
        raise RuntimeError('Failed to {label}'.format(label=label))

    return exit_code, worker
    def run(self, host, command):
        hosts = query.Query(self.config).execute(host)
        if not hosts:
            return CommandReturn(1, None, "host is wrong or does not match rules")
        target = transports.Target(hosts)
        worker = transport.Transport.new(self.config, target)
        worker.commands = [self.format_command(command)]
        worker.handler = "sync"

        # If verbose is false, suppress stdout and stderr of Cumin.
        if self.options.get("verbose", False):
            return_code = worker.execute()
        else:
            # Temporary workaround until Cumin has full support to suppress output (T212783).
            stdout = transports.clustershell.sys.stdout
            stderr = transports.clustershell.sys.stderr
            try:
                with open(os.devnull, "w") as discard_output:
                    transports.clustershell.sys.stdout = discard_output
                    transports.clustershell.sys.stderr = discard_output
                    return_code = worker.execute()
            finally:
                transports.clustershell.sys.stdout = stdout
                transports.clustershell.sys.stderr = stderr

        for nodes, output in worker.get_results():
            if host in nodes:
                result = str(bytes(output), "utf-8")
                return CommandReturn(return_code, result, None)

        return CommandReturn(return_code, None, None)
Ejemplo n.º 4
0
def get_all_hosts(projects):
    """
    Return the Cumin query with the list of projects that have NFS configured
    :param projects: set of projects to gather hosts for
    :return String
    """
    config = cumin.Config()
    projects_q = ["O{{project:{}}}".format(project) for project in projects]
    cumin_query = "({})".format(" or ".join(projects_q))
    return query.Query(config).execute(cumin_query)
Ejemplo n.º 5
0
def main():
    """Check Cumin aliases for inconsistencies.

    Note:
    Those are the performed checks
      - each alias should return some hosts, unless listed in OPTIONAL_ALIASES.
      - the sum of all DC-related aliases should return all hosts.
      - the sum of all the other aliases should return all hosts.

    """
    config = Config()
    dc_hosts = NodeSet()
    alias_hosts = NodeSet()
    all_hosts = query.Query(config).execute('*')

    for alias in config['aliases']:
        try:
            match = query.Query(config).execute('A:' + alias)
        except InvalidQueryError as e:
            print('Unable to execute query for alias {alias}: {msg}'.format(
                alias=alias, msg=e))
            continue

        if not match and alias not in OPTIONAL_ALIASES:
            print('Alias {alias} matched 0 hosts'.format(alias=alias))

        if alias in DCS:
            dc_hosts |= match
        else:
            alias_hosts |= match

        time.sleep(2)  # Go gentle on PuppetDB

    for hosts, name in ((dc_hosts, 'DC'), (alias_hosts, 'Other')):
        if all_hosts - hosts:
            print('{name} aliases do not cover all hosts: {hosts}'.format(
                name=name, hosts=(all_hosts - hosts)))
        elif dc_hosts - all_hosts:
            print('{name} aliases have unknown hosts: {hosts}'.format(
                name=name, hosts=(hosts - all_hosts)))

    return 0
Ejemplo n.º 6
0
    def run(self, host, command):
        hosts = query.Query(self.config).execute(host)
        target = transports.Target(hosts)
        worker = transport.Transport.new(self.config, target)
        worker.commands = [self.format_command(command)]
        worker.handler = 'sync'
        return_code = worker.execute()
        for nodes, output in worker.get_results():
            if host in nodes:
                result = str(bytes(output), 'utf-8')
                return CommandReturn(return_code, result, None)

        return CommandReturn(return_code, None, None)
Ejemplo n.º 7
0
def get_hosts(args, config):
    """Resolve the hosts selection into a list of hosts and return it. Raises KeyboardInterruptError.

    Arguments:
        args: ArgumentParser instance with parsed command line arguments
        config: a dictionary with the parsed configuration file

    """
    hosts = query.Query(config).execute(args.hosts)

    if not hosts:
        stderr('No hosts found that matches the query')
        return hosts

    stderr('{num} hosts will be targeted:'.format(num=len(hosts)))
    stderr(Colored.cyan(cumin.nodeset_fromlist(hosts)))

    if args.dry_run:
        stderr('DRY-RUN mode enabled, aborting')
        return []

    if args.force:
        stderr('FORCE mode enabled, continuing without confirmation')
        return hosts

    if not sys.stdout.isatty():  # pylint: disable=no-member
        message = 'Not in a TTY but neither DRY-RUN nor FORCE mode were specified.'
        stderr(message)
        raise cumin.CuminError(message)

    for i in range(10):
        stderr('Confirm to continue [y/n]?', end=' ')
        answer = input()  # nosec
        if not answer:
            continue

        if answer in 'yY':
            break
        if answer in 'nN':
            raise KeyboardInterruptError

    else:
        stderr('Got invalid answer for {i} times'.format(i=i))
        raise KeyboardInterruptError

    return hosts
Ejemplo n.º 8
0
def get_all_hosts(share):
    """
    Return the Cumin query with the list of projects that have NFS configured
    :param share: NFS Share to filter for
    :return String
    """
    config = cumin.Config()

    with open(NFS_MOUNT_FILE, 'r') as f:
        nfs_config = yaml.safe_load(f)

    projects = []

    for project, mounts in nfs_config['private'].items():
        if share == 'all' or share in mounts['mounts']:
            projects.append('O{project:%s}' % project)

    cumin_query = '({})'.format(' or '.join(projects))
    return query.Query(config).execute(cumin_query)
    def query(self,
              query_string: str,
              use_sudo: bool = False) -> "RemoteHosts":
        """Execute a Cumin query and return the matching hosts.

        Arguments:
            query_string (str): the Cumin query string to execute.
            use_sudo (bool): If True will prepend 'sudo -i' to every command.

        Returns:
            spicerack.remote.RemoteHosts: RemoteHosts instance matching the given query.

        """
        # TODO: Revisit the current implementation of sudo once Cumin has native support for it.
        try:
            hosts = query.Query(self._config).execute(query_string)
        except CuminError as e:
            raise RemoteError("Failed to execute Cumin query") from e

        return RemoteHosts(self._config,
                           hosts,
                           dry_run=self._dry_run,
                           use_sudo=use_sudo)