salt write module code

salt 编写代码

  1. salt远程执行底层原理

    1
    2
    3
    4
    5
    6
    7
    salt底层通信是通过zeroMQ完成的,采用了zeroMQ的订阅发布模式.在订阅发布模式中Pub将消息发送到总线,所有的Sub接收到来自总线的消息后,根据自己的订阅条件来接收特定的消息.对应于salt中就是master将事件发布到消息总线,minion订阅并监听事件,然后minion会查看事件是否和自己匹配以确定是否需要执行.

    salt master启动时会监听两个端口,默认是4505和4506
    * 4506 salt master Ret接口,支持认证,文件服务,结果收集等
    * 4505 salt master pub接口,提供远程执行命令发送功能

    salt minion 启动时从配置文件中获取master地址,如果为域名,则进行解析.解析后,会连接master的4506端口(Ret)进行key认证.认证通过,会获取master的publish_port(4505),然后连接publish_port订阅来自master pub接口任务. 当master下发操作指令时,所有的minion都能接收到,然后minion会检查本机是否匹配.如果匹配,则执行.执行完毕后,把结果发送到master的4506(ret)由master进行处理.命令发送通信完全是异步的,并且命令包很小.此外,这些命令包通过maqpack进行序列化后数据会进一步压缩,所以salt网络负载非常低
  2. 执行模块的构成结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    例如: test.sleep
    def sleep(length):
    """
    Instruct the minion to initiate a process that will sleep for a given period of timezone
    CLI Example:
    .. code-block::bash
    salt '*' test.sleep 20
    """
    time.sleep(int(length))
    return True

    综上,salt的执行模块函数其实就是python函数,但通过结合salt的远程执行功能后会变得非常强大
  3. 编写自己的执行模块函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    * 创建模块存放位置(默认)
    [root@saltserver ~]# mkdir -p /srv/salt/_modules

    * 编写模块
    [root@saltserver ~]# vim /srv/salt/_modules/hello.py
    def world():
    """
    This is my first function.
    CLI Example:
    salt '*' hello.world
    """
    return 'Hello, world!'

    * 把模块推送到所有minion上
    [root@saltserver ~]# salt '*' saltutil.sync_modules
    192.168.13.187:
    - modules.hello

    [root@saltserver ~]# salt '*' sys.list_modules|grep hello
    - hello

    * 在所有minion上执行模块
    [root@saltserver ~]# salt '*' hello.world
    192.168.13.187:
    Hello, world!
  4. 交叉调用salt自带的模块函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    * __salt__函数
    [root@saltserver ~]# vim /usr/local/python27/lib/python2.7/site-packages/salt/modules/useradd.py
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)

    综上,我们可以通过"__salt__"调用所有其他执行模块,就像使用salt命令一样简单

    * __grains__和__pillar__函数
    [root@saltserver ~]# vim /usr/local/python27/lib/python2.7/site-packages/salt/modules/aptpkg.py
    if __grains__.get('os_family') in ('Kali', 'Debian', 'neon'):
    if __grains__['os'] in ('Ubuntu', 'Mint', 'neon'):
    综上,可以看出__grains__类似于grain模块,可以获取主机的信息并使用
    同样,__pillar__类似于pillar模块

    * __virtual__函数
    __virtual__函数作用很特殊.salt在加载执行模块时,__virtual__函数可以帮助salt完成以下两项工作:
    1.帮助salt决定是否要加载这个模块
    2.需要时可以重新命名该模块
    例如:
    [root@saltserver ~]# vim /usr/local/python27/lib/python2.7/site-packages/salt/modules/aptpkg.py
    # Define the module's virtual name
    __virtualname__ = 'pkg'
    def __virtual__():
    '''
    Confirm this module is on a Debian based system
    '''
    if __grains__.get('os_family') in ('Kali', 'Debian', 'neon'):
    return __virtualname__
    elif __grains__.get('os_family', False) == 'Cumulus':
    return __virtualname__
    return (False, 'The pkg module could not be loaded: unsupported OS family')

    在模块加载时执行"__virtual__"函数,"__virtual__"函数通过"__grains__"函数判断操作系统是否为'kali'或'debian','neno',并返回"__virtualname__"值,而"__virtualname__"的值将作为模块名使用.如果返回值为False,则模块中函数将不被加载;如果返回值为True,salt将文件名作为模块名
  5. 编写一个完整的模块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    * 编写模块
    [root@saltserver ~]# vim /srv/salt/_modules/prank.py
    # -*- coding:utf-8 -*-
    """
    The top nth processes which take up CPU and Memory space usage are available through this module,aditionaly;the module can get the system load information.
    """

    # import python libs
    import os

    # import salt libs
    import salt.utils

    def cpu(n):
    """
    Return the top nth processes which take up the cpu usage for this minion
    CLI Example:
    salt '*' prank.cpu <n>
    """
    cmd = "ps aux|sort -k3 -nr|head -n%s" % str(n)
    output = __salt__['cmd.run_stdout'](cmd)
    res = []
    for line in output.splitlines():
    res.append(line)
    return res

    def mem(n):
    """
    Return th top nth processes which take up the memory usage for this minion
    CLI example:
    salt '*' prink.mem <n>
    """
    cmd = "ps aux|sort -k4 -nr|head -n%s" % str(n)
    output = __salt__['cmd.run_stdout'](cmd)
    res = []
    for line in output.splitlines():
    res.append(line)
    return res

    def load():
    """
    Return the load averages for this minion
    CLI Example:
    salt '*' prink.load
    """
    load_avg = os.getloadavg()
    return {'1-min': load_avg[0],'5-min':load_avg[1],'15-min':load_avg[2]}

    * 同步模块
    [root@saltserver ~]# salt '*' saltutil.sync_modules
    192.168.13.187:
    - modules.prank

    * 查看模块帮助
    [root@saltserver ~]# salt '192.168.13.187' sys.doc prank
    prank.cpu:
    Return the top nth processes which take up the cpu usage for this minion
    CLI Example:
    salt '*' prank.cpu <n>
    prank.load:
    Return the load averages for this minion
    CLI Example:
    salt '*' prink.load <n>
    prank.mem:
    Return th top nth processes which take up the memory usage for this minion
    CLI example:
    salt '*' prink.mem <n>

    * 执行模块
    [root@saltserver ~]# salt '*' prank.load
    192.168.13.187:
    ----------
    1-min:
    0.0
    15-min:
    0.0
    5-min:
    0.0