266 lines
10 KiB
Python
266 lines
10 KiB
Python
from vms import connect_to_vcenter, get_vm_info_and_save_to_db, update_vm_power_status
|
||
from flask import Flask, render_template, flash, send_from_directory, redirect, url_for
|
||
from db_manager import db, User, VirtualMachine, Stables
|
||
from flask_login import LoginManager, login_required, current_user
|
||
from routers.user_routers import user_blueprint
|
||
from routers.vm_routers import vm_blueprint
|
||
from flask_principal import Principal
|
||
from flask_socketio import SocketIO
|
||
from flask_migrate import Migrate
|
||
from flask_session import Session
|
||
from flask.cli import AppGroup
|
||
from dotenv import load_dotenv
|
||
from docx import Document
|
||
from io import BytesIO
|
||
import threading
|
||
import schedule
|
||
import requests
|
||
import logging
|
||
import redis
|
||
import time
|
||
import os
|
||
import re
|
||
|
||
# Создаем директорию для логов, если ее нет
|
||
log_dir = 'logs'
|
||
if not os.path.exists(log_dir):
|
||
os.makedirs(log_dir)
|
||
|
||
# Настройки логирования
|
||
log_format = '%(name)s - %(levelname)s - %(message)s'
|
||
log_path = os.path.join(log_dir, 'app.log')
|
||
logging.basicConfig(filename=log_path, level=logging.INFO, format=log_format, filemode='w')
|
||
|
||
dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
|
||
|
||
if os.path.exists(dotenv_path):
|
||
load_dotenv(dotenv_path)
|
||
else:
|
||
exit('[STOP SYSTEM STARTUP] >> Не обнаружен файл переменных окружения ".env". \n'
|
||
'Файл должен располагаться на одном уровне с "app.py".')
|
||
|
||
app = Flask(__name__)
|
||
socketio = SocketIO(app)
|
||
login_manager = LoginManager()
|
||
|
||
app.register_blueprint(user_blueprint)
|
||
app.register_blueprint(vm_blueprint)
|
||
|
||
login_manager.init_app(app)
|
||
|
||
principal = Principal(app)
|
||
|
||
migrate = Migrate(app, db)
|
||
|
||
app.secret_key = os.environ.get('SECRET')
|
||
|
||
# Блок создания кастомных комманд
|
||
|
||
group_command_one = AppGroup('backtask')
|
||
|
||
|
||
@group_command_one.command('full')
|
||
def command():
|
||
logging.info('Запустить в ручном режиме выполнение выполнения - full_upd')
|
||
full_upd()
|
||
|
||
|
||
@group_command_one.command('power')
|
||
def command():
|
||
logging.info('Запустить в ручном режиме выполнение выполнения - power_status_upd')
|
||
power_status_upd()
|
||
|
||
|
||
@group_command_one.command('version')
|
||
def command():
|
||
logging.info('Запустить в ручном режиме выполнение запуска - стабильный_upd')
|
||
stables_upd()
|
||
|
||
|
||
app.cli.add_command(group_command_one)
|
||
|
||
# End block
|
||
|
||
|
||
if (os.environ.get('DB_TYPE')).lower() == "sqlite":
|
||
app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{os.environ.get('DB_NAME')}.db"
|
||
elif (os.environ.get('DB_TYPE')).lower() == "postgresql":
|
||
app.config['SQLALCHEMY_DATABASE_URI'] = (f"postgresql://{os.environ.get('DB_USER')}:{os.environ.get('DB_PASS')}@"
|
||
f"{os.environ.get('DB_HOST')}:{os.environ.get('DB_PORT')}/"
|
||
f"{os.environ.get('DB_NAME')}")
|
||
elif (os.environ.get('DB_TYPE')).lower() == "mysql":
|
||
app.config['SQLALCHEMY_DATABASE_URI'] = (f"mysql+mysqlconnector://{os.environ.get('DB_USER')}:"
|
||
f"{os.environ.get('DB_PASS')}@{os.environ.get('DB_HOST')}:"
|
||
f"{os.environ.get('DB_PORT')}/{os.environ.get('DB_NAME')}")
|
||
else:
|
||
exit('[DB ERROR] >> Неверно указаны настройки базы данных (параметр - DB_TYPE)!')
|
||
|
||
db.init_app(app)
|
||
|
||
if (os.environ.get('SESSION_TYPE')).lower() == 'redis':
|
||
app.config['SESSION_TYPE'] = 'redis'
|
||
app.config['SESSION_PERMANENT'] = True
|
||
app.config['SESSION_USE_SIGNER'] = True
|
||
app.config['SESSION_KEY_PREFIX'] = os.environ.get('SESSION_KEY_PREFIX')
|
||
app.config['SESSION_REDIS'] = redis.StrictRedis(
|
||
host=os.environ.get('REDIS_HOST'),
|
||
port=os.environ.get('REDIS_PORT'),
|
||
db=os.environ.get('REDIS_DB'),
|
||
password=os.environ.get('REDIS_PASS')
|
||
)
|
||
app.config['PERMANENT_SESSION_LIFETIME'] = int(os.environ.get('SESSION_LIFETIME'))
|
||
elif (os.environ.get('SESSION_TYPE')).lower() == 'file':
|
||
app.config['SESSION_TYPE'] = 'filesystem'
|
||
else:
|
||
exit('[SESSION ERROR] >> Неверно указаны настройки сессии(параметр - SESSION_TYPE)!')
|
||
|
||
Session(app)
|
||
|
||
|
||
@app.route('/')
|
||
def index():
|
||
total_vm = VirtualMachine.query.count()
|
||
number_of_employees = VirtualMachine.query.filter_by(status="Занято").count()
|
||
number_of_technical = VirtualMachine.query.filter_by(technical=True).count()
|
||
quantity_for_tests = int(total_vm) - (int(number_of_technical) + int(number_of_employees))
|
||
stables_version = Stables.query.all()
|
||
return render_template('home.html', total_vm=total_vm,
|
||
number_of_employees=number_of_employees,
|
||
number_of_technical=number_of_technical,
|
||
quantity_for_tests=quantity_for_tests,
|
||
stables_version=stables_version)
|
||
|
||
|
||
@app.route('/favicon.ico')
|
||
def fav():
|
||
return send_from_directory(os.path.join(app.root_path, 'static'), 'image/fav.ico')
|
||
|
||
|
||
@app.route('/about')
|
||
def about():
|
||
return render_template('about.html')
|
||
|
||
|
||
@app.route('/admin')
|
||
@login_required
|
||
def admin():
|
||
if current_user.is_admin:
|
||
all_user = User.query.all()
|
||
return render_template('admin.html', all_user=all_user)
|
||
else:
|
||
flash(f'Пользователь {current_user} не администратор!', 'danger')
|
||
return redirect(url_for('index'))
|
||
|
||
|
||
@login_manager.user_loader
|
||
def load_user(user_id):
|
||
return db.session.get(User, user_id)
|
||
|
||
|
||
@login_manager.unauthorized_handler
|
||
def unauthorized():
|
||
flash('Доступ разрешен только авторизованным!', 'danger')
|
||
return render_template('login.html')
|
||
|
||
|
||
vcenter_connections = [
|
||
{"host": f"{os.environ.get('HYPER1_HOST')}", "user": f"{os.environ.get('HYPER1_USER')}",
|
||
"password": f"{os.environ.get('HYPER1_PASS')}"},
|
||
{"host": f"{os.environ.get('HYPER2_HOST')}", "user": f"{os.environ.get('HYPER2_USER')}",
|
||
"password": f"{os.environ.get('HYPER2_PASS')}"},
|
||
{"host": f"{os.environ.get('HYPER3_HOST')}", "user": f"{os.environ.get('HYPER3_USER')}",
|
||
"password": f"{os.environ.get('HYPER3_PASS')}"},
|
||
{"host": f"{os.environ.get('HYPER4_HOST')}", "user": f"{os.environ.get('HYPER4_USER')}",
|
||
"password": f"{os.environ.get('HYPER4_PASS')}"}
|
||
]
|
||
|
||
|
||
def stables_upd():
|
||
with app.app_context():
|
||
url = "https://s3.printum.io/stablerefs/Printum%20software.docx"
|
||
response = requests.get(url)
|
||
docx_file = BytesIO(response.content)
|
||
doc = Document(docx_file)
|
||
pattern = re.compile(r'(\d+\.\d+\.\d+)')
|
||
target_values = []
|
||
for paragraph in doc.paragraphs:
|
||
matches = pattern.findall(paragraph.text)
|
||
if matches:
|
||
target_values.extend(matches)
|
||
|
||
monitoring_value = target_values[0]
|
||
printmanager_value = target_values[2]
|
||
|
||
existing_stables = Stables.query.first()
|
||
|
||
if existing_stables:
|
||
existing_stables.monitoring = monitoring_value
|
||
existing_stables.printmanager = printmanager_value
|
||
db.session.commit()
|
||
else:
|
||
new_version = Stables(monitoring=monitoring_value, printmanager=printmanager_value)
|
||
db.session.add(new_version)
|
||
db.session.commit()
|
||
logging.info('Фоновая задача «stables_upd» выполнена успешно.')
|
||
|
||
|
||
def power_status_upd():
|
||
with app.app_context():
|
||
for connection in vcenter_connections:
|
||
content = connect_to_vcenter(connection['host'], connection['user'], connection['password'])
|
||
if content:
|
||
update_vm_power_status(content, connection['host'])
|
||
logging.info('Фоновая задача «power_status_upd» выполнена успешно.')
|
||
|
||
|
||
def full_upd():
|
||
with app.app_context():
|
||
for connection in vcenter_connections:
|
||
content = connect_to_vcenter(connection['host'], connection['user'], connection['password'])
|
||
if content:
|
||
get_vm_info_and_save_to_db(content, connection['host'])
|
||
logging.info('Фоновая задача «full_upd» выполнена успешно.')
|
||
|
||
|
||
# Настройки обработки фоновых задач
|
||
if (os.environ.get('DISABLING_TASK')).lower() == 'false':
|
||
lock = threading.Lock()
|
||
|
||
|
||
def run_tasks():
|
||
while True:
|
||
lock.acquire()
|
||
schedule.run_pending()
|
||
lock.release()
|
||
time.sleep(1)
|
||
|
||
|
||
schedule.every(int(os.environ.get('STABLES_UPDATE'))).minutes.do(stables_upd)
|
||
schedule.every(int(os.environ.get('POWER_STATUS_UPDATE'))).minutes.do(power_status_upd)
|
||
if (os.environ.get('PERFORMANCE')).lower() == 'period':
|
||
schedule.every(int(os.environ.get('FULL_UPDATE'))).minutes.do(full_upd)
|
||
elif (os.environ.get('PERFORMANCE')).lower() == 'time':
|
||
schedule.every().day.at(f"{os.environ.get('HOUR_FULL_UPDATE')}").do(full_upd)
|
||
else:
|
||
logging.error("Неверно указано время или период выполнения полного обновления!")
|
||
exit(1)
|
||
|
||
thread = threading.Thread(target=run_tasks)
|
||
thread.start()
|
||
else:
|
||
logging.error("Выполнение фоновых задач отключено!!")
|
||
|
||
# Первичная инициализация БД при первом запуске
|
||
if not os.path.exists(".init") and os.path.exists(".create"):
|
||
print("Первоначальная инициализация и загрузка данных в базу данных осуществляется...")
|
||
try:
|
||
full_upd()
|
||
stables_upd()
|
||
with open(".init", "w") as f:
|
||
f.write("Первая инициализация БД прошла успешно")
|
||
except Exception as e:
|
||
logging.error(f"ОШИБКА при первой инициализации: {e}")
|
||
|
||
if __name__ == '__main__':
|
||
socketio.run(app, debug=True, allow_unsafe_werkzeug=True)
|