最近在看minion的启动的源代码,一路曲折啊,经过一番努力,终于理解了流程。现在记录下,方便以后查阅。


总体来说流程如下:

1、解析命令行参数和minion配置文件,得到options和config字典

2、设置日志(salt.log.setup.setup_logfile_logger负责)

3、设置pidfile

4、根据master参数决定调用salt.minion.MultiMinion或者salt.minion.Minion初始化

5、调用tune_in方法


解析命令行参数和配置文件调用的是salt.Minion,这个类极其复杂,使用了高级概念元类,多重继承。我看的时候特别晕,只是理解了大概。

对应文件是salt/__init__.py,这个文件中的Minion类是salt.utils.parsers.MinionOptionParser的子类。

下面代码对应文件是salt/utils/parsers.py。

class MinionOptionParser(MasterOptionParser):

    __metaclass__ = OptionParserMeta # 元类

    description = (
        'The Salt minion, receives commands from a remote Salt master.'
    )    

    # ConfigDirMixIn config filename attribute
    _config_filename_ = 'minion'
    # LogLevelMixIn attributes
    # LOGS_DIR = '/var/log/salt'
    _default_logging_logfile_ = os.path.join(syspaths.LOGS_DIR, 'minion')

    # 设置self.config字典的
    def setup_config(self):
        return config.minion_config(self.get_config_file_path(),
                                    minion_id=True)


设置日志,调用的是salt.log.setup.setup_logfile_logger函数,主要是设置handler,loglevel,formatter。用到的是logging模块。对应的文件是salt/log/setup.py


初始化是一般调用的是salt.minion.Minion,如果设置的多个masters,则会调用salt.minion.MultiMinion。这里以salt.minion.Minion讲解过程。对应文件是salt/minion.py

salt.minion.Minion初始化过程如下:

1、验证ZMQ的版本

2、获取grains

3、向ret端口发送验证请求,获取master的aes和pub端口

4、获取pillar数据

5、装载可用的minion模块和returners

6、设置schedule


向ret端口发送验证请求,进行数字签名过程如下:

对应的接口是salt.crypt.Auth

1、调用get_keys方法load key,如果没有则生成密钥对,密钥保存到minion.pem,公钥保存到minion.pub,然后再load key,使用的模块是M2Crypto.RSA

2、进行数字签名,向master_ip:4506发送请求

请求格式:

payload = {

'enc':'clear',

'load':{

'cmd':'_auth',

'id':minion的id,

'pub':minion.pub的内容,

}

}

返回格式:

payload = {

'aes':加密的数据,

'enc':'pub',

'pub_key':key,

'publish_port':'4505',

'sig':加密的数据

}

3、将pub_key字段对应的数据写入minion_master.pub

4、对aes和sig字段对应的数据解密,代码如下

key = self.get_keys()
key_str = key.private_decrypt(payload['aes'], RSA.pkcs1_oaep_padding)
if 'sig' in payload:
    m_path = os.path.join(self.opts['pki_dir'], self.mpub)
    if os.path.exists(m_path):
        try:
            mkey = RSA.load_pub_key(m_path)
        except Exception:
            return '', ''
        digest = hashlib.sha256(key_str).hexdigest()
        m_digest = mkey.public_decrypt(payload['sig'], 5)
        if m_digest != digest:
            return '', ''
else:
    return '', ''
if '_|-' in key_str:
    return key_str.split('_|-')
else:
    if 'token' in payload:
        token = key.private_decrypt(payload['token'], RSA.pkcs1_oaep_padding)
        return key_str, token
    elif not master_pub:
        return key_str, ''


获取grains数据主要调用的是salt.loader.grains,这个方法会间接去调用salt.loader.Loader类,对应文件是salt/loader.py,这个是调用imp模块加载模块的。

获取pillar数据主要调用的是salt.pillar.get_pillar,对应文件是salt/pillar/__init__.py。

后期会针对pillar和grains的获取详细介绍下,或者看看saltstack中国用户组的介绍。


tune_in的这个方法属于salt.minion.Minion的。流程如下:

1、获取pub和pull的地址,默认是文件,通过ipc通信

2、绑定pub和pull

3、创建sub socket连接master的pub地址并保持长连接

4、执行死循环,触发event


这里只是大概的记录下流程,写的不怎么详细,还请大家海涵。

接下来的任务就是研究salt-minion去处理一个job的流程。


参考:

http://www.saltstack.cn/projects/cssug-kb/wiki/Salt-zeromq-01

http://www.saltstack.cn/projects/cssug-kb/wiki/Salt-pillar-01

http://devopstarter.info/yuan-ma-jie-du-saltstackyun-xing-ji-zhi-zhi-job-runtime/