一、扩展Grains

我们知道,grains可以帮助收集minion端的静态信息。在更为复杂的业务环境中,可以使用自定义的grains帮助收集真实需要的静态或者业务信息;

grains流程:  master端定义脚本--->脚本sync到minion端--->minion刷新grains--->获取新的grains值

举例说明:

[root@linux-node1 ~]# cat /srv/salt/base/_grains/example.py
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'Charles Chang'
def grains():
local = {}
test = {'key':'value','key1':'value1','key2':'value2'}
local['list'] =[1,2,3,4]
local['string']='str'
local['dict'] =test
return local

sync grains到minion端  

salt '*' saltutil.sync_grains
linux-node2.oldboyedu.com:
- grains.example
linux-node1.oldboyedu.com:
- grains.example

在minion端查看grains脚本位置

[root@linux-node1 _grains]# salt '*' cmd.run ls /var/cache/salt/minion/extmods/grains
linux-node2.oldboyedu.com:
example.py
example.pyc
linux-node1.oldboyedu.com:
example.py
example.pyc

自定义grains如下

[root@linux-node1 ~]# salt '*' grains.item list string dict
linux-node2.oldboyedu.com:
----------
dict:
----------
key:
value
key1:
value1
key2:
value2
list:
- 1
- 2
- 3
- 4
string:
str
linux-node1.oldboyedu.com:
----------
dict:
----------
key:
value
key1:
value1
key2:
value2
list:
- 1
- 2
- 3
- 4
string:
str

  

  

二、扩展module

使用salt自带的模块dig查看

from __future__ import absolute_import

# Import salt libs
import salt.utils # Import python libs
import logging
import re
import socket log = logging.getLogger(__name__) __virtualname__ = 'dig' def __virtual__():
'''
Only load module if dig binary is present
'''
return True if salt.utils.which('dig') else False def A(host, nameserver=None):
'''
Return the A record for ``host``. Always returns a list. CLI Example: .. code-block:: bash salt ns1 dig.A www.google.com
'''
dig = ['dig', '+short', str(host), 'A'] if nameserver is not None:
dig.append('@{0}'.format(nameserver)) cmd = __salt__['cmd.run_all'](dig, python_shell=False)
# In this case, 0 is not the same as False
if cmd['retcode'] != 0:
log.warn(
'dig returned exit code \'{0}\'. Returning empty list as '
'fallback.'.format(
cmd['retcode']
)
)
return [] # make sure all entries are IPs
return [x for x in cmd['stdout'].split('\n') if check_ip(x)]

  

下面编辑一个puppet模块文件,用于批量检查puppet的状态:

 [root@linux-node1 _modules]# pwd
/srv/salt/base/_modules
[root@linux-node1 _modules]# cat puppet.py
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
from __future__ import absolute_import
from salt.ext.six.moves.urllib.request import urlopen as _urlopen
import salt.utils
import salt.utils.decorators as decorators @decorators.memoize
def __detect_os():
return salt.utils.which('puppet') def __virtual__():
if __detect_os():
return True
return False def setmaster(master='linux-node1.oldboyedu.com',config_file='/etc/puppet/puppet.conf'):
check='grep server {0}'.format(config_file)
outcheck = __salt__['cmd.run'](check)
if outcheck:
cmdline = 'sed -i "s/server = .*/server = {0}/g" {1}'.format(master,config_file)
output = __salt__['cmd.run'](cmdline)
return 'has change server to {0}'.format(master)
else:
cmdline = 'echo " server = {0}" >> {1}'.format(master,config_file)
output = __salt__['cmd.run'](cmdline)
return 'has change server to {0} need restart the service'.format(master) def version():
cmd = 'rpm -qf {0}'.format(__detect_os())
output = __salt__['cmd.run'](cmd).splitlines()
ret = output[0].split(': ')
return ret[-1] def service(single=None):
status = ('start','stop','status','restart','reload','force-reload','condrestart','once','genconfig')
if single not in status:
return 'puppet can not suppert this single'
cmdline = 'systemctl {0} puppet.service'.format(single)
output = __salt__['cmd.run'](cmdline)
return output def master(config_file='/etc/puppet/puppet.conf'):
cmdline= 'grep server' + '{0}'.format(config_file)
output=__salt__['cmd.run'](cmdline,python_shell=False)
if output:
return output
else:
return 'puppet server not setting'

puppet.py

执行命令,将module同步到所有的minion端:

[root@linux-node1 ~]# salt '*' saltutil.sync_modules
linux-node1.oldboyedu.com:
- modules.puppet
linux-node2.oldboyedu.com:
- modules.puppet

同步结果:

