Salt中Pillar那點事python
基本簡介git
在 SaltStack 中, Pillar做爲定義minion全局數據的接口. 默認存儲在master端, Minion啓動時會鏈接master獲取最新的pillar數據. Pillar使用相似於State Tree的結構, 默認使用 YAML 做爲其描述格式, 在Minion內部最終轉換成 Python字典 .github
那麼在Salt內部, Pillar是如何工做的? 在哪些狀況下,須要先執行刷新Pillar操做? 而哪些又不須要?緩存
本文基於 Salt 2014.1.4網絡
配置文件中的Pillarless
pillar_rootside
存在於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 時才生效.ui
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 進行編寫.
Posted on: 2014-06-08
Category: SaltStack – Tags: saltstack, pillar
pengyao. Built using Pelican. Theme by Giulio Fidente on github. .