CMDB на коленке

CMDB на коленке

Файлы

cmdb.db - база данных
cmdb.py - скрипт для работы с БД
create_tables.sql - скуль запрос создающий в пустой БД нужную таблицу. запуск: cat create_tables.sql | sqlite3 cmdb.db
read.me

Как я с этим работаю

./cmdb.py help
Usage: ./cmdb.py [list] [<id>]
   or: ./cmdb.py [list_html]
   or: ./cmdb.py [add <fqdn> <ip1>[,<ip2>,...] "<description>"]
   or: ./cmdb.py [remove <id>]
   or: ./cmdb.py [update_(fqdn|ip|descr) <id> "<string>"
   or: ./cmdb.py [clear_descr <id>]
   or: ./cmdb.py [search|find "<string>"]

Всё самое интересное в дескрипшене. С коллегами существует договоренность по каким правилам его заполнять. Общий принцип: <Категория1>:<список1>;<Категория2>:<список2>; и тд.

Например: Добавляем сервер у которого имя: s1.domain.tld; ip: 10.11.1.1 и 10.22.1.1; Операционка: RHEL5, сам он: вмварная виртуалка и назначение у него - вебсервер для тестеров; Локация: DC1

./cmdb.py add s1.domain.tld 10.11.1.1,10.22.1.1 "OS:RHEL5;Virt:Vmware;L:DC1;F:web,test;"

Ищем этот сервер:

./cmdb.py find s1.domain.tld
581|s1.domain.tld|10.11.1.1,10.22.1.1|F:web,test;Virt:Vmware;OS:RHEL5;L:DC1;

Переносим его в другую локацию:

./cmdb.py update_descr 581 "L:DC2;"
./cmdb.py find s1.domain.tld
581|s1.domain.tld|10.11.1.1,10.22.1.1|F:web,test;Virt:Vmware;OS:RHEL5;L:DC2;

Удаляем:

./cmdb.py remove 581
./cmdb.py find s1.domain.tld

Содержимое файлов

read.me

servername
=========

FQDN name

iplist
======

ip1[,ip2,ip3...]

description
===========

[OS:<operating_system>;][Virt:<Zone|Vmware|PowerVM>;][Owner:<servername>;][Aliases:<alias1,alias2,alias3,...>;][F:<function1,function2,...>;][HW:<hardware>;][L:<location>;][MGMT:<hostname,...>;][PWR:<ON|OFF>;][MEM:<size><G|M>]

<operating_system>: AIX5.3|AIX6.1|RHEL4|RHEL5|CentOS5|Ubuntu12.04|Solaris10|Solaris8|Solaris9

<location>: DC1|DC2|DC3

<hardware>: HP_DL380_G4|HP_DL380_G5|SPARC-Enterprise-T5220|Sun-Fire-T1000|Sun-Fire-T2000|Sun-Fire-V240

=========================
for update cmdb.html type:

./cmdb.py list_html > cmdb.html
 
backup cmdb
===========

echo '.dump' | sqlite ./cmdb.db | gzip -c > cmdb.dump.`date +%Y%m%d`.gz

create_tables.sql

create table if not exists cmdb (
    id  integer primary key autoincrement,
    servername text unique not null,
    iplist  text,
    description text
);

cmdb.py

   1 #!/usr/bin/env python
   2 # -*- coding: utf-8 -*-
   3 # filename: cmdb.py
   4 
   5 
   6 import socket
   7 import time
   8 try:
   9     import sqlite3 as sqlite
  10 except:
  11     import sqlite
  12 
  13 CMDB_DB="./cmdb.db"
  14 
  15 
  16 def descr_to_dict(string):
  17     """ String --> dict()
  18     String: "OS:Ubuntu12.04;Virt:Vmware;Aliases:msk-www-test3;F:test,web;L:DC1;"
  19     """
  20     return dict([ [a, b.split(',')] for a,b in [i.split(':') for i in string.split(';')][:-1]])
  21 
  22 def is_ip_correct(ip):
  23     if len(ip.split('.')) == 4:
  24         try:
  25             socket.inet_aton(ip)
  26             return True
  27         except socket.error:
  28             return False
  29     else:
  30         return False
  31 
  32 def check_ip_list(ip_list):
  33     return [ip for ip in ip_list if is_ip_correct(ip)]
  34 
  35 class AttrDisplay(object):
  36     def __str__(self):
  37         attrs = []
  38         for key in sorted(self.__dict__):
  39             attrs.append('%s=%s' % (key, getattr(self, key)))
  40         return "[%s: %s]" % (self.__class__.__name__, ' | '.join(attrs))
  41 
  42 class Server(AttrDisplay):
  43     """ Class for server """
  44 
  45     def set_description(self, dic):
  46         for key, item in dic.items():
  47             self.__setattr__(key, item)
  48 
  49     def set_ip_list(self, ip_list):
  50         if issubclass(type(ip_list), list):
  51             self.ip_list = check_ip_list(ip_list)
  52         else:
  53             raise TypeError("ip_list must be list type.")
  54 
  55     def __init__(self, fqdn, ip_list, dic=None, s_id=None):
  56         self.fqdn = fqdn
  57         self.s_id = s_id
  58         self.set_ip_list(ip_list)
  59         if not dic is None:
  60             self.set_description(dic)
  61 
  62     def get_fqdn(self):
  63         return self.fqdn
  64 
  65     def set_fqdn(self, fqdn):
  66         self.fqdn = fqdn
  67 
  68     def get_info(self):
  69         d = dict(self.__dict__)
  70         fqdn = d.pop('fqdn')
  71         ip = ','.join(d.pop('ip_list'))
  72         s_id = d.pop('s_id')
  73         s = "%s|" % s_id
  74         s += "%s|" % fqdn
  75         s += "%s|" % ip
  76         descr = ""
  77         for k,i in d.items():
  78             if isinstance(i,list):
  79                 descr +="%s:%s;" % (k, ','.join(list(i)))
  80             else:
  81                 descr +="%s:%s;" % (k, i)
  82         return s + descr
  83 
  84     def get_ip_list(self):
  85         return list(self.ip_list)
  86 
  87     def clear_descr(self):
  88         d = dict(self.__dict__)
  89         d.pop('fqdn')
  90         d.pop('ip_list')
  91         d.pop('s_id')
  92         for k,i in d.items():
  93             self.__delattr__(k)
  94 
  95     def get_descr(self):
  96         d = dict(self.__dict__)
  97         d.pop('fqdn')
  98         d.pop('ip_list')
  99         d.pop('s_id')
 100         return d
 101 
 102     def get_id(self):
 103         return self.s_id
 104 
 105 class CMDBase(AttrDisplay):
 106     """ CMD Base class """
 107 
 108    # Internal methods
 109     def _open_db(self):
 110         if not self._opendb_flag:
 111             self.connect = sqlite.connect(self.cmdb_db)
 112             self.cursor = self.connect.cursor()
 113             self._opendb_flag = True
 114 
 115     def __init__(self, cmdb_db=CMDB_DB):
 116         self.cmdb_db = cmdb_db
 117         self._opendb_flag = False
 118         self._open_db()
 119 
 120     def _commit_db(self):
 121         if self._opendb_flag:
 122             self.connect.commit()
 123 
 124     def _exec_query(self, query, commit=True):
 125         if not self._opendb_flag:
 126             self._open_db()
 127         self.cursor.execute(query)
 128         if commit:
 129             self._commit_db()
 130 
 131     def _get_query_result(self):
 132         return self.cursor.fetchall()
 133 
 134     def close_db(self, commit=True):
 135         if self._opendb_flag:
 136             if commit:
 137                 self.connect.commit()
 138             self.cursor.close()
 139             self.connect.close()
 140             self._opendb_flag = False
 141 
 142     # Public methods
 143     def get_server_list(self, s_id=None, search=None):
 144         if not self._opendb_flag:
 145             self._open_db()
 146         if s_id is None:
 147             self._exec_query("select * from cmdb", commit=False)
 148         else:
 149             self._exec_query("select * from cmdb where id='%s'" % s_id, commit=False)
 150         if search is not None:
 151             query = """select * from cmdb 
 152                             where description LIKE '%%%s%%' or 
 153                                 servername LIKE '%%%s%%' or 
 154                                 iplist LIKE '%%%s%%'""" % (search, search, search)
 155             self._exec_query(query, commit=False)
 156         res = self._get_query_result()
 157         return [ Server(r[1], r[2].split(','), s_id=r[0], dic=descr_to_dict(r[3])) for r in res ]
 158 
 159     def get_server_by_name(self, s_id=None, search=None):
 160         if not self._opendb_flag:
 161             self._open_db()
 162         if search is not None:
 163             query = """select * from cmdb where servername='%s' """ % (search)
 164             self._exec_query(query, commit=False)
 165         res = self._get_query_result()
 166         return [ Server(r[1], r[2].split(','), s_id=r[0], dic=descr_to_dict(r[3])) for r in res ]
 167 
 168     def get_server(self, s_id):
 169         return self.get_server_list(s_id=s_id)[0]
 170 
 171     def add_server(self, fqdn, ip_list, descr):
 172         srv = Server(fqdn.lower(), ip_list.split(','), dic=descr_to_dict(descr))
 173         inf = srv.get_info().split('|')
 174         self._exec_query(
 175             "insert into cmdb (servername, iplist, description) values ('%s', '%s', '%s');" % (inf[1],inf[2], inf[3] ))
 176 
 177     def remove_server(self, s_id):
 178         self._exec_query("delete from cmdb where id = '%s';" % s_id)
 179 
 180     def update_server(self, s_id, fqdn=None, ip_list=None, descr=None):
 181         srv = self.get_server(s_id)
 182         if fqdn:
 183             srv.set_fqdn(fqdn.lower())
 184         if ip_list:
 185             srv.set_ip_list(ip_list)
 186         if descr:
 187             srv.set_description(descr_to_dict(descr))
 188         inf = srv.get_info().split('|')
 189         query = "update cmdb set servername='%s', iplist='%s', description='%s' where id='%s';"
 190         self._exec_query(query % (inf[1],inf[2], inf[3], inf[0]))
 191 
 192     def clear_descr_server(self, s_id):
 193         srv = self.get_server(s_id)
 194         srv.clear_descr()
 195         inf = srv.get_info().split('|')
 196         query = "update cmdb set servername='%s', iplist='%s', description='%s' where id='%s';"
 197         self._exec_query(query % (inf[1],inf[2], inf[3], inf[0]))
 198 
 199 def print_server_list(lst):
 200     for l in lst:
 201         print l.get_info()
 202 
 203 def print_html(lst):
 204     print "<html><title>SERVERS LIST</title>"
 205     print '<style type="text/css"> table {border-collapse:collapse;} table,td,th {border: 1px solid #333;} </style>'
 206     print "<body>"
 207     print '<h1>SERVER LIST</h1>'
 208     print '<p><font color="green" size=+2><b>%s</b></font></p>' % time.ctime()
 209     print "<table>"
 210     for n,l in enumerate(lst):
 211         s = l.get_info().split('|')
 212         print "<tr valign=top><td><b>%s</b></td><td width='15%%'>%s</td><td>%s</td><td><b>%s</td></tr>" % (
 213                 n+1,
 214                 s[1],
 215                 '<br />'.join(s[2].split(',')),
 216                 ', '.join(
 217                         '</b>: '.join(
 218                             '<br /><b>'.join(
 219                                     s[3].split(';')[:-1]
 220                                             ).split(':')
 221                                     ).split(',')
 222                         )
 223                 )
 224     print "</table></body></html>"
 225 
 226 def main():
 227     import sys
 228     db = CMDBase()
 229     if len(sys.argv) == 1:
 230         lst = db.get_server_list()
 231         print_server_list(lst)
 232     elif sys.argv[1].upper() == 'LIST':
 233         if len(sys.argv) > 2:
 234             lst = db.get_server_list(sys.argv[2])
 235         else:
 236             lst = db.get_server_list()
 237         print_server_list(lst)
 238     elif sys.argv[1].upper() == 'ADD' and len(sys.argv) == 5:
 239         db.add_server(sys.argv[2], sys.argv[3], sys.argv[4])
 240     elif sys.argv[1].upper() == 'REMOVE' and len(sys.argv) == 3:
 241         db.remove_server(sys.argv[2])
 242     elif sys.argv[1].upper() == 'UPDATE_FQDN' and len(sys.argv) == 4:
 243         db.update_server(sys.argv[2], fqdn=sys.argv[3])
 244     elif sys.argv[1].upper() == 'UPDATE_IP' and len(sys.argv) == 4:
 245         db.update_server(sys.argv[2], ip_list=sys.argv[3].split(','))
 246     elif sys.argv[1].upper() == 'UPDATE_DESCR' and len(sys.argv) == 4:
 247         db.update_server(sys.argv[2], descr=sys.argv[3])
 248     elif sys.argv[1].upper() == 'CLEAR_DESCR' and len(sys.argv) == 3:
 249         db.clear_descr_server(sys.argv[2])
 250     elif sys.argv[1].upper() == 'LIST_HTML':
 251         lst = db.get_server_list()
 252         lst.sort(key=lambda n: n.fqdn)
 253         print_html(lst)
 254     elif (sys.argv[1].upper() == 'SEARCH' or sys.argv[1].upper() == 'FIND') and len(sys.argv) == 3:
 255         lst = db.get_server_list(search=sys.argv[2])
 256         print_server_list(lst)
 257     elif (sys.argv[1].upper() == 'GET') and len(sys.argv) == 3:
 258         lst = db.get_server_by_name(search=sys.argv[2])
 259         print_server_list(lst)
 260     else:
 261         sys.stderr.write("Usage: %s [list] [<id>]\n" % sys.argv[0])
 262         sys.stderr.write("   or: %s [list_html]\n" % sys.argv[0])
 263         sys.stderr.write("   or: %s [add <fqdn> <ip1>[,<ip2>,...] \"<description>\"]\n" % sys.argv[0])
 264         sys.stderr.write("   or: %s [remove <id>]\n" % sys.argv[0])
 265         sys.stderr.write("   or: %s [update_(fqdn|ip|descr) <id> \"<string>\"\n" % sys.argv[0])
 266         sys.stderr.write("   or: %s [clear_descr <id>]\n" % sys.argv[0])
 267         sys.stderr.write("   or: %s [search|find \"<string>\"]\n" % sys.argv[0])
 268     db.close_db()
 269     return 0
 270 
 271 if __name__ == '__main__':
 272     main()