[root@linux-node1 ~]# salt '*' cmd.run ls /var/cache/salt/minion/extmods/modules/
linux-node2.oldboyedu.com:
puppet.py
puppet.pyc
linux-node1.oldboyedu.com:
puppet.py
puppet.pyc

检测puppet版本:

[root@linux-node1 ~]# salt '*' puppet.version
linux-node2.oldboyedu.com:
puppet-3.8.7-2.el7.noarch
linux-node1.oldboyedu.com:
puppet-3.6.2-3.el7.noarch
[root@linux-node1 ~]#
[root@linux-node1 ~]# salt '*' puppet.service status
linux-node2.oldboyedu.com:
* puppet.service - Puppet agent
Loaded: loaded (/usr/lib/systemd/system/puppet.service; disabled; vendor preset: disabled)
Active: inactive (dead)
linux-node1.oldboyedu.com:
* puppet.service - Puppet agent
Loaded: loaded (/usr/lib/systemd/system/puppet.service; disabled; vendor preset: disabled)
Active: inactive (dead)
ERROR: Minions returned with non-zero exit code [root@linux-node1 ~]# salt '*' puppet.master
linux-node2.oldboyedu.com:
puppet server not setting
linux-node1.oldboyedu.com:
puppet server not setting
ERROR: Minions returned with non-zero exit code [root@linux-node1 ~]# salt '*' puppet.setmaster
linux-node2.oldboyedu.com:
has change server to linux-node1.oldboyedu.com need restart the service
linux-node1.oldboyedu.com:
has change server to linux-node1.oldboyedu.com need restart the service [root@linux-node1 ~]# salt '*' puppet.master
linux-node2.oldboyedu.com:
puppet server not setting
linux-node1.oldboyedu.com:
puppet server not setting
ERROR: Minions returned with non-zero exit code

可以将平时有点繁琐的流程操作封装为saltstack module的方式,方便以后重复使用;

三、state扩展

state sls执行流程:sls的yaml格式使yaml_safe_load为python的字典数据类型--->state调用module操作

看官方的例子:

[root@linux-node1 states]# vim rabbitmq_user.py
# -*- coding: utf-8 -*-
'''
Manage RabbitMQ Users
===================== Example: .. code-block:: yaml rabbit_user:
rabbitmq_user.present:
- password: password
- force: True
- tags:
- monitoring
- user
- perms:
- '/':
- '.*'
- '.*'
- '.*'
- runas: rabbitmq
'''
from __future__ import absolute_import # Import python libs
import logging # Import salt libs
import salt.utils log = logging.getLogger(__name__) def __virtual__():
'''
Only load if RabbitMQ is installed.
'''
return salt.utils.which('rabbitmqctl') is not None def absent(name,
runas=None):
'''
Ensure the named user is absent name
The name of the user to remove
runas
User to run the command
'''
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}} user_exists = __salt__['rabbitmq.user_exists'](name, runas=runas) #rabbitmq.user_exists是调用modules目录下rabbitmq.py文件中user_exists函数 if not user_exists:
ret['comment'] = 'User {0} is not present'.format(name)
elif __opts__['test']:
ret['result'] = None
if user_exists:
ret['comment'] = 'Removing user {0}'.format(name)
else:
result = __salt__['rabbitmq.delete_user'](name, runas=runas)
if 'Error' in result:
ret['result'] = False
ret['comment'] = result['Error']
elif 'Deleted' in result:
ret['comment'] = 'Deleted'
ret['changes'] = {'new': '', 'old': name} return ret

必须返回一个字典 

下面编写一个检测ansible.cfg文件的state,并使用sls进行调用:

[root@linux-node1 _states]# pwd
/srv/salt/base/_states
[root@linux-node1 _states]# cat ansible.py
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
from __future__ import absolute_import
import salt.utils
import ConfigParser def files(name='/etc/ansible/ansible.cfg ',
inventory=None,
forks=None,
module_lang=None,
host_key_checking=None,
timeout=None
):
ret = {
'name':name,
'changes':{},
'result':True,
'comment':''
}
all = {}
file = __salt__['file.file_exists'](name)
if __opts__['test']: #是否在命令行加test=True
ret['comment'] = 'some default has changed'
ret['result']=None
return ret
if file:
cf = ConfigParser.ConfigParser()
cf.read(name)
if inventory:
cf.set('defaults','inventory',inventory)
mess = 'inventory change to {0} \n'.format(inventory)
if forks:
cf.set('defaults','forks',forks)
mess +='fork changing to {0} \n'.format(forks)
if module_lang:
cf.set('defaults','module_lang',module_lang)
mess += 'module_lang chnge to {0} \n'.format(module_lang)
if host_key_checking:
cf.set('defaults','host_key_checking',host_key_checking)
mess +='host_key_checking to {0} \n'.format(host_key_checking)
if timeout:
cf.set('defaults','timeout',timeout)
mess +='timout change to {0} \n'.format(timeout)
cf.write(open(name,"w"))
ret['result'] = True
all['message']=mess
ret['comment'] = 'some default has changed'
ret['changes']=all
else:
ret['comment']= '{0} files not exists'.format(name)
ret['result'] = False
return ret

