#!/usr/bin/env python
# -*- coding: utf-8 -*
import requests
import re
import logging
import sqlite3
from sys import stdout
#path.append(r'..\NMS\clsNMS')
from clsNMS.nms_search import cls_search
from clsNMS.const import VLAN_ID
from urllib3 import exceptions as url_ex
from socket import timeout
from bs4 import BeautifulSoup
from threading import Thread
# форматируем записи
formatter= logging.Formatter('%(asctime)s %(levelname)9s %(message)s', "%Y-%m-%d %H:%M:%S")
# создаём объект с именем модуля
logger = logging.getLogger('term_info')
logger.setLevel(logging.INFO)
# создаём обрабочтик лога в файл
handler = logging.FileHandler('terminfo.log', 'a', encoding='utf-8')
handler.setLevel(logging.DEBUG)
handler.setFormatter(formatter)
logger.addHandler(handler)
# создаём обрабочтик лога в консоль
console = logging.StreamHandler(stdout)
console.setFormatter(formatter)
#console.setLevel(logging.INFO)
logger.addHandler(console)
nms = cls_search()
vno = 'starblazer'
ip_all = []
for s in [VLAN_ID['ya'][vno], VLAN_ID['am5'][vno], VLAN_ID['am7'][vno]]:
for i in nms.list_station_route(s):
ip_all.append(i['addr'])
soft_term = list()
with_passdw = []
class info():
'''
Получение информации с терминала и добавление ее в глобальную переменную soft_term
'''
def __init__(self):
pass
def read_info(self, ip):
'''
читаем первую строку с адреса http://{ip}/ss30
и приводим к виду (ip, soft, ver, sn}
:param ip:
:return:
'''
try:
url = f'http://{ip}/ss30'
r = requests.get(url, timeout=5)
soup = BeautifulSoup(r.text.encode(), features="lxml").text.split('\n')
mask = re.sub(r'^[\W\w\s_-]+!', '', soup[0])
try:
soft, ver, sn = map(str.strip, re.split(r'\s[A-Za-z]*:\s', mask.strip()))
except ValueError:
logger.info(f'терминал с ip {ip} запаролен')
with_passdw.append(ip)
return False
soft_term.append ((ip, soft, ver, sn))
debug = f'{ip:15s}Get data'
logger.info(debug)
return True
except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout, url_ex.ReadTimeoutError,
timeout, requests.exceptions.ConnectionError) as e:
logger.debug(f'{ip:15s}Connection timeout')
def check_term (ip):
'''
функция вызывает метод класса, который снимает информацию с терминала
нужна для запуска нескольких копий в разных потоках
:param ip: массив проверяемых ip адресов
'''
for i in ip:
s.read_info(i)
def split_list(alist, wanted_parts=1):
'''
Функция длч разития списка на n частей
:param alist: Список
:param wanted_parts: количество частей, на которое его нужно разбить
:return: список n списков
'''
length = len(alist)
return [ alist[i*length // wanted_parts: (i+1)*length // wanted_parts]
for i in range(wanted_parts) ]
def clear_db():
'''
# Очищаем БД (если надо проверить все вновь)
:return:
'''
sql = 'delete from term_info;'
cursor.execute(sql)
conn.commit()
#################################################
s = info()
# Cоединение с БД и получение курсора для дальнейшего взаимодействия
db = r'e:\SQLite\DB\term_info.db'
conn = sqlite3.connect(database=db)
cursor = conn.cursor()
# Очищаем БД (если надо проверить все вновь)
# clear_db()
# Получаем список уже проверенных ip адресов
sql = 'select ip from term_info;'
detect_ip = list(sum(cursor.execute(sql).fetchall(), ()))
# Список ip адресов, котрые не проверять (коллективные подключения с паролем)
list_ip_ignore = ['172.21.17.1', '172.21.148.1', '172.20.192.17']
detect_ip += list_ip_ignore
# Список проверяемых адресов за вычетом проверенных и игнорируемых
check_list = [x for x in ip_all if x not in detect_ip]
logger.info(f'Для проверки {len(check_list)} терминалов')
# Время начала проверки
logger.info('start')
# Массив с потоками
threads = []
# Создаем потоки
for i in split_list(check_list, 32):
threads.append(Thread(target=check_term, args=(i,)))
# запускаем потоки
for i in threads:
i.start()
# Блокируем потоки
for i in threads:
i.join()
# Время окончания проверки
logger.info('stop')
logger.info(f'Собрана информация с {len(soft_term)} из {len(check_list)} терминалов')
# Добавляем найденную информацию в базу данных
for i in soft_term:
try:
sql = 'insert into term_info (ip, soft, ver, sn) values (?,?,?,?);'
cursor.execute(sql, i)
except sqlite3.IntegrityError:
print('insert into term_info (ip, soft, ver, sn) values (\'{}\',\'{}\',\'{}\',\'{}\');'.format(*i))
conn.commit()
if len(with_passdw) > 0:
logger.info('Запароленные терминалы: {}'.format(', '.join(with_passdw)))