async def init_hosts(**kwargs): """Process list of devices to gather data from. This involves creating a node for each device listed, and connecting to those devices and initializing state about those devices """ nodes = {} inventory = kwargs.pop('inventory', None) if not inventory: ans_inventory = kwargs.pop('ans_inventory', None) else: _ = kwargs.pop('ans_inventory', None) namespace = kwargs.pop('namespace', 'default') passphrase = kwargs.pop('passphrase', None) ssh_config_file = kwargs.pop('ssh_config_file', None) jump_host = kwargs.pop('jump_host', None) ignore_known_hosts = kwargs.pop('ignore_known_hosts', False) if kwargs: logger.error(f'Received unrecognized keywords {kwargs}, aborting') sys.exit(1) if inventory: hostsconf = get_hostsdata_from_hostsfile(inventory) else: hostsconf = yaml.safe_load('\n'.join( convert_ansible_inventory(ans_inventory, namespace))) if not hostsconf: logger.error("No hosts specified in inventory file") print("ERROR: No hosts specified in inventory file") sys.exit(1) for namespace in hostsconf: if "namespace" not in namespace: logger.warning('No namespace specified, assuming "default"') nsname = "default" else: nsname = namespace["namespace"] tasks = [] for host in namespace.get("hosts", []): entry = host.get("url", None) if entry: words = entry.split() result = urlparse(words[0]) username = result.username password = result.password or "vagrant" port = result.port host = result.hostname devtype = None keyfile = None for i in range(1, len(words[1:]) + 1): if words[i].startswith('keyfile'): keyfile = words[i].split("=")[1] elif words[i].startswith('devtype'): devtype = words[i].split("=")[1] newnode = Node() tasks += [ newnode._init( address=host, username=username, port=port, password=password, passphrase=passphrase, transport=result.scheme, devtype=devtype, ssh_keyfile=keyfile, ssh_config_file=ssh_config_file, jump_host=jump_host, namespace=nsname, ignore_known_hosts=ignore_known_hosts, ) ] if not tasks: logger.error("No hosts detected in provided inventory file") return [] for f in asyncio.as_completed(tasks): newnode = await f if newnode.devtype is None: logger.error( "Unable to determine device type for {}".format(host)) else: logger.info(f"Added node {newnode.hostname}") nodes.update({"{}.{}".format(nsname, newnode.hostname): newnode}) return nodes
async def init_hosts(**kwargs): """Process list of devices to gather data from. This involves creating a node for each device listed, and connecting to those devices and initializing state about those devices """ nodes = {} inventory = kwargs.pop('inventory', None) if not inventory: ans_inventory = kwargs.pop('ans_inventory', None) else: _ = kwargs.pop('ans_inventory', None) ans_inventory = None namespace = kwargs.pop('namespace', 'default') passphrase = kwargs.pop('passphrase', None) ssh_config_file = kwargs.pop('ssh_config_file', None) jump_host = kwargs.pop('jump_host', None) jump_host_key_file = kwargs.pop('jump_host_key_file', None) ignore_known_hosts = kwargs.pop('ignore_known_hosts', False) user_password = kwargs.pop('password', None) if kwargs: logger.error(f'Received unrecognized keywords {kwargs}, aborting') sys.exit(1) if inventory: hostsconf = get_hostsdata_from_hostsfile(inventory) else: hostsconf = yaml.safe_load('\n'.join( convert_ansible_inventory(ans_inventory, namespace))) if not hostsconf: logger.error("No hosts specified in inventory file") print("ERROR: No hosts specified in inventory file") sys.exit(1) if jump_host_key_file: if not jump_host: logger.error("Jump host key file specified without jump host") print("ERROR: Jump host key file specified without jump host") sys.exit(1) else: if not os.access(jump_host_key_file, os.F_OK): logger.error( f"Jump host key file {jump_host_key_file} does not exist") print(f"ERROR: Jump host key file {jump_host_key_file} " f"does not exist") sys.exit(1) if not os.access(jump_host_key_file, os.R_OK): logger.error( f"Jump host key file {jump_host_key_file} not readable") print(f"ERROR: Jump host key file {jump_host_key_file} " f"not readable") sys.exit(1) for namespace in hostsconf: nsname = namespace["namespace"] tasks = [] hostlist = namespace.get("hosts", []) if not hostlist: logger.error(f'No hosts in namespace {nsname}') continue for host in hostlist: if not isinstance(host, dict): logger.error(f'Ignoring invalid host specification: {host}') continue entry = host.get("url", None) if entry: words = entry.split() result = urlparse(words[0]) username = result.username password = result.password or user_password or "vagrant" port = result.port host = result.hostname devtype = None keyfile = None try: for i in range(1, len(words[1:]) + 1): if words[i].startswith('keyfile'): keyfile = words[i].split("=")[1] elif words[i].startswith('devtype'): devtype = words[i].split("=")[1] elif words[i].startswith('username'): username = words[i].split("=")[1] elif words[i].startswith('password'): password = words[i].split("=")[1] except IndexError: logger.error(f'Invalid key/value {words}, missing "="') logger.error(f'Ignoring node {host}') continue newnode = Node() tasks += [ newnode._init( address=host, username=username, port=port, password=password, passphrase=passphrase, transport=result.scheme, devtype=devtype, ssh_keyfile=keyfile, ssh_config_file=ssh_config_file, jump_host=jump_host, jump_host_key_file=jump_host_key_file, namespace=nsname, ignore_known_hosts=ignore_known_hosts, ) ] else: logger.error(f'Ignoring invalid host specification: {entry}') if not tasks: logger.error("No hosts detected in provided inventory file") return [] for f in asyncio.as_completed(tasks): newnode = await f if newnode.devtype is None: logger.error( "Unable to determine device type for {}:{}".format( newnode.address, newnode.port)) else: logger.info(f"Added node {newnode.hostname}:{newnode.port}") nodes.update({"{}.{}".format(nsname, newnode.hostname): newnode}) return nodes