從cmdb獲取原始主機資訊生成ansible的hosts檔案
阿新 • • 發佈:2018-11-08
#!/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()