1. 程式人生 > >從cmdb獲取原始主機資訊生成ansible的hosts檔案

從cmdb獲取原始主機資訊生成ansible的hosts檔案

#!/usr/bin/env python
#-*- coding: utf-8 -*-
#Description:應用場景,從cmdb中直接獲取主機資訊,然後生成ansible支援的ini格式inventory檔案;並且劃分了原子組、業務組(高階分組)、應用組(高階分組),其中,原子組是業務組和應用組的交集名稱,業務組和應用組的成員都是原子組;

import shutil
import os
from datetime import datetime
import logging
import ConfigParser
import re
import requests
import json
import sys
reload(sys)
sys.setdefaultencoding('utf8')

#變數、配置初始化
#backuptime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
backuptime = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
logging.basicConfig(filename="inventory.log", level = logging.DEBUG,
                    format='levelname: %(levelname)s, process-id: %(process)d, filename: %(filename)s, messages: %(message)s')
hosts_all = []
atomic_groups = []
advanced_groups_app = []
advanced_groups_business = []

#從資料庫獲取主機資訊資料,看實際情況返回的資料結構型別,最終所有的主機要構造成一個列表,備用;
#comment: 備註
#service: 執行的服務
#idc: 機房名稱
#project:所屬專案,主機組
#eth1: 公網IP
#eth2: 內網IP
def get_hosts_all():
    token = 'yyyyyyyyyyyyyyyyyyyyyy'
    headers = {'token': token}
    url = 'http://xxxxxxxx:xxxx/yyyyyy/get_hosts/'
    res = requests.get(url=url, headers=headers)
    for i in res.json():
        re1 = r'^[a-z]+'
        comment = i['comment']
        lcomment = comment.split(';')
        if re.match(re1, comment) and re.search('lt;', comment):
            #過濾掉lt-test、lt-gray組的機器,構造一個完全lt組的主機名列表
            if 'lt-' not in comment:
                sighost = lcomment[0]
                hosts_all.append(sighost)
    return hosts_all

#備份ansible原來的inventory檔案
def backup_ansible_inventory():
    bakFile = 'hosts_' + backuptime
    if os.path.isfile('hosts'):
        if not os.path.isfile(bakFile):
            shutil.move('hosts', bakFile)

#構造初始的原子組列表
def build_atomic_groups():
    with open('init_atomic_groups_name.txt', 'r') as iagn:
        iagn_lines = iagn.readlines()
    for iagn_line in iagn_lines:
        iagn_line = iagn_line.strip()
        atomic_groups.append(iagn_line)
    return atomic_groups

#構造初始的高階分組列表,基於應用名稱
def build_advanced_groups_app():
    with open('init_advanced_groups_app.txt', 'r') as iaga:
        iaga_lines = iaga.readlines()
    for iaga_line in iaga_lines:
        iaga_line = iaga_line.strip()
        advanced_groups_app.append(iaga_line)
    # print 'advanced_groups_app: ', advanced_groups_app
    return advanced_groups_app

#構造初始的高階分組列表,基於業務模組
def build_advanced_groups_business():
    with open('init_advanced_groups_business.txt', 'r') as iagb:
        iagb_lines = iagb.readlines()
    for iagb_line in iagb_lines:
        iagb_line = iagb_line.strip()
        advanced_groups_business.append(iagb_line)
    # print 'advanced_groups_business: ', advanced_groups_business
    return advanced_groups_business

#構造ConfigParser物件,並初始化section物件,包括初始化的原子組和高階分組
def build_sections():
    conf = ConfigParser.ConfigParser(allow_no_value = True)
    for agroup in atomic_groups:
        conf.add_section(agroup)
    return conf

#構造一個原子組名的正則表示式列表,用於匹配hosts主機名,然後放到對應的原子組中;
def gen_groups_re(atomic_groups):
    global groups_re
    groups_re = []
    for group_re in atomic_groups:
        group_re = group_re.split('_')
        group_re[0] = group_re[0] + '[0-9]*'
        group_re = '.'.join(group_re)
        groups_re.append(group_re)
    return groups_re

