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
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)
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)
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
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)
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
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)