自動化運維工具Ansible之動態inventory文件

去年的時候開發了一個自動化運維的小系統,用的就是Ansible 的python API,其中動態從數據庫獲取主機組合主機變量的功能,着實費了老大的勁,最後用了個很雞肋的方法實現了。最近幾個月把Ansible的官方文檔通看了一遍,哎,想死的心都有了,文檔裏面已經寫的很清楚如何實現動態inventory文件了,就怪當時自己太着急,沒仔細看文檔。

自己開發的動態inventory腳本文件,只需要支持兩個參數即可:

--list 返回所有的主機組信息,每個組都應該包含字典形式的主機列表,子組列表,如果需要的話還應該組變量,最簡單的信息是隻包含主機列表,返回的數據格式要是JSON格式的。

--host <hostname> 返回該主機的變量列表,或者是返回一個空的字典,JSON格式。


參數--list訪問腳本的時候,返回數據結果:


    {
        "databases"   : {
            "hosts"   : [ "host1.example.com", "host2.example.com" ],
            "vars"    : {
                "a"   : true
            }
        },
        "webservers"  : [ "host2.example.com", "host3.example.com" ],
        "atlanta"     : {
            "hosts"   : [ "host1.example.com", "host4.example.com", "host5.example.com" ],
            "vars"    : {
                "b"   : false
            },
            "children": [ "marietta", "5points" ]
        },
        "marietta"    : [ "host6.example.com" ],
        "5points"     : [ "host7.example.com" ]
    }


databses,webservers,atlanta,marietta,5points爲主機組名稱,hosts爲該主機組下的主機列表,vars爲主機組的變量,children爲該主機組的子組列表。


參數--host <hostname>訪問腳本的時候,返回的數據結果,如果沒有主機變量則返回一個空的字典:

    {
        "favcolor"   : "red",
        "ntpserver"  : "wolf.example.com",
        "monitoring" : "pack.example.com"
    }


 但是如果針對每個主機都調用一次`--host`的話,將會產生大量的資源開銷。在Ansible1.3或之後的版本中,如果腳本返回了一個稱爲`_meta`的頂級元素,該元素中如果包含着`hostvars`關鍵字,那麼就可以將所有主機的變量都返回。腳本也不會再爲每個主機都調用一次`--host`,這講節省大量的資源開銷,同時也方便的客戶端的緩存。
返回的`_meta`類似如下格式:


    {
    
        # results of inventory script as above go here
        # ...
    
        "_meta" : {
           "hostvars" : {
              "moocow.example.com"     : { "asdf" : 1234 },
              "llama.example.com"      : { "asdf" : 5678 },
           }
        }
    
    }

所返回的變量可以在模板中引用。

示例:

動態腳本內容


[root@web1 ~]# cat /etc/ansible/getHosts.py 
    #!/usr/bin/python
    import argparse
    try:
        import json
    except ImportError:
        import simplejson as json
    
    '''這裏是模擬數據,工作上一般該數據都是從數據庫或者緩存中讀取的'''
    mockData = {
        "webservers":{
            "hosts": ["192.168.1.65"],
            "vars":{
                "http_port":8888,
                "max_clients":789
            }
        },
    
        "databases":{
            "hosts":["192.168.1.65"],
            "vars":{
                "action":"Restart MySQL server."
            }
        }
    }
    '''模擬數據結束'''
    def getList():
        '''get list hosts group'''
        print json.dumps(mockData)
    
    
    def getVars(host):
        '''Get variables about a specific host'''
        print json.dumps(mockData[host]["vars"])
    
    
    if __name__ == "__main__":
    
        parser = argparse.ArgumentParser()
        parser.add_argument('--list',action='store_true',dest='list',help='get all hosts')
        parser.add_argument('--host',action='store',dest='host',help='get all hosts')
        args = parser.parse_args()
    
        if args.list:
            getList()
    
        if args.host:
            getVars(args.host)

該腳本支持兩個參數--list和--host。


playbook內容:

[root@web1 ~]# cat /etc/ansible/test.yml 
    ---
    - hosts: webservers
      remote_user: root
      tasks:
        - name: config httpd.file
          template: src=/etc/ansible/httpd.j2 dest=/etc/httpd.conf

執行命令:


[root@web1 ansible]# ansible-playbook -i /etc/ansible/getHosts.py /etc/ansible/test.yml
    
    PLAY [webservers] ************************************************************* 
    
    GATHERING FACTS *************************************************************** 
    ok: [192.168.1.65]
    
    TASK: [config httpd.file] ***************************************************** 
    changed: [192.168.1.65]
    
    PLAY RECAP ******************************************************************** 
    192.168.1.65               : ok=2    changed=1    unreachable=0    failed=0   
    
    [root@web1 ansible]# ansible -i /etc/ansible/getHosts.py databases -m shell -a "echo {{ action }}"192.168.1.65 | success | rc=0 >>
    Restart MySQL server.

Python API調用動態inventory:

[root@web1 ~]# cat an.py 
    #!/usr/bin/env python
    
    import ansible.runner
    
    runner = ansible.runner.Runner(
        module_name='shell',
        module_args='echo {{ action }}',
        pattern='databases',
        host_list='/etc/ansible/getHosts.py',
        forks=10
    )
    
    data = runner.run()
    print data
    [root@web1 ~]# python an.py 
    {'dark': {}, 'contacted': {u'192.168.1.65': {u'cmd': u'echo Restart MySQL server.', u'end': u'2015-08-07 15:26:02.141350', u'stdout': u'Restart MySQL server.', u'changed': True, u'start': u'2015-08-07 15:26:02.128109', u'delta': u'0:00:00.013241', u'stderr': u'', u'rc': 0, 'invocation': {'module_name': 'shell', 'module_args': u'echo Restart MySQL server.'}, u'warnings': []}}}

總的來說,只要腳本文件支持--list和--host <hostname>參數,並且返回的結果是文檔所指定的格式,就不會出現什麼問題。

好吧,就寫到這了,趕緊更新自己的運維繫統中的動態腳本去.......

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章