ansible-自定义/扩展facts信息组件

一.简述:

    当公司业务达到一定规模后,不同的业务,部署不同的服务/组件,很有必要用一些方法(静态文件/主机名?)标识出相应的主机角色(所属项目),有的还会同公司的CMDB平台做数据同步便于维护。 在以上描述的多role的复杂环境下,在使用ansible的过程中, 难免会通过facts采集一些数据的信息,然而ansible默认搜集的信息基本上是根据机器属性相关;而无法搜集业务相关的信息,好消息是,尽管ansible不能默认搜集相关信息,但是却支持自定义facts信息采集的插件。

二. facts使用简述:

一般情况下ansible可以通过setup模块采集facts信息。setup的源码如下:

def main():
    module = AnsibleModule(
        argument_spec = dict(
            gather_subset=dict(default=["all"], required=False, type='list'),
            filter=dict(default="*", required=False),
            fact_path=dict(default='/etc/ansible/facts.d', required=False),
        ),
        supports_check_mode = True,
    )
    data = get_all_facts(module)
    module.exit_json(**data)

# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.facts import *

if __name__ == '__main__':
    main()

可发现,setup定义了一个main函数,然后加载了module_utils.basic和facts数据,打开facts.py可看一下代码片段:

    def __init__(self, module, load_on_init=True):
        self.module = module
        self.facts = {}
        ### TODO: Eventually, these should all get moved to populate().  But
        # some of the values are currently being used by other subclasses (for
        # instance, os_family and distribution).  Have to sort out what to do
        # about those first.
        if load_on_init:   #采集信息的函数如下,如不需要可注释相关的方法(platform_facts有依赖,不能注释)
            self.get_platform_facts()
            self.get_distribution_facts()
            self.get_cmdline()
            self.get_public_ssh_host_keys()
            self.get_selinux_facts()
            self.get_caps_facts()
            self.get_fips_facts()
            self.get_pkg_mgr_facts()
            self.get_service_mgr_facts()
            self.get_lsb_facts()
            self.get_date_time_facts()
            self.get_user_facts()
            self.get_local_facts()
            self.get_env_facts()
            self.get_dns_facts()
            self.get_python_facts()

可发现Facts类初始化会执行一下相关的函数采集相关的facts信息,其中get_local_facts()可从被控制机上读取文件,作为facts信息进行搜集,这种情况下,我们就可以通过将被控制机上的一些信息写入相关文件,即可通过ansible的采集。get_local_facts内容如下:

    def get_local_facts(self):
        fact_path = self.module.params.get('fact_path', None)  #获取facts文件路径(main中定义)
        if not fact_path or not os.path.exists(fact_path):
            return

        local = {}
        for fn in sorted(glob.glob(fact_path + '/*.fact')):  #for facts文件路径下所以*.fact结尾的文件
            print fn
            # where it will sit under local facts
            fact_base = os.path.basename(fn).replace('.fact','')
            if stat.S_IXUSR & os.stat(fn)[stat.ST_MODE]:
                # run it
                # try to read it as json first
                # if that fails read it with ConfigParser
                # if that fails, skip it
                rc, out, err = self.module.run_command(fn)
            else:
                out = get_file_content(fn, default='')

            fact = 'loading %s' % fact_base
            try:                  #尝试用json解析,失败用configparser(fact文件内容只支持json或INI).
                fact = json.loads(out)
            except ValueError:
                # load raw ini
                cp = configparser.ConfigParser()
                try:
                    cp.readfp(StringIO(out))
                except configparser.Error:
                    fact = "error loading fact - please check content"
                else:
                    fact = {}
                    #print cp.sections()
                    for sect in cp.sections():
                        if sect not in fact:
                            fact[sect] = {}
                        for opt in cp.options(sect):
                            val = cp.get(sect, opt)
                            fact[sect][opt]=val

            local[fact_base] = fact
        if not local:
            return
        self.facts['local'] = local            #赋值

注意ansible默认只处理/etc/ansible/facts.d下以.fact结尾的文件,并且文件内容只能是json格式或者INI格式。知道了ansible facts的处理过程后,就好解决了, 可以在被控制机上/etc/ansible/facts.d(也可以通过指定或修改默认路径)创建一个fact结尾的文件:

# mkdir -p /etc/ansible/facts.d/
# vim /etc/ansible/facts.d/test.fact
{"name":"xiang.xiao3", "dicttest":{"AA":"BB"}}

执行setup测试如下:

# ansible test -m setup -a "filter=ansible_local"
BJCER11-18.opi.com | SUCCESS => {
    "ansible_facts": {
        "ansible_local": {
            "ansible": {
                "dicttest": {
                    "AA": "BB"
                }, 
                "name": "xiang.xiao3"
            }
        }
    }, 
    "changed": false
}

采集OK 。。。。。。。

上面一种情况用于在默认facts的基础上做相应的扩展,但其实很多时候我们并不会使用所采集的信息,比如,hosts定义的是主机名,我只想采集主机上的ip,其他的都不需要,或者想采集默认facts信息中没有的信息, 这种情况下,就不太适合使用facts.d的方式(并且,执行默认的facts采集,本人测试大概会需要3s钟的时间,比较长了),解决方式是:禁用默认的facts,采用自己写的模块!

三. 自定义facts模块

如果自定义facts模块的话,需要注意下路径问题,配置文件中可通过library参数指定或者使用ANSIBLE_LIBRARY环境变量指定,或者ansible目录下的library目录下(后两种方式这里就不说了),本人的library配置如下:

library        = /usr/share/my_modules/

在library目录下创建一个ipinfo的模块,内容如下:

#!/usr/bin/python
DOCUMENTATION = """    #简介
test
test
"""

EXAMPLES="""          #案例
- info: test 
"""
import sys
import shlex
import json
import socket

hosts = socket.gethostname()
ips = socket.gethostbyname(hosts)    #通过主机名获取ip

args_file = sys.argv[1]
args_data = file(args_file).read()
argu = shlex.split(args_data)
for i in argu:
    if "=" in i:
        (key,value) = i.split("=")
        if key == "enable" and value == "yes":
            print json.dumps({"ansible_facts":{"ipp":ips}})

注:  采集的数据必须json格式,且放在key名为'ansible_facts' 的key下,否则。。。。等着纠结吧!!!!

然后配置playbook:

---
- hosts: test
  #gather_facts: False
  tasks:
      - name: req value
        ipinfo: enable=yes

      - name: copy nginx.conf
        debug: msg="value:{{ ipp }}"

执行结果如下:

TASK [copy nginx.conf] *********************************************************
ok: [BJCER11-18.opi.com] => {
    "msg": "value:10.5.11.18"
}

ad-hoc执行方式:

# ansible test -m ipinfo -a "enable=yes"
BJCER11-18.opi.com | SUCCESS => {
    "ansible_facts": {
        "ipp": "10.5.11.18"
    }, 
    "changed": false
}

如有需求,细节上的可自行修改!

 ----------------------------------------------------------------------------------------------

深耕运维行业多年,擅长linux、容器云原生、运维自动化等方面。
承接各类运维环境部署、方案设计/实施、服务代运维工作,欢迎沟通交流 !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值