设为首页 收藏本站
查看: 1001|回复: 0

[经验分享] Saltstack中Pillar那点事

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-11-6 08:20:09 | 显示全部楼层 |阅读模式
Salt中Pillar那点事

基本简介

在 SaltStack 中, Pillar作为定义minion全局数据的接口. 默认存储在master端, Minion启动时会连接master获取最新的pillar数据. Pillar使用类似于State Tree的结构, 默认使用 YAML 作为其描述格式, 在Minion内部最终转换成 Python字典 .

那么在Salt内部, Pillar是如何工作的? 在哪些情况下,需要先执行刷新Pillar操作? 而哪些又不需要?

本文基于 Salt 2014.1.4

配置文件中的Pillar

pillar_roots
存在于master/minion配置文件中. 指定Pillar roots对应环境的目录, 其布局类似于State Tree. 在minion配置文件中配置该选项, 只有当 file_client 为 local 时才生效.
state_top
存在于master/minion配置文件中, 默认值为top.sls. 官方描述为用于state system, 用于告诉minion使用哪个环境并且需要执行哪些模块. 其实该选项也应用在pillar system中, 作用和state system类似. 所以如果更改了本选项, pillar system对应的top.sls也需要变更. 在minion配置文件中配置该选项, 只有当 file_client 为 local 时才生效.
file_client
存在于minion配置文件中, 默认值为remote. 用于指定去哪里查找文件. 有效值是 remote 和 local. remote 表示使用master, local 用于 Masterless 的情况.
pillar_opts
存在于master配置文件中, 默认值为True. 指定是否将master配置选项作为pillar. 如果该选项为True, 修改了master配置选项时, 需要重启master, 才能在pillar中得到最新的值.
Minion中的Pillar实现

Minion中pillar为Python字典, Minion启动时, 默认会连接master获取最新的pillar数据, 存储在 self.opts['pillar'] 中. 对应代码 如下:

class Minion(MinionBase):
    '''
    This class instantiates a minion, runs connections for a minion,
    and loads all of the functions into the minion
    '''
    def __init__(self, opts, timeout=60, safe=True):
        '''
        Pass in the options dict
        '''
        ......
        self.opts['pillar'] = salt.pillar.get_pillar(
            opts,
            opts['grains'],
            opts['id'],
            opts['environment'],
        ).compile_pillar()
        ......
那么 salt.pillar.get_pillar 是如何工作的? 对应代码 如下:

def get_pillar(opts, grains, id_, saltenv=None, ext=None, env=None):
    '''
    Return the correct pillar driver based on the file_client option
    '''
    if env is not None:
        salt.utils.warn_until(
            'Boron',
            'Passing a salt environment should be done using \'saltenv\' '
            'not \'env\'. This functionality will be removed in Salt Boron.'
        )
        # Backwards compatibility
        saltenv = env

    return {
            'remote': RemotePillar,
            'local': Pillar
            }.get(opts['file_client'], Pillar)(opts, grains, id_, saltenv, ext)
也可以从代码中获知, 会从opts中获取 file_client 值, 如果是remote, 则对应的对象为RemotePillar, 如果是local, 则为Pillar, 进行后续处理

如果Minion在运行过程中, 接受到的指令以 refresh_pillar 字符串开头, 则执行 pillar_refresh 操作. 对应代码 如下:

if package.startswith('module_refresh'):
    self.module_refresh()
elif package.startswith('pillar_refresh'):
    self.pillar_refresh()
那么 pillar_refresh() 都进行了哪些工作? 对应代码 如下:

def pillar_refresh(self):
    '''
    Refresh the pillar
    '''
    self.opts['pillar'] = salt.pillar.get_pillar(
        self.opts,
        self.opts['grains'],
        self.opts['id'],
        self.opts['environment'],
    ).compile_pillar()
    self.module_refresh()
从代码中得知, pillar_refresh操作, 除了从Master端/Minion本地获取最新的pillar信息外, 也会执行模块刷新(module_refresh)工作. 可以将minion本地的日志级别调整为 trac, 然后执行 saltutil.refresh_pillar 操作, 然后观察minion日志, 是否会刷新模块进行验证.

Target中的Pillar

Salt指令发送底层网络, 采用ZeroMQ PUB/SUB结构. Minion会监听SUB接口, Master会将指令发送到本地的PUB接口, 然后所有Minion均会收到该指令, 然后在Minion本地判断自己是否需要执行该指令(即Target). 当前版本中, 已经支持pillar作为Target(通过"-I"选项指定). 对应代码 如下:

def pillar_match(self, tgt, delim=':'):
    '''
    Reads in the pillar glob match
    '''
    log.debug('pillar target: {0}'.format(tgt))
    if delim not in tgt:
        log.error('Got insufficient arguments for pillar match '
                  'statement from master')
        return False
    return salt.utils.subdict_match(self.opts['pillar'], tgt, delim=delim)