sls文件如下:

[root@linux-node1 base]# ls
ansible.sls _states
[root@linux-node1 base]# cat ansible.sls
'/etc/ansible/ansible.cfg':
ansible.files:
- inventory: /etc/host
- timeout: 88
- forks: 8

同步到minion端:

[root@linux-node1 _states]# salt '*' saltutil.sync_states
linux-node1.oldboyedu.com:
- states.ansible
linux-node2.oldboyedu.com:
- states.ansible
[root@linux-node1 base]# salt '*' cmd.run ls /var/cache/salt/minion/extmods/states/
linux-node1.oldboyedu.com:
ansible.py
ansible.pyc
linux-node2.oldboyedu.com:
ansible.py
ansible.pyc

  

测试:

[root@linux-node1 _states]# salt '*' state.sls ansible test=True
linux-node1.oldboyedu.com:
----------
ID: /etc/ansible/ansible.cfg
Function: ansible.files
Result: None
Comment: some default has changed
Started: 10:37:37.868769
Duration: 11.797 ms
Changes: Summary
------------
Succeeded: 1 (unchanged=1)
Failed: 0
------------
Total states run: 1
linux-node2.oldboyedu.com:
----------
ID: /etc/ansible/ansible.cfg
Function: ansible.files
Result: None
Comment: some default has changed
Started: 10:37:37.852572
Duration: 6.358 ms
Changes: Summary
------------
Succeeded: 1 (unchanged=1)
Failed: 0
------------
Total states run: 1 [root@linux-node1 _states]# salt '*' state.sls ansible
linux-node2.oldboyedu.com:
----------
ID: /etc/ansible/ansible.cfg
Function: ansible.files
Result: False
Comment: /etc/ansible/ansible.cfg files not exists
Started: 10:39:21.038324
Duration: 10.685 ms
Changes: Summary
------------
Succeeded: 0
Failed: 1
------------
Total states run: 1
linux-node1.oldboyedu.com:
----------
ID: /etc/ansible/ansible.cfg
Function: ansible.files
Result: True
Comment: some default has changed
Started: 10:39:21.082694
Duration: 10.97 ms
Changes:
----------
message:
inventory change to /etc/host
fork changing to 8
timout change to 88 Summary
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1 [root@linux-node1 _states]# salt '*' cmd.run "cat /etc/ansible/ansible.cfg|egrep '^inventory|^forks|^timeout'"
linux-node1.oldboyedu.com:
inventory = /etc/host
forks = 8
timeout = 88
linux-node2.oldboyedu.com:
cat: /etc/ansible/ansible.cfg: No such file or directory
ERROR: Minions returned with non-zero exit code

四、ext_pillar与ext_nodes

1、理解ext_pillar

先可以一个例子:

[root@linux-node1 ~]# vim /usr/lib/python2.7/site-packages/salt/pillar/hiera.py

# -*- coding: utf-8 -*-
'''
Use hiera data as a Pillar source
'''
from __future__ import absolute_import # Import python libs
import logging # Import salt libs
import salt.utils
from salt.ext.six import string_types # Import third party libs
import yaml # Set up logging
log = logging.getLogger(__name__) def __virtual__():
'''
Only return if hiera is installed
'''
return 'hiera' if salt.utils.which('hiera') else False def ext_pillar(minion_id, # pylint: disable=W0613
pillar, # pylint: disable=W0613
conf):
'''
Execute hiera and return the data
'''
cmd = 'hiera -c {0}'.format(conf)
for key, val in __grains__.items():
if isinstance(val, string_types):
cmd += ' {0}={1!r}'.format(key, val)
try:
data = yaml.safe_load(__salt__['cmd.run'](cmd))
except Exception:
log.critical(
'Hiera YAML data failed to parse from conf {0}'.format(conf)
)
return {}
return data

pillar是通过yaml定义的,通过yaml_safe_load后就是python的数据类型了,也就是说从外部获取的pillar数据就是python里面的字典类型数据,salt就完成了对pillar数据的定义;目前官方已经支持24种从外部获取pillar数据的方式,当然可以自己定义从哪些地方获取pillar数据;

2、ext_nodes

在定义完pillar之后,需要在top.sls文件中指定pillar和minion之间的对于关系,也就是哪些minion会应用这些pillar,也就是说需要让top.sls支持动态的功能

 

五、saltstack git文件服务器

 