#開啟hosts配置檔案,準備寫入
def main():
    with open('hosts', 'wb+') as host_file:
        groups_re = gen_groups_re(atomic_groups)
        groups_re_num = len(groups_re)
        groups_app_num = len(advanced_groups_app)
        groups_business_num = len(advanced_groups_business)
        print 'init_groups_business_num: ', groups_business_num
        print 'init_groups_app_num: ', groups_app_num
        # print "groups_re_num: ", groups_re_num
        #遍歷所有主機名
        for h in hosts_all:
            #遍歷所有正則表示式,將主機名與正則表示式列表進行匹配,如果沒有匹配的,則建立新的原子組名稱,並把該主機新增到新增的原子組內,此時資料都還是在記憶體中的ConfigParser物件中;
            h_i = 0
            for r in groups_re:#[1,2,3]
                match = re.search(r, h)
                if match:
                    #從正則表示式構造對應的原子組名稱
                    group_tmp = r.split('.')
                    group_tmp[0] = group_tmp[0].split('[')[0]
                    group_tmp = '_'.join(group_tmp)
                    conf.set(group_tmp, h)
                    break
                else:
                    h_i += 1
            #如果迴圈次數與已有原子組個數相等,則說明該主機沒有屬於的原子組,需要增加原子組並把該主機新增到該原子組中;
            if h_i == groups_re_num:
                new_group = h.split('.')
                new_group[0] = re.sub(r'[0-9]+', '', new_group[0])
                new_group = '_'.join(new_group[0:3])
                print 'new_group: ', new_group
                #更新原子組名稱列表
                atomic_groups.append(new_group)
                #更新正則表示式列表
                groups_re = gen_groups_re(atomic_groups)
                groups_re_num = len(groups_re)
                #更新原子組初始化檔案
                with open('init_atomic_groups_name.txt', 'a') as iagn:
                    iagn.write('\n' + new_group)
                conf.add_section(new_group)
                conf.set(new_group, h)
                print 'host: {0}, h_i: {1}'.format(h,h_i)

        #此時ConfigParser物件還在記憶體中,沒有消失,後面再add_sections,則是在寫入到檔案那一刻時的內容後面再次追加了;檔案的追加和ConfigParser物件內容的追加是兩個概念;
        #構造基於應用名稱的高階分組
        for appgroup in advanced_groups_app:
            conf.add_section(appgroup)
        for g in atomic_groups:
            j = 0
            for k in advanced_groups_app:
                kre = k + '_'
                kmatch = re.match(kre, g)
                if kmatch:
                    conf.set(k, g)
                    break
                else:
                    j += 1
            if j == groups_app_num:
                new_group_app = g.split('_')[0]
                print 'new_group_app: ', new_group_app
                #更新advanced_groups_app列表,下一次迴圈開始使用最新的列表;
                advanced_groups_app.append(new_group_app)
                #更新groups_app_num的值;
                groups_app_num = len(advanced_groups_app)
                with open('init_advanced_groups_app.txt', 'a') as iaga:
                    iaga.write('\n' + new_group_app)
                conf.add_section(new_group_app)
                conf.set(new_group_app, g)
                print 'advanced_groups_app new: ', advanced_groups_app
        #
        #
        #構造基於業務模組的高階分組
        for busgroup in advanced_groups_business:
            conf.add_section(busgroup)
        for g in atomic_groups:
            j = 0
            # print 'business_g: ', g
            for k in advanced_groups_business:
                kre = '_' + k
                kmatch = re.search(kre, g)
                if kmatch:
                    conf.set(k, g)
                    break
                else:
                    j += 1
            # print 'bussiness_j: ', j
            if j == groups_business_num:
                new_group_business = g.split('_')
                new_group_business = '_'.join(new_group_business[1:])
                # print 'new_group_business: ', new_group_business
                #更新advanced_groups_app列表,下一次迴圈開始使用最新的列表;
                advanced_groups_business.append(new_group_business)
                #更新groups_business_num的值,下一次迴圈開始使用;
                groups_business_num = len(advanced_groups_business)
                with open('init_advanced_groups_business.txt', 'a') as iagb:
                    iagb.write('\n' + new_group_business)
                conf.add_section(new_group_business)
                conf.set(new_group_business, g)
        conf.write(host_file)

if __name__ == '__main__':
    backup_ansible_inventory()
    hosts_all = get_hosts_all()
    atomic_groups = build_atomic_groups()
    advanced_groups_app = build_advanced_groups_app()
    advanced_groups_business = build_advanced_groups_business()
    conf = build_sections()
    main()