可以看出, 其匹配使用的是 self.opts['pillar'] 即当前Minion内存中的Pillar的数据. 因此如果在Master/Minion(当 file_client 为 local 时)修改了Pillar数据后, 想要使用最新的Pillar来做Target操作, 需要在执行前先手动执行 saltutil.refresh_pillar 操作, 以刷新Minion内存中的Pillar数据.

远程执行模块中的Pillar

pillar.items

对应代码 如下:

pillar = salt.pillar.get_pillar(
    __opts__,
    __grains__,
    __opts__['id'],
    __opts__['environment'])

return pillar.compile_pillar()
会连接Master/Minion(当 file_client 为 local 时)获取最新的pillar数据并返回. 但并不会刷新Minion本地的缓存. 也就是说, 在master端修改了Pillar Tree, 在刷新pillar(saltutil.refresh_pillar)前, 可以先使用 pillar.items 来验证其数据是否达到预期.

pillar.data

对应代码 如下:

data = items
只是创建了一个赋值引用, 指定data和执行items一样

pillar.item

对应代码 如下:

ret = {}
pillar = items()
for arg in args:
    try:
        ret[arg] = pillar[arg]
    except KeyError:
        pass
return ret
先使用pillar.items来获取最新的Master端最新的pillar数据. 然后一个for循环, 从items获取所需要的keys对应的值. 所以item可以查询多个key.

pillar.raw

对应代码 如下:

if key:
    ret = __pillar__.get(key, {})
else:
    ret = __pillar__

return ret
从当前Minion本地获取 __pillar__ (self.opts[pillar])的值. 也就是说使用 pillar.raw 与 pillar.items 不同, 获取到的是Minion内存中的pillar的值, 并非是master端定义的值. 如果指定了key, 则返回对应key的值. 如果没有, 则返回整个 __pillar__

pillar.get

对应代码 如下:

return salt.utils.traverse_dict(__pillar__, key, default)
和 pillar.raw 工作方式类似, 是从 __pillar__ 中进行的取值, 用于获取pillar中对应的key值. 与 pillar.raw执行key不同的是, get递归获取内嵌字典的值(默认以":"做分隔). 从最新develop分支中看, 下一个版本(Helium)中将增加merge功能.

pillar.ext

与pillar.items工作方式类似, 用于获取ext pillar的值

saltutil.refresh_pillar

对应代码 如下:

__salt__['event.fire']({}, 'pillar_refresh')
在Minion本地Event接口上产生一个 pillar_refresh event. 之前在Minion中的Pillar中, Minion本地会监听本地Event接口, 如果捕捉到以 pillar_refresh 开始的指令, 会刷新本地pillar.

配置管理中的Pillar

在SLS中使用Pillar

在SLS中, 可以直接使用pillar. 如pillar['pkg'], 其直接使用的是Minion当前内存中pillar的值(self.opts['pillar']).

state.sls & state.highstate

将这两个远程执行模块方法放到配置管理中, 因为其功能是用于向Minions发送配置管理指令.

state.sls及state.highstate在代码中, 均为 salt.state.HighState 对象. 在执行时为 State 对象. State类在实例化时,则会刷新pillar, 对应代码 如下:

class State(object):
    '''
    Class used to execute salt states
    '''
    def __init__(self, opts, pillar=None, jid=None):
        if 'grains' not in opts:
            opts['grains'] = salt.loader.grains(opts)
        self.opts = opts
        self._pillar_override = pillar
        self.opts['pillar'] = self._gather_pillar()
而_gather_pillar 对应代码 如下:

def _gather_pillar(self):
    '''
    Whenever a state run starts, gather the pillar data fresh
    '''
    pillar = salt.pillar.get_pillar(
            self.opts,
            self.opts['grains'],
            self.opts['id'],
            self.opts['environment'],
            )
    ret = pillar.compile_pillar()
    if self._pillar_override and isinstance(self._pillar_override, dict):
        ret.update(self._pillar_override)
    return ret
_gather_pillar从Master上获取Minion对应的最新pillar数据, __init__方法中的 self.opts['pillar'] = self._gather_pillar() 将该数据赋值给self.opts['pillar']以完成Minion本地内存中Pillar数据的刷新操作. 这就是为什么修改了Master上的Pillar的值, 而无需执行刷新操作(saltutil.refresh_pillar), 因为在执行state.highstate及state.sls时会自动应该最新的值.

ext_pillar

Salt支持从第三方系统中获取Pillar信息,使Salt易于与现有的CMDB系统进行数据整合. 对应的配置是master配置文件中的ext_pillar选项. 官方当前已经提供了 若干驱动 .

如果已经提供的驱动并不满足需求, 自定义ext_pillar驱动也非常简单. 只需要驱动文件放到master端salt代码中pillar目录下即可, 驱动为python代码, 其中包含ext_pillar函数, 且该函数第一个参数是minion_id, 第二个参数为pillar, 其返回值是一个标准的 Python字典 即可. 可以参照 cobbler的ext_pillar 进行编写.



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-27172-1-1.html 上篇帖子: 在SaltStack中使用Pillar 下篇帖子: saltstack快速安装
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表