本文共 5104 字,大约阅读时间需要 17 分钟。
一个组的Class,包含对外方法以及属性如下。
组做为inventory的子节点,会有嵌套组,组变量,组内主机,子组,父组的一些概念
[ 'name', 'hosts', 'vars', 'child_groups', 'parent_groups', 'depth', '_hosts_cache' ]
虽然类是一个对象,但是我们有时可以把类看成一个字典,加一个方法
Group看起来就像一个字典,既然理解是一个字典,我们把结构分析出来。记住这个结构就很好理解这个类,另外提供的方法都是为了实现这个实例
group_name = { "depth" : depth, "name" : name, "hosts" : [host, host, host], # 这里的host为host类的实例,看host类分析 "vars" : { "key1" : "value1", "key2" : "value2", }, "child_groups" : [ group, # 这里的group就是我们自己,一种深度的方式 group, group, ], "parent_group" : [ group, # 这里的group就是我们自己 group, group , ], # 这里的host为所有的子组子组的host的集合, # 代表这个组包含的所有主机 "_hosts_cache" : [host, host, host] }
class Group(object): ''' a group of ansible hosts ''' __slots__ = [ 'name', 'hosts', 'vars', 'child_groups', 'parent_groups', 'depth', '_hosts_cache' ] def __init__(self, name=None): # 组内的主机、子组和父组是一个列表、变量为为字典 self.depth = 0 self.name = name self.hosts = [] self.vars = {} self.child_groups = [] self.parent_groups = [] self._hosts_cache = None #self.clear_hosts_cache() # 不允许没有不传组名,这里没有用真假, 个人认为用 # if not self.name 为更好 if self.name is None: raise Exception("group name is required") # 添加子组方法 def add_child_group(self, group): if self == group: # 不允许自己添加自己 raise Exception("can't add group to itself") # don't add if it's already there # 组名如果已经存在子组里面即不添加,这里的验证方式以组名认证 # 同样认为用 if group not in self.child_groups会更好理解一点 if not group in self.child_groups: # 添加子组,可以看到子组也是一个列表 self.child_groups.append(group) # update the depth of the child # 更新组的深度,这里需要注意的是子组也是同样走这个类,而depth # 会动态生成, 比较当前组的深度 +1 与要添加的组的深度,哪个 # 更大当前组的深度就为这个 group.depth = max([self.depth+1, group.depth]) # update the depth of the grandchildren # 更新子组的子组的深度,这里用的是注释是孙组 # 但看函数原型则所有后辈组的深度为一样 group._check_children_depth() # now add self to child's parent_groups list, but only if there # isn't already a group with the same name # 如果组名不在 父组列组的名称当中,用到了列表解析 # 通过列表解析获取所有父组的名字来进行比对,不在即不同名,就添加 # 到父组里面 if not self.name in [g.name for g in group.parent_groups]: group.parent_groups.append(self) # 添缓存, 即子组与所有子组的 _hosts_cache为量为空 self.clear_hosts_cache() # 验证子组深度,这是一个递归函数,这里可以知道的一点是 # 所有后輩组的深度都是一样 def _check_children_depth(self): # 递归所有子组 for group in self.child_groups: # 子组的深度更新,保持与当前组一置 group.depth = max([self.depth+1, group.depth]) # 递归,所以所有子组的所有深度都会被改变 group._check_children_depth() # 添加主机 def add_host(self, host): # 往组的主机列表里添加这台主机 self.hosts.append(host) # 同样把主机的组里面添加自己的组 host.add_group(self) # 再清缓存, 即子组与所有子组的 _hosts_cache为量为空 self.clear_hosts_cache() # 设置变量,这里对应的是组,所以设置的是组的变量 def set_variable(self, key, value): self.vars[key] = value # 清空缓存 def clear_hosts_cache(self): # 子组与所有子组的 _hosts_cache为量为空 self._hosts_cache = None for g in self.parent_groups: g.clear_hosts_cache() # 获取组内的主机 def get_hosts(self): # 如果主机缓存在的话直接返回,否则返回内置方法 # self._get_hosts() if self._hosts_cache is None: self._hosts_cache = self._get_hosts() return self._hosts_cache # 内置获取主机的方法, 用到集合的概念,但没有用集合的方法 def _get_hosts(self): # hosts列表 seen 字典 hosts = [] seen = {} # 先遍历子组 for kid in self.child_groups: # 一个递归,外部递归,获取子组的所有主机,即 # 不管组多深,都能拿出子组所有的主机 kid_hosts = kid.get_hosts() # 下面是做主机重复的判断,如果重复了就不加了 for kk in kid_hosts: if kk not in seen: # 这里暂时没有意义,代表主机已经存在了 seen[kk] = 1 # 不存在就添加主机 hosts.append(kk) # 再遍历自己组的主机 for mine in self.hosts: # 上面的seen作用主要体现在这儿,因为两个for # 命令空间不同所以写在这里做判断,同样存在即不添加 # 保持hosts为一个组内的集合 集合是不会有同样的组的 if mine not in seen: seen[mine] = 1 hosts.append(mine) return hosts # 获取变量 def get_variables(self): # 一份浅拷贝的变量,需要注意的是变量是没有潜逃的 return self.vars.copy() # 获取所有父组的递归函数 def _get_ancestors(self): results = {} for g in self.parent_groups: results[g.name] = g results.update(g._get_ancestors()) return results def get_ancestors(self): return self._get_ancestors().values()
转载于:https://blog.51cto.com/cwtea/2043640