group.py
作者 煮酒品茶
一个组的Class,包含对外方法以及属性如下。
组做为inventory的子节点,会有嵌套组,组变量,组内主机,子组,父组的一些概念
[ 'name', 'hosts', 'vars', 'child_groups', 'parent_groups', 'depth', '_hosts_cache' ]
- name 主机名称,就是IP
- 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]
}
方法说明
- add_child_group # 添加子组
- add_host # 添加主机,即添加到hosts属性当中
- set_variable # 设置环境变量,即vars当中
- clear_hosts_cache # 清空组内所有主机的缓存,这是一个属性
- get_hosts # 获取所有主机,当_hosts_cache不存在时,否则直接返回_hosts_cache
- get_variables # 获取所有变量
- get_ancestors # 获取所有父组
类原型
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()