def make_inventory( inventory_filename, deploy_dir=None, limit=None, ssh_user=None, ssh_key=None, ssh_key_password=None, ssh_port=None, ssh_password=None, ): ''' Builds a ``pyinfra.api.Inventory`` from the filesystem. If the file does not exist and doesn't contain a / attempts to use that as the only hostname. ''' if ssh_port is not None: ssh_port = int(ssh_port) file_groupname = None try: attrs = exec_file(inventory_filename, return_locals=True) groups = { key: value for key, value in six.iteritems(attrs) if is_inventory_group(key, value) } # Used to set all the hosts to an additional group - that of the filename # ie inventories/dev.py means all the hosts are in the dev group, if not present file_groupname = path.basename(inventory_filename).split('.')[0] except IOError: # Otherwise we assume the inventory is actually a hostname or list of hostnames groups = { 'all': inventory_filename.split(','), } all_data = {} if 'all' in groups: all_hosts = groups.pop('all') if isinstance(all_hosts, tuple): all_hosts, all_data = all_hosts # Build all out of the existing hosts if not defined else: all_hosts = [] for hosts in groups.values(): # Groups can be a list of hosts or tuple of (hosts, data) hosts = hosts[0] if isinstance(hosts, tuple) else hosts for host in hosts: # Hosts can be a hostname or tuple of (hostname, data) hostname = host[0] if isinstance(host, tuple) else host if hostname not in all_hosts: all_hosts.append(hostname) groups['all'] = (all_hosts, all_data) # Apply the filename group if not already defined if file_groupname and file_groupname not in groups: groups[file_groupname] = all_hosts # In pyinfra an inventory is a combination of (hostnames + data). However, in CLI # mode we want to be define this in separate files (inventory / group data). The # issue is we want inventory access within the group data files - but at this point # we're not ready to make an Inventory. So here we just create a fake one, and # attach it to pseudo_inventory while we import the data files. logger.debug('Creating fake inventory...') fake_groups = { # In API mode groups *must* be tuples of (hostnames, data) name: group if isinstance(group, tuple) else (group, {}) for name, group in six.iteritems(groups) } fake_inventory = Inventory((all_hosts, all_data), **fake_groups) pseudo_inventory.set(fake_inventory) # Get all group data (group_data/*.py) group_data = get_group_data(deploy_dir) # Reset the pseudo inventory pseudo_inventory.reset() # For each group load up any data for name, hosts in six.iteritems(groups): data = {} if isinstance(hosts, tuple): hosts, data = hosts if name in group_data: data.update(group_data.pop(name)) # Attach to group object groups[name] = (hosts, data) # Loop back through any leftover group data and create an empty (for now) # group - this is because inventory @connectors can attach arbitrary groups # to hosts, so we need to support that. for name, data in six.iteritems(group_data): groups[name] = ([], data) # Apply any limit to all_hosts if limit: # Limits can be groups limit_groupname = limit if limit_groupname in groups: all_hosts = [ host[0] if isinstance(host, tuple) else host for host in groups[limit_groupname][0] ] # Or hostnames w/*wildcards else: limits = limit.split(',') all_hosts = [ host for host in all_hosts if (isinstance(host, tuple) and any( fnmatch(host[0], limit) for limit in limits)) or ( isinstance(host, six.string_types) and any( fnmatch(host, limit) for limit in limits)) ] # Reassign the all group w/limit groups['all'] = (all_hosts, all_data) return Inventory(groups.pop('all'), ssh_user=ssh_user, ssh_key=ssh_key, ssh_key_password=ssh_key_password, ssh_port=ssh_port, ssh_password=ssh_password, **groups), file_groupname and file_groupname.lower()
def make_inventory( inventory_filename, deploy_dir=None, ssh_port=None, ssh_user=None, ssh_key=None, ssh_key_password=None, ssh_password=None, winrm_username=None, winrm_password=None, winrm_port=None, ): ''' Builds a ``pyinfra.api.Inventory`` from the filesystem. If the file does not exist and doesn't contain a / attempts to use that as the only hostname. ''' if ssh_port is not None: ssh_port = int(ssh_port) file_groupname = None # If we're not a valid file we assume a list of comma separated hostnames if not path.exists(inventory_filename): groups = { 'all': inventory_filename.split(','), } else: groups = _get_groups_from_filename(inventory_filename) # Used to set all the hosts to an additional group - that of the filename # ie inventories/dev.py means all the hosts are in the dev group, if not present file_groupname = path.basename(inventory_filename).rsplit('.')[0] all_data = {} if 'all' in groups: all_hosts = groups.pop('all') if isinstance(all_hosts, tuple): all_hosts, all_data = all_hosts # Build all out of the existing hosts if not defined else: all_hosts = [] for hosts in groups.values(): # Groups can be a list of hosts or tuple of (hosts, data) hosts = hosts[0] if isinstance(hosts, tuple) else hosts for host in hosts: # Hosts can be a hostname or tuple of (hostname, data) hostname = host[0] if isinstance(host, tuple) else host if hostname not in all_hosts: all_hosts.append(hostname) groups['all'] = (all_hosts, all_data) # Apply the filename group if not already defined if file_groupname and file_groupname not in groups: groups[file_groupname] = all_hosts # In pyinfra an inventory is a combination of (hostnames + data). However, in CLI # mode we want to be define this in separate files (inventory / group data). The # issue is we want inventory access within the group data files - but at this point # we're not ready to make an Inventory. So here we just create a fake one, and # attach it to pseudo_inventory while we import the data files. logger.debug('Creating fake inventory...') fake_groups = { # In API mode groups *must* be tuples of (hostnames, data) name: group if isinstance(group, tuple) else (group, {}) for name, group in six.iteritems(groups) } fake_inventory = Inventory((all_hosts, all_data), **fake_groups) pseudo_inventory.set(fake_inventory) # Get all group data (group_data/*.py) group_data = _get_group_data(deploy_dir) # Reset the pseudo inventory pseudo_inventory.reset() # For each group load up any data for name, hosts in six.iteritems(groups): data = {} if isinstance(hosts, tuple): hosts, data = hosts if name in group_data: data.update(group_data.pop(name)) # Attach to group object groups[name] = (hosts, data) # Loop back through any leftover group data and create an empty (for now) # group - this is because inventory @connectors can attach arbitrary groups # to hosts, so we need to support that. for name, data in six.iteritems(group_data): groups[name] = ([], data) return Inventory(groups.pop('all'), ssh_user=ssh_user, ssh_key=ssh_key, ssh_key_password=ssh_key_password, ssh_port=ssh_port, ssh_password=ssh_password, winrm_username=winrm_username, winrm_password=winrm_password, winrm_port=winrm_port, **groups), file_groupname and file_groupname.lower()
def make_inventory(inventory_filename, override_data=None, cwd=None, group_data_directories=None): """ Builds a ``pyinfra.api.Inventory`` from the filesystem. If the file does not exist and doesn't contain a / attempts to use that as the only hostname. """ file_groupname = None # If we're not a valid file we assume a list of comma separated hostnames if not path.exists(inventory_filename): groups = { "all": inventory_filename.split(","), } else: groups = _get_groups_from_filename(inventory_filename) # Used to set all the hosts to an additional group - that of the filename # ie inventories/dev.py means all the hosts are in the dev group, if not present file_groupname = path.basename(inventory_filename).rsplit(".", 1)[0] all_data = {} if "all" in groups: all_hosts = groups.pop("all") if isinstance(all_hosts, tuple): all_hosts, all_data = all_hosts # Build all out of the existing hosts if not defined else: all_hosts = [] for hosts in groups.values(): # Groups can be a list of hosts or tuple of (hosts, data) hosts = hosts[0] if isinstance(hosts, tuple) else hosts for host in hosts: # Hosts can be a hostname or tuple of (hostname, data) hostname = host[0] if isinstance(host, tuple) else host if hostname not in all_hosts: all_hosts.append(hostname) groups["all"] = (all_hosts, all_data) # Apply the filename group if not already defined if file_groupname and file_groupname not in groups: groups[file_groupname] = all_hosts # In pyinfra an inventory is a combination of (hostnames + data). However, in CLI # mode we want to be define this in separate files (inventory / group data). The # issue is we want inventory access within the group data files - but at this point # we're not ready to make an Inventory. So here we just create a fake one, and # attach it to the inventory context while we import the data files. logger.debug("Creating fake inventory...") fake_groups = { # In API mode groups *must* be tuples of (hostnames, data) name: group if isinstance(group, tuple) else (group, {}) for name, group in groups.items() } fake_inventory = Inventory((all_hosts, all_data), **fake_groups) possible_group_data_folders = [cwd] inventory_dirname = path.abspath(path.dirname(inventory_filename)) if inventory_dirname != cwd: possible_group_data_folders.append(inventory_dirname) if group_data_directories: possible_group_data_folders.extend(group_data_directories) group_data = defaultdict(dict) with ctx_inventory.use(fake_inventory): for folder in possible_group_data_folders: for group_name, data in _get_group_data(folder).items(): group_data[group_name].update(data) # For each group load up any data for name, hosts in groups.items(): data = {} if isinstance(hosts, tuple): hosts, data = hosts if name in group_data: data.update(group_data.pop(name)) # Attach to group object groups[name] = (hosts, data) # Loop back through any leftover group data and create an empty (for now) # group - this is because inventory @connectors can attach arbitrary groups # to hosts, so we need to support that. for name, data in group_data.items(): groups[name] = ([], data) return ( Inventory(groups.pop("all"), override_data=override_data, **groups), file_groupname and file_groupname.lower(), )