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()