扩展saltstack组件的更多相关文章

  1. .NET平台开源项目速览(5)深入使用与扩展SharpConfig组件

    上个月在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧  和 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 中都提到了SharpConfig组件,简单轻量级 ...

  2. [Unity]Unity3D编辑器插件扩展和组件扩展

    1. 插件扩展 1.1. 命名空间 using UnityEditor; using UnityEngine; //非必需,常用到 1.2. 使用语法 [MenuItem("Assets/M ...

  3. Unity插件扩展中组件常用的几个方法

    最近为美术编写一个Unity编辑器的扩展,主要为了减轻美术在修改预制对象时的机械化操作的繁琐和出错.具体实现的几个功能: 1.删除指定组件: 2.复制.粘贴指定的组件: 3.重新关联新的属性: 4.重 ...

  4. 动态扩展php组件(mbstring为例)

    1.进入源码包中的mbstring目录 cd ~/php-/ext/mbstring/ 2.启动phpize /usr/local/php/bin/phpize 3.配置configure ./con ...

  5. ionic之AngularJS扩展动态组件

    目录: 1. 模态对话框 : $ionicModal 2. 上拉菜单 : $ionicActionSheet 3. 弹出框 : $ionicPopup 4. 浮动框 : $ionicPopover 5 ...

  6. 《SaltStack技术入门与实践》—— Grains

    Grains 本章节参考<SaltStack技术入门与实践>,感谢该书作者: 刘继伟.沈灿.赵舜东 前几章我们已经了解SaltStack各个组件以及通过一个案例去熟悉它的各种应用,从这章开 ...

  7. 扩展 jquery miniui 组件实现自动查询数据

    主题 之前写过一篇文章分享了公司basecode查找数据后台是怎么实现的(http://www.cnblogs.com/abcwt112/p/6085335.html).今天想分享一下公司前台是怎么扩 ...

  8. JS组件系列——自己动手扩展BootstrapTable的treegrid功能

    前言:上篇  JS组件系列——自己动手封装bootstrap-treegrid组件 博主自己动手封装了下treegrid的功能,但毕竟那个组件只是一个单独针对树形表格做的,适用性还比较有限.关注博主的 ...

  9. Unity3D编辑器扩展(四)——扩展自己的组件

    前面已经写了三篇: Unity3D编辑器扩展(一)——定义自己的菜单按钮 Unity3D编辑器扩展(二)——定义自己的窗口 Unity3D编辑器扩展(三)——使用GUI绘制窗口 今天写第四篇,扩展自己 ...

随机推荐

  1. MapReduce高级编程

    MapReduce 计数器.最值: 计数器 数据集在进行MapReduce运算过程中,许多时候,用户希望了解待分析的数据的运行的运行情况.Hadoop内置的计数器功能收集作业的主要统计信息,可以帮助用 ...

  2. 如何在ubuntu系统里面用新加装的硬盘对系统进行扩容

    我这里是用256G的固态硬盘安装了系统,想通过扩展1T的机械硬盘存储数据的,现在我们需要的就是把这个1T的硬盘进行扩容进去 使用df -h和sudo fdisk -l命令查看磁盘情况 切换到root用 ...

  3. JavaScript基础知识点学习记录

    一.简介: JavaScript是一种基于对象和事件驱动并具有相对安全性的客户端脚本语言,同时也是一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态功能,比如相应用户的各种操作. J ...

  4. angularjs指令实现轮播图----swiper

    'use strict'; angular.module('app').directive('swipersLbt',swipers); swipers.$inject = ['$timeout']; ...

  5. join,fromkeys(),深浅拷贝

    1. 补充基础数据类型的相关知识点 1. str. join() 把列表变成字符串例 # s= "哈哈"# s1=s.join('-')# print(s1)# s="呵 ...

  6. StanFord ML 笔记 第六部分&&第七部分

    第六部分内容: 1.偏差/方差(Bias/variance) 2.经验风险最小化(Empirical Risk Minization,ERM) 3.联合界(Union bound) 4.一致收敛(Un ...

  7. datetime模块的简单用法

    import datetime print(datetime.datetime.today()) #2018-08-14 14:18:28.575412 print(datetime.date.tod ...

  8. Java Swing类 例子代码:将子类继承JFrame 并且接口按键监听ActionLisetener (将内容直接添加到JFrame不创建Contaniner)

    package rom; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import ...

  9. 浏览器预览office文件(word,Excel,等)

    提示:预览是通过后台转pdf到前台展示的过程,当然网上也有购买的api 举个栗子:(http://www.officeweb365.com/) <!DOCTYPE html> <ht ...

  10. iOS oc 检测手机移动网络和wifi是否开启

    利用Reachability的的一个方法currentReachabilityStatus 获取枚举类型值判断是否为2即可,不是2就不是WiFi. enum {        // DDG Netwo ...