duzo fixow i optymalizacji

This commit is contained in:
Mateusz Gruszczyński
2025-03-10 23:32:43 +01:00
parent c4b5e703f3
commit a8954020f6
4 changed files with 274 additions and 106 deletions

142
app.py
View File

@@ -1,4 +1,4 @@
from flask import Flask, render_template, request, redirect, url_for, flash, session, Response
from flask import Flask, render_template, request, redirect, url_for, flash, session, Response, jsonify
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
import os, paramiko, threading, time, io, tempfile, csv
@@ -159,7 +159,11 @@ def ensure_local_defaults(content, user_id):
return final_content
def format_host(host):
if not host:
return "Unknown Host"
resolved_name = None
# Priorytet dla Linux Daemon
if host.use_daemon and host.type == 'linux' and host.daemon_url:
resolved_name = host.resolved_daemon or host.hostname
@@ -175,12 +179,8 @@ def format_host(host):
except (socket.herror, socket.gaierror):
pass # Jeśli nie można rozwiązać, pozostaw IP
return f"{resolved_name} ({host.raw_ip})"
return f"{resolved_name} ({host.raw_ip})" if resolved_name else f"Unknown ({host.raw_ip})"
# Automatyczne dodanie wartości systemowych
variables["hostname"] = socket.gethostname() # Nazwa hosta
variables["resolved_hostname"] = socket.getfqdn() # Pełna nazwa hosta
return variables
def wrap_content_with_comments(content):
@@ -679,48 +679,54 @@ def clear_server():
def clear_single_server(host_id):
if 'user_id' not in session:
return redirect(url_for('login'))
host = db.session.get(Host, host_id)
if not host or host.user_id != session['user_id']:
flash('Host not found or unauthorized', 'danger')
return redirect(url_for('clear_servers'))
return redirect(url_for('clear_server'))
default_content = ensure_local_defaults("", session['user_id'])
default_content = ensure_local_defaults("")
try:
host_name = format_host(host)
if host.use_daemon and host.type == 'linux':
import requests
url = host.daemon_url.rstrip('/') + '/hosts'
headers = {"Authorization": host.daemon_token}
# Zakładamy, że demon potrafi zastąpić /etc/hosts treścią "default_content"
resp = requests.post(url, json={"hosts": default_content},
headers=headers, verify=False, timeout=10)
resp = requests.post(url, json={"hosts": default_content}, headers=headers, verify=False, timeout=10)
if resp.status_code != 200:
raise Exception(f"Daemon update error: {resp.status_code} - {resp.text}")
elif host.type == 'mikrotik':
clear_mikrotik(host)
else:
# standard linux
clear_linux(host, default_content)
flash(f'Cleared host: {host.hostname}', 'success')
flash(f'Cleared host: {host_name}', 'success')
except Exception as e:
flash(f'Error clearing host {host.hostname}: {str(e)}', 'danger')
flash(f'Error clearing host {host_name}: {str(e)}', 'danger')
return redirect(url_for('clear_server'))
return redirect(url_for('clear_all_server'))
@app.route('/clear-all-server', methods=['GET', 'POST'])
def clear_all_server():
if 'user_id' not in session:
return redirect(url_for('login'))
hosts = Host.query.filter_by(user_id=session['user_id']).all()
if request.method == 'POST':
linux_clear = request.form.get('linux')
mikrotik_clear = request.form.get('mikrotik')
default_content = ensure_local_defaults("")
default_content = ensure_local_defaults("", session['user_id'])
for h in hosts:
try:
host_name = format_host(h) if h else "Unknown Host"
print(f"DEBUG: Czyszczenie hosta {host_name}")
if h.type == 'linux' and linux_clear:
if h.use_daemon:
import requests
@@ -732,18 +738,18 @@ def clear_all_server():
raise Exception(f"Daemon update error: {resp.status_code} - {resp.text}")
else:
clear_linux(h, default_content)
flash(f'Cleared Linux host: {h.hostname}', 'success')
flash(f'Cleared Linux host: {host_name}', 'success')
elif h.type == 'mikrotik' and mikrotik_clear:
clear_mikrotik(h)
flash(f'Cleared Mikrotik host: {h.hostname}', 'success')
flash(f'Cleared Mikrotik host: {host_name}', 'success')
except Exception as e:
flash(f'Error clearing host {h.hostname}: {str(e)}', 'danger')
flash(f'Error clearing host {host_name}: {str(e)}', 'danger')
return redirect(url_for('clear_all_server'))
return render_template('clear_servers.html', hosts=hosts)
return render_template('clear_servers.html', hosts=hosts, format_host=format_host)
# -------------------
# ZARZĄDZANIE PLIKAMI HOSTS (WIELOKROTNE PLIKI)
@@ -1246,35 +1252,24 @@ def deploy_user(user_id):
if not h.auto_deploy_enabled:
continue
# Pobranie pliku hosts wybranego dla serwera
if h.preferred_hostfile_id:
chosen_file = HostFile.query.filter_by(id=h.preferred_hostfile_id, user_id=user_id).first()
if not chosen_file:
chosen_file = default_file
else:
chosen_file = default_file
# Wstępna zawartość - pobrany plik hosts
chosen_file = HostFile.query.filter_by(id=h.preferred_hostfile_id, user_id=user_id).first() if h.preferred_hostfile_id else default_file
final_content = chosen_file.content.strip()
# Jeśli disable_local_default jest włączone → usuwamy local-defaults, ale reszta pozostaje
if h.disable_local_default:
final_content = remove_local_defaults(final_content, user_id)
else:
# Dodaj regex, jeśli nie jest wyłączony
if not h.disable_regex_deploy and regex_lines.strip():
final_content = regex_lines + "\n" + final_content
final_content = ensure_local_defaults(final_content, user_id)
try:
# 🖥 Wgrywanie na Mikrotik
host_name = format_host(h) if h else "Unknown Host"
if h.type == 'mikrotik':
wrapped_content = wrap_mikrotik_content(final_content)
deploy_mikrotik(h, wrapped_content)
log_details = f'[MIKROTIK] Updated {format_host(h)} for user {user_id}'
log_details = f'[MIKROTIK] Updated {host_name} for user {user_id}'
# 🖥 Wgrywanie na Linux Daemon
elif h.use_daemon and h.type == 'linux':
import requests
wrapped_content = wrap_content_with_comments(final_content)
@@ -1283,9 +1278,8 @@ def deploy_user(user_id):
resp = requests.post(url, json={"hosts": wrapped_content}, headers=headers, timeout=10, verify=False)
if resp.status_code != 200:
raise Exception(f"Daemon POST error: {resp.status_code} - {resp.text}")
log_details = f'[LINUX/DAEMON] Updated {format_host(h)} for user {user_id}'
log_details = f'[LINUX/DAEMON] Updated {host_name} for user {user_id}'
# 🖥 Wgrywanie na standardowy Linux przez SSH
else:
ssh = open_ssh_connection(h)
wrapped_content = wrap_content_with_comments(final_content)
@@ -1297,14 +1291,13 @@ def deploy_user(user_id):
sftp.close()
ssh.close()
os.remove(tmp_file_path)
log_details = f'[LINUX] Updated {format_host(h)} for user {user_id}'
log_details = f'[LINUX] Updated {host_name} for user {user_id}'
# Logowanie wdrożenia
db.session.add(DeployLog(details=log_details, user_id=user_id))
db.session.commit()
except Exception as e:
error_log = f'Failed to update {format_host(h)}: {str(e)} for user {user_id}'
error_log = f'Failed to update {host_name}: {str(e)} for user {user_id}'
db.session.add(DeployLog(details=error_log, user_id=user_id))
db.session.commit()
@@ -1751,7 +1744,9 @@ def local_defaults():
ip_address = request.form.get('ip_address', '').strip()
if hostname and ip_address:
new_entry = LocalDefaultEntry(user_id=user_id, hostname=hostname, ip_address=ip_address or None, entry=entry_content)
entry_content = f"{ip_address} {hostname}"
new_entry = LocalDefaultEntry(user_id=user_id, hostname=hostname, ip_address=ip_address, entry=entry_content)
db.session.add(new_entry)
db.session.commit()
flash('Dodano nowy wpis.', 'success')
@@ -1764,19 +1759,66 @@ def local_defaults():
return render_template('local_defaults.html', entries=entries)
@app.route('/local-defaults/delete/<int:entry_id>', methods=['POST'])
def delete_local_default(entry_id):
@app.route('/local-defaults/delete', methods=['POST'])
def delete_local_default(entry_id=None):
if 'user_id' not in session:
return redirect(url_for('login'))
return jsonify({'status': 'error', 'message': 'Unauthorized'}), 403
entry = LocalDefaultEntry.query.get(entry_id)
if not entry or entry.user_id != session['user_id']:
flash('Wpis nie istnieje lub brak uprawnień.', 'danger')
if request.is_json:
data = request.get_json()
entry_ids = data.get('entry_ids', [])
if not entry_ids:
return jsonify({'status': 'error', 'message': 'Brak wpisów do usunięcia'}), 400
entries_to_delete = LocalDefaultEntry.query.filter(
LocalDefaultEntry.id.in_(entry_ids),
LocalDefaultEntry.user_id == session['user_id']
).all()
if not entries_to_delete:
return jsonify({'status': 'error', 'message': 'Nie znaleziono wpisów do usunięcia'}), 404
for entry in entries_to_delete:
db.session.delete(entry)
db.session.commit()
return jsonify({'status': 'success', 'message': 'Wpisy usunięte pomyślnie'})
else:
# Obsługa usuwania pojedynczego wpisu
entry = LocalDefaultEntry.query.get(entry_id)
if not entry or entry.user_id != session['user_id']:
flash('Wpis nie istnieje lub brak uprawnień.', 'danger')
return redirect(url_for('local_defaults'))
db.session.delete(entry)
db.session.commit()
flash('Wpis został usunięty.', 'info')
return redirect(url_for('local_defaults'))
db.session.delete(entry)
db.session.commit()
flash('Wpis został usunięty.', 'info')
return redirect(url_for('local_defaults'))
@app.route('/local-defaults/update/<int:entry_id>', methods=['POST'])
def update_local_default(entry_id):
if 'user_id' not in session:
return jsonify({'status': 'error', 'message': 'Unauthorized'}), 403
entry = db.session.get(LocalDefaultEntry, entry_id)
if not entry or entry.user_id != session['user_id']:
return jsonify({'status': 'error', 'message': 'Entry not found'}), 404
data = request.get_json()
new_ip = data.get('ip_address', '').strip()
new_hostname = data.get('hostname', '').strip()
if new_ip and new_hostname:
entry.ip_address = new_ip
entry.hostname = new_hostname
entry.entry = f"{new_ip} {new_hostname}"
db.session.commit()
return jsonify({'status': 'success', 'message': 'Updated successfully', 'ip_address': new_ip, 'hostname': new_hostname})
else:
return jsonify({'status': 'error', 'message': 'IP and hostname are required'}), 400
scheduler = BackgroundScheduler(timezone=get_localzone())
scheduler.add_job(func=scheduled_deployments, trigger="interval", minutes=1, next_run_time=datetime.now())