def __init__(self, host_list=C.DEFAULT_HOST_LIST): # the host file file, or script path, or list of hosts # if a list, inventory data will NOT be loaded self.host_list = host_list # caching to avoid repeated calculations, particularly with # external inventory scripts. self._vars_per_host = {} self._vars_per_group = {} self._hosts_cache = {} self._groups_list = {} # to be set by calling set_playbook_basedir by ansible-playbook self._playbook_basedir = None # the inventory object holds a list of groups self.groups = [] # a list of host(names) to contain current inquiries to self._restriction = None self._also_restriction = None self._subset = None if isinstance(host_list, basestring): if "," in host_list: host_list = host_list.split(",") host_list = [h for h in host_list if h and h.strip()] if isinstance(host_list, list): self.parser = None all = Group('all') self.groups = [all] for x in host_list: if ":" in x: tokens = x.split(":", 1) all.add_host(Host(tokens[0], tokens[1])) else: all.add_host(Host(x)) elif os.path.exists(host_list): if os.path.isdir(host_list): # Ensure basedir is inside the directory self.host_list = os.path.join(self.host_list, "") self.parser = InventoryDirectory(filename=host_list) self.groups = self.parser.groups.values() elif utils.is_executable(host_list): self.parser = InventoryScript(filename=host_list) self.groups = self.parser.groups.values() else: self.parser = InventoryParser(filename=host_list) self.groups = self.parser.groups.values() utils.plugins.vars_loader.add_directory(self.basedir(), with_subdir=True) else: raise errors.AnsibleError( "Unable to find an inventory file, specify one with -i ?") self._vars_plugins = [x for x in utils.plugins.vars_loader.all(self)]
def __init__(self, host_list=C.DEFAULT_HOST_LIST): # the host file file, or script path, or list of hosts # if a list, inventory data will NOT be loaded self.host_list = host_list # caching to avoid repeated calculations, particularly with # external inventory scripts. self._vars_per_host = {} self._vars_per_group = {} self._hosts_cache = {} self._groups_list = {} # the inventory object holds a list of groups self.groups = [] # a list of host(names) to contain current inquiries to self._restriction = None self._also_restriction = None self._subset = None if type(host_list) in [ str, unicode ]: if host_list.find(",") != -1: host_list = host_list.split(",") host_list = [ h for h in host_list if h and h.strip() ] if type(host_list) == list: self.parser = None all = Group('all') self.groups = [ all ] for x in host_list: if x.find(":") != -1: tokens = x.split(":",1) all.add_host(Host(tokens[0], tokens[1])) else: all.add_host(Host(x)) elif os.path.exists(host_list): if os.path.isdir(host_list): # Ensure basedir is inside the directory self.host_list = os.path.join(self.host_list, "") self.parser = InventoryDirectory(filename=host_list) self.groups = self.parser.groups.values() elif utils.is_executable(host_list): self.parser = InventoryScript(filename=host_list) self.groups = self.parser.groups.values() else: data = file(host_list).read() if not data.startswith("---"): self.parser = InventoryParser(filename=host_list) self.groups = self.parser.groups.values() else: raise errors.AnsibleError("YAML inventory support is deprecated in 0.6 and removed in 0.7, see the migration script in examples/scripts in the git checkout") utils.plugins.vars_loader.add_directory(self.basedir(), with_subdir=True) else: raise errors.AnsibleError("Unable to find an inventory file, specify one with -i ?") self._vars_plugins = [ x for x in utils.plugins.vars_loader.all(self) ]
def get_file_parser(hostsfile, groups, loader): # check to see if the specified file starts with a # shebang (#!/), so if an error is raised by the parser # class we can show a more apropos error shebang_present = False processed = False myerr = [] parser = None try: inv_file = open(hostsfile) first_line = inv_file.readlines()[0] inv_file.close() if first_line.startswith('#!'): shebang_present = True except: pass #FIXME: make this 'plugin loop' # script if loader.is_executable(hostsfile): try: parser = InventoryScript(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: myerr.append(str(e)) elif shebang_present: myerr.append( "The file %s looks like it should be an executable inventory script, but is not marked executable. Perhaps you want to correct this with `chmod +x %s`?" % (hostsfile, hostsfile)) # YAML/JSON if not processed and not shebang_present and os.path.splitext( hostsfile)[-1] in C.YAML_FILENAME_EXTENSIONS: try: parser = InventoryYAMLParser(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: myerr.append(str(e)) # ini if not processed and not shebang_present: try: parser = InventoryINIParser(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: myerr.append(str(e)) if not processed and myerr: raise AnsibleError('\n'.join(myerr)) return parser
def __init__(self, filename=C.DEFAULT_HOST_LIST): self.names = os.listdir(filename) self.names.sort() self.directory = filename self.parsers = [] self.hosts = {} self.groups = {} for i in self.names: if i.endswith("~") or i.endswith(".orig") or i.endswith(".bak"): continue if i.endswith(".ini"): # configuration file for an inventory script continue if i.endswith(".retry"): # this file is generated on a failed playbook and should only be # used when run specifically continue # Skip hidden files if i.startswith('.') and not i.startswith('./'): continue # These are things inside of an inventory basedir if i in ("host_vars", "group_vars", "vars_plugins"): continue fullpath = os.path.join(self.directory, i) if os.path.isdir(fullpath): parser = InventoryDirectory(filename=fullpath) elif utils.is_executable(fullpath): parser = InventoryScript(filename=fullpath) else: parser = InventoryParser(filename=fullpath) self.parsers.append(parser) # This takes a lot of code because we can't directly use any of the objects, as they have to blend for name, group in parser.groups.iteritems(): if name not in self.groups: self.groups[name] = group else: # group is already there, copy variables # note: depth numbers on duplicates may be bogus for k, v in group.get_variables().iteritems(): self.groups[name].set_variable(k, v) for host in group.get_hosts(): if host.name not in self.hosts: self.hosts[host.name] = host else: # host is already there, copy variables # note: depth numbers on duplicates may be bogus for k, v in host.vars.iteritems(): self.hosts[host.name].set_variable(k, v) self.groups[name].add_host(self.hosts[host.name]) # This needs to be a second loop to ensure all the parent groups exist for name, group in parser.groups.iteritems(): for ancestor in group.get_ancestors(): self.groups[ancestor.name].add_child_group( self.groups[name])
def __init__(self, host_list=C.DEFAULT_HOST_LIST): # the host file file, or script path, or list of hosts # if a list, inventory data will NOT be loaded self.host_list = host_list # caching to avoid repeated calculations, particularly with # external inventory scripts. self._vars_per_host = {} self._vars_per_group = {} self._hosts_cache = {} self._groups_list = {} # the inventory object holds a list of groups self.groups = [] # a list of host(names) to contain current inquiries to self._restriction = None self._also_restriction = None self._subset = None # whether the inventory file is a script self._is_script = False if type(host_list) in [str, unicode]: if host_list.find(",") != -1: host_list = host_list.split(",") host_list = [h for h in host_list if h and h.strip()] if type(host_list) == list: all = Group('all') self.groups = [all] for x in host_list: if x.find(":") != -1: tokens = x.split(":", 1) all.add_host(Host(tokens[0], tokens[1])) else: all.add_host(Host(x)) elif os.access(host_list, os.X_OK): self._is_script = True self.parser = InventoryScript(filename=host_list) self.groups = self.parser.groups.values() else: data = file(host_list).read() if not data.startswith("---"): self.parser = InventoryParser(filename=host_list) self.groups = self.parser.groups.values() else: raise errors.AnsibleError( "YAML inventory support is deprecated in 0.6 and removed in 0.7, see the migration script in examples/scripts in the git checkout" )
def get_file_parser(hostsfile, groups, loader): # check to see if the specified file starts with a # shebang (#!/), so if an error is raised by the parser # class we can show a more apropos error shebang_present = False processed = False myerr = [] parser = None try: with open(hostsfile, 'rb') as inv_file: initial_chars = inv_file.read(2) if initial_chars.startswith(b'#!'): shebang_present = True except: pass #FIXME: make this 'plugin loop' # script if loader.is_executable(hostsfile): try: parser = InventoryScript(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: myerr.append('Attempted to execute "%s" as inventory script: %s' % (hostsfile, to_native(e))) elif shebang_present: myerr.append("The inventory file \'%s\' looks like it should be an executable inventory script, but is not marked executable. " "Perhaps you want to correct this with `chmod +x %s`?" % (hostsfile, hostsfile)) # YAML/JSON if not processed and not shebang_present and os.path.splitext(hostsfile)[-1] in C.YAML_FILENAME_EXTENSIONS: try: parser = InventoryYAMLParser(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: myerr.append('Attempted to read "%s" as YAML: %s' % (to_native(hostsfile), to_native(e))) # ini if not processed and not shebang_present: try: parser = InventoryINIParser(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: myerr.append('Attempted to read "%s" as ini file: %s ' % (to_native(hostsfile), to_native(e))) if not processed and myerr: raise AnsibleError('\n'.join(myerr)) return parser
def get_file_parser(hostsfile, groups, loader): # check to see if the specified file starts with a # shebang (#!/), so if an error is raised by the parser # class we can show a more apropos error shebang_present = False processed = False myerr = [] parser = None try: inv_file = open(hostsfile) first_line = inv_file.readlines()[0] inv_file.close() if first_line.startswith('#!'): shebang_present = True except: pass if loader.is_executable(hostsfile): try: parser = InventoryScript(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: myerr.append("The file %s is marked as executable, but failed to execute correctly. " % hostsfile + \ "If this is not supposed to be an executable script, correct this with `chmod -x %s`." % hostsfile) myerr.append(str(e)) if not processed: try: parser = InventoryINIParser(loader=loader, groups=groups, filename=hostsfile) processed = True except Exception as e: if shebang_present and not loader.is_executable(hostsfile): myerr.append("The file %s looks like it should be an executable inventory script, but is not marked executable. " % hostsfile + \ "Perhaps you want to correct this with `chmod +x %s`?" % hostsfile) else: myerr.append(str(e)) if not processed and myerr: raise AnsibleError('\n'.join(myerr)) return parser
def __init__(self, host_list=C.DEFAULT_HOST_LIST): # the host file file, or script path, or list of hosts # if a list, inventory data will NOT be loaded self.host_list = host_list # the inventory object holds a list of groups self.groups = [] # a list of host(names) to contain current inquiries to self._restriction = None # whether the inventory file is a script self._is_script = False if type(host_list) in [str, unicode]: if host_list.find(",") != -1: host_list = host_list.split(",") if type(host_list) == list: all = Group('all') self.groups = [all] for x in host_list: if x.find(":") != -1: tokens = x.split(":", 1) all.add_host(Host(tokens[0], tokens[1])) else: all.add_host(Host(x)) elif os.access(host_list, os.X_OK): self._is_script = True self.parser = InventoryScript(filename=host_list) self.groups = self.parser.groups.values() else: data = file(host_list).read() if not data.startswith("---"): self.parser = InventoryParser(filename=host_list) self.groups = self.parser.groups.values() else: self.parser = InventoryParserYaml(filename=host_list) self.groups = self.parser.groups.values()
def __init__(self, filename=C.DEFAULT_HOST_LIST): self.names = os.listdir(filename) self.names.sort() self.directory = filename self.parsers = [] self.hosts = {} self.groups = {} for i in self.names: if i.endswith("~") or i.endswith(".orig") or i.endswith(".bak"): continue # These are things inside of an inventory basedir if i in ("host_vars", "group_vars", "vars_plugins"): continue fullpath = os.path.join(self.directory, i) if os.path.isdir(fullpath): parser = InventoryDirectory(filename=fullpath) elif utils.is_executable(fullpath): parser = InventoryScript(filename=fullpath) else: parser = InventoryParser(filename=fullpath) self.parsers.append(parser) # This takes a lot of code because we can't directly use any of the objects, as they have to blend for name, group in parser.groups.iteritems(): if name not in self.groups: self.groups[name] = Group(name) for k, v in group.get_variables().iteritems(): self.groups[name].set_variable(k, v) for host in group.get_hosts(): if host.name not in self.hosts: self.hosts[host.name] = Host(host.name) for k, v in host.vars.iteritems(): self.hosts[host.name].set_variable(k, v) self.groups[name].add_host(self.hosts[host.name]) # This needs to be a second loop to ensure all the parent groups exist for name, group in parser.groups.iteritems(): for ancestor in group.get_ancestors(): self.groups[ancestor.name].add_child_group(self.groups[name])
def __init__(self, loader, variable_manager, host_list=C.DEFAULT_HOST_LIST): # the host file file, or script path, or list of hosts # if a list, inventory data will NOT be loaded self.host_list = host_list self._loader = loader self._variable_manager = variable_manager # caching to avoid repeated calculations, particularly with # external inventory scripts. self._vars_per_host = {} self._vars_per_group = {} self._hosts_cache = {} self._groups_list = {} self._pattern_cache = {} # to be set by calling set_playbook_basedir by playbook code self._playbook_basedir = None # the inventory object holds a list of groups self.groups = [] # a list of host(names) to contain current inquiries to self._restriction = None self._also_restriction = None self._subset = None if isinstance(host_list, basestring): if "," in host_list: host_list = host_list.split(",") host_list = [ h for h in host_list if h and h.strip() ] if host_list is None: self.parser = None elif isinstance(host_list, list): self.parser = None all = Group('all') self.groups = [ all ] ipv6_re = re.compile('\[([a-f:A-F0-9]*[%[0-z]+]?)\](?::(\d+))?') for x in host_list: m = ipv6_re.match(x) if m: all.add_host(Host(m.groups()[0], m.groups()[1])) else: if ":" in x: tokens = x.rsplit(":", 1) # if there is ':' in the address, then this is an ipv6 if ':' in tokens[0]: all.add_host(Host(x)) else: all.add_host(Host(tokens[0], tokens[1])) else: all.add_host(Host(x)) elif os.path.exists(host_list): if os.path.isdir(host_list): # Ensure basedir is inside the directory self.host_list = os.path.join(self.host_list, "") self.parser = InventoryDirectory(loader=self._loader, filename=host_list) self.groups = self.parser.groups.values() else: # check to see if the specified file starts with a # shebang (#!/), so if an error is raised by the parser # class we can show a more apropos error shebang_present = False try: inv_file = open(host_list) first_line = inv_file.readlines()[0] inv_file.close() if first_line.startswith('#!'): shebang_present = True except: pass if is_executable(host_list): try: self.parser = InventoryScript(loader=self._loader, filename=host_list) self.groups = self.parser.groups.values() except: if not shebang_present: raise errors.AnsibleError("The file %s is marked as executable, but failed to execute correctly. " % host_list + \ "If this is not supposed to be an executable script, correct this with `chmod -x %s`." % host_list) else: raise else: try: self.parser = InventoryParser(filename=host_list) self.groups = self.parser.groups.values() except: if shebang_present: raise errors.AnsibleError("The file %s looks like it should be an executable inventory script, but is not marked executable. " % host_list + \ "Perhaps you want to correct this with `chmod +x %s`?" % host_list) else: raise vars_loader.add_directory(self.basedir(), with_subdir=True) else: raise errors.AnsibleError("Unable to find an inventory file, specify one with -i ?") self._vars_plugins = [ x for x in vars_loader.all(self) ] # FIXME: shouldn't be required, since the group/host vars file # management will be done in VariableManager # get group vars from group_vars/ files and vars plugins for group in self.groups: # FIXME: combine_vars group.vars = combine_vars(group.vars, self.get_group_variables(group.name)) # get host vars from host_vars/ files and vars plugins for host in self.get_hosts(): # FIXME: combine_vars host.vars = combine_vars(host.vars, self.get_host_variables(host.name))
def __init__(self, filename=C.DEFAULT_HOST_LIST): self.names = os.listdir(filename) self.names.sort() self.directory = filename self.parsers = [] self.hosts = {} self.groups = {} for i in self.names: if i.endswith("~") or i.endswith(".orig") or i.endswith(".bak"): continue if i.endswith(".ini"): # configuration file for an inventory script continue if i.endswith(".retry"): # this file is generated on a failed playbook and should only be # used when run specifically continue # Skip hidden files if i.startswith('.') and not i.startswith('./'): continue # These are things inside of an inventory basedir if i in ("host_vars", "group_vars", "vars_plugins"): continue fullpath = os.path.join(self.directory, i) if os.path.isdir(fullpath): parser = InventoryDirectory(filename=fullpath) elif utils.is_executable(fullpath): parser = InventoryScript(filename=fullpath) else: parser = InventoryParser(filename=fullpath) self.parsers.append(parser) # retrieve all groups and hosts form the parser and add them to # self, don't look at group lists yet, to avoid # recursion trouble, but just make sure all objects exist in self newgroups = parser.groups.values() for group in newgroups: for host in group.hosts: self._add_host(host) for group in newgroups: self._add_group(group) # now check the objects lists so they contain only objects from # self; membership data in groups is already fine (except all & # ungrouped, see later), but might still reference objects not in self for group in self.groups.values(): # iterate on a copy of the lists, as those lists get changed in # the loop # list with group's child group objects: for child in group.child_groups[:]: if child != self.groups[child.name]: group.child_groups.remove(child) group.child_groups.append(self.groups[child.name]) # list with group's parent group objects: for parent in group.parent_groups[:]: if parent != self.groups[parent.name]: group.parent_groups.remove(parent) group.parent_groups.append(self.groups[parent.name]) # list with group's host objects: for host in group.hosts[:]: if host != self.hosts[host.name]: group.hosts.remove(host) group.hosts.append(self.hosts[host.name]) # also check here that the group that contains host, is # also contained in the host's group list if group not in self.hosts[host.name].groups: self.hosts[host.name].groups.append(group) # extra checks on special groups all and ungrouped # remove hosts from 'ungrouped' if they became member of other groups if 'ungrouped' in self.groups: ungrouped = self.groups['ungrouped'] # loop on a copy of ungrouped hosts, as we want to change that list for host in ungrouped.hosts[:]: if len(host.groups) > 1: host.groups.remove(ungrouped) ungrouped.hosts.remove(host) # remove hosts from 'all' if they became member of other groups # all should only contain direct children, not grandchildren # direct children should have dept == 1 if 'all' in self.groups: allgroup = self.groups['all'] # loop on a copy of all's child groups, as we want to change that list for group in allgroup.child_groups[:]: # groups might once have beeen added to all, and later be added # to another group: we need to remove the link wit all then if len(group.parent_groups) > 1: # real children of all have just 1 parent, all # this one has more, so not a direct child of all anymore group.parent_groups.remove(allgroup) allgroup.child_groups.remove(group) elif allgroup not in group.parent_groups: # this group was once added to all, but doesn't list it as # a parent any more; the info in the group is the correct # info allgroup.child_groups.remove(group)
def __init__(self, filename=C.DEFAULT_HOST_LIST): ''' InventoryDirectory基类,包含以下属性: names,当前目录下的文件名称列表 directory, 目录名 parsers,解析器列表,每一个文件解析成一个parser hosts,主机对象字典 groups,组对象字典 ''' # os.listdir函数用来列出当前目录下的所有文件 self.names = os.listdir(filename) self.names.sort() self.directory = filename self.parsers = [] self.hosts = {} self.groups = {} for i in self.names: # 变量该目录下所有文件 # Skip files that end with certain extensions or characters # 跳过带有特定扩展名或字符结尾的文件 if any(i.endswith(ext) for ext in ("~", ".orig", ".bak", ".ini", ".retry", ".pyc", ".pyo")): continue # Skip hidden files # 跳过隐藏文件 if i.startswith('.') and not i.startswith('./'): continue # These are things inside of an inventory basedir # 跳过可能包含变量值的文件 if i in ("host_vars", "group_vars", "vars_plugins"): continue fullpath = os.path.join(self.directory, i) if os.path.isdir(fullpath): # 如果该文件仍然是一个目录,则生成一个当前类对象的Parser(嵌套处理) parser = InventoryDirectory(filename=fullpath) elif utils.is_executable(fullpath): # 如果文件是一个可执行文件,则创建一个InventoryScript类的Parser parser = InventoryScript(filename=fullpath) else: parser = InventoryParser(filename=fullpath) # 如果文件是一个普通文件,则使用InventoryParser类的parser self.parsers.append(parser) # 将parser加入self.parsers的列表中 # retrieve all groups and hosts form the parser and add them to # self, don't look at group lists yet, to avoid # recursion trouble, but just make sure all objects exist in self newgroups = parser.groups.values() # 获取当前parser的groups列表 for group in newgroups: for host in group.hosts: # 遍历每个group对象的hosts对象列表,将host对象添加到self.hosts字典中。 self._add_host(host) # 添加host可能出现在多个文件返回结果中具有相同hostname的情况,需要进行合并。 for group in newgroups: # 将groups列表中的group加到self.groups字典中,为什么不在上一个循环中一次性搞定。。。 self._add_group(group) # 添加group,可能出现group重复的情况,需要进行合并 # now check the objects lists so they contain only objects from # self; membership data in groups is already fine (except all & # ungrouped, see later), but might still reference objects not in self # 所有group都添加完成后还要做一些检测,包括子组,父组,host # 如果self.groups和self.hosts中的group对象和host对象出现名称相同,但对象不同的,都需要以self.groups和self.hosts中为准 for group in self.groups.values(): # iterate on a copy of the lists, as those lists get changed in # the loop # list with group's child group objects: for child in group.child_groups[:]: # a和a[:]有什么区别,干嘛多写3个字符 if child != self.groups[child.name]: group.child_groups.remove(child) group.child_groups.append(self.groups[child.name]) # list with group's parent group objects: for parent in group.parent_groups[:]: if parent != self.groups[parent.name]: group.parent_groups.remove(parent) group.parent_groups.append(self.groups[parent.name]) # list with group's host objects: for host in group.hosts[:]: if host != self.hosts[host.name]: group.hosts.remove(host) group.hosts.append(self.hosts[host.name]) # also check here that the group that contains host, is # also contained in the host's group list if group not in self.hosts[host.name].groups: self.hosts[host.name].groups.append(group) # extra checks on special groups all and ungrouped # remove hosts from 'ungrouped' if they became member of other groups # 检测ungrouped组 if 'ungrouped' in self.groups: ungrouped = self.groups['ungrouped'] # loop on a copy of ungrouped hosts, as we want to change that list for host in ungrouped.hosts[:]: if len(host.groups) > 1: host.groups.remove(ungrouped) ungrouped.hosts.remove(host) # remove hosts from 'all' if they became member of other groups # all should only contain direct children, not grandchildren # direct children should have dept == 1 # 对all组的检测 if 'all' in self.groups: allgroup = self.groups['all' ] # loop on a copy of all's child groups, as we want to change that list for group in allgroup.child_groups[:]: # 遍历allgroup中的所有group对象 # groups might once have beeen added to all, and later be added # to another group: we need to remove the link wit all then if len(group.parent_groups) > 1 and allgroup in group.parent_groups: # 如果当前group的父组数量大于1,并且allgroup是他的父组,则表名该组不是allgroup的子组 # all group的子组必须只有all一个父组 # real children of all have just 1 parent, all # this one has more, so not a direct child of all anymore group.parent_groups.remove(allgroup) allgroup.child_groups.remove(group) elif allgroup not in group.parent_groups: # 以group的父组信息为准进行数据清理 # this group was once added to all, but doesn't list it as # a parent any more; the info in the group is the correct # info allgroup.child_groups.remove(group)
if i.endswith(".retry"): # this file is generated on a failed playbook and should only be # used when run specifically >>>>>>> remote continue # Skip hidden files if i.startswith('.') and not i.startswith('./'): continue # These are things inside of an inventory basedir if i in ("host_vars", "group_vars", "vars_plugins"): continue fullpath = os.path.join(self.directory, i) if os.path.isdir(fullpath): parser = InventoryDirectory(filename=fullpath) elif utils.is_executable(fullpath): parser = InventoryScript(filename=fullpath) else: parser = InventoryParser(filename=fullpath) self.parsers.append(parser) # retrieve all groups and hosts form the parser and add them to # self, don't look at group lists yet, to avoid # recursion trouble, but just make sure all objects exist in self newgroups = parser.groups.values() for group in newgroups: for host in group.hosts: self._add_host(host) for group in newgroups: self._add_group(group) # now check the objects lists so they contain only objects from
def __init__(self, host_list=C.DEFAULT_HOST_LIST, vault_password=None): # the host file file, or script path, or list of hosts # if a list, inventory data will NOT be loaded # host_list 有很多中类型 self.host_list = host_list self._vault_password = vault_password # caching to avoid repeated calculations, particularly with # external inventory scripts. # 缓存一些数据以避免重复计算,特别是使用外部库存脚本。 self._vars_per_host = {} # 每个主机变量 self._vars_per_group = {} # 每个group 变量 self._hosts_cache = {} # 主机列表缓存 self._groups_list = {} # group 列表缓存 self._pattern_cache = {} # pattern 模式缓存 # to be set by calling set_playbook_basedir by playbook code self._playbook_basedir = None # the inventory object holds a list of groups self.groups = [] # a list of host(names) to contain current inquiries to self._restriction = None self._also_restriction = None self._subset = None # 如果host_list是字符串,则根据逗号进行分隔成列表 if isinstance(host_list, basestring): if "," in host_list: host_list = host_list.split(",") host_list = [h for h in host_list if h and h.strip()] if host_list is None: self.parser = None # 如果host_list是列表,创建一个all group,并将host加入all group,支持IPV6 elif isinstance(host_list, list): self.parser = None all = Group('all') self.groups = [all] ipv6_re = re.compile('\[([a-f:A-F0-9]*[%[0-z]+]?)\](?::(\d+))?') for x in host_list: m = ipv6_re.match(x) if m: all.add_host(Host(m.groups()[0], m.groups()[1])) else: if ":" in x: tokens = x.rsplit(":", 1) # if there is ':' in the address, then this is an ipv6 if ':' in tokens[0]: all.add_host(Host(x)) else: all.add_host(Host(tokens[0], tokens[1])) else: all.add_host(Host(x)) # 如果host_list是文件或文件夹 elif os.path.exists(host_list): if os.path.isdir(host_list): # Ensure basedir is inside the directory # 如果host_list是目录parser使用 InventoryDirectory 目录解析 self.host_list = os.path.join(self.host_list, "") self.parser = InventoryDirectory(filename=host_list) self.groups = self.parser.groups.values() else: # check to see if the specified file starts with a # shebang (#!/), so if an error is raised by the parser # class we can show a more apropos error # 如果host_list是文件,则判断文件是否以shebang开头 shebang_present = False try: inv_file = open(host_list) first_line = inv_file.readlines()[0] inv_file.close() if first_line.startswith('#!'): shebang_present = True except: pass if utils.is_executable(host_list): try: # 如果host_list是可执行文件,parser使用InventoryScript解析 self.parser = InventoryScript(filename=host_list) self.groups = self.parser.groups.values() except: if not shebang_present: raise errors.AnsibleError("The file %s is marked as executable, but failed to execute correctly. " % host_list + \ "If this is not supposed to be an executable script, correct this with `chmod -x %s`." % host_list) else: raise else: try: # 如果host_list是普通文本文件,parser使用 InventoryParser 解析 self.parser = InventoryParser(filename=host_list) self.groups = self.parser.groups.values() except: if shebang_present: raise errors.AnsibleError("The file %s looks like it should be an executable inventory script, but is not marked executable. " % host_list + \ "Perhaps you want to correct this with `chmod +x %s`?" % host_list) else: raise utils.plugins.vars_loader.add_directory(self.basedir(), with_subdir=True) else: raise errors.AnsibleError( "Unable to find an inventory file, specify one with -i ?") self._vars_plugins = [x for x in utils.plugins.vars_loader.all(self) ] # 加载vars plugin,这里先跳过 # get group vars from group_vars/ files and vars plugins # 从group_vars/ 目录的文件和vars plugins中获取group 变量 for group in self.groups: group.vars = utils.combine_vars( group.vars, self.get_group_variables(group.name, vault_password=self._vault_password)) # get host vars from host_vars/ files and vars plugins # 从host_vars/ 目录的文件和vars plugins中获取host变量 for host in self.get_hosts(): host.vars = utils.combine_vars( host.vars, self.get_host_variables(host.name, vault_password=self._vault_password))