You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.4 KiB
104 lines
3.4 KiB
import subprocess
|
|
import json
|
|
import os
|
|
import time
|
|
from flask import Flask, render_template, request, Response, jsonify, redirect, url_for, session
|
|
from datetime import timedelta
|
|
from dotenv import load_dotenv
|
|
|
|
# Load biến môi trường từ file .env
|
|
load_dotenv()
|
|
|
|
app = Flask(__name__)
|
|
app.secret_key = os.getenv("SECRET_KEY", "default_secret_key") # Lấy từ .env hoặc đặt giá trị mặc định
|
|
app.permanent_session_lifetime = timedelta(days=1)
|
|
|
|
# Danh sách tài khoản & mật khẩu
|
|
USERS = {
|
|
"admin": "123456",
|
|
"user1": "password1",
|
|
"user2": "password2"
|
|
}
|
|
|
|
# Định nghĩa đường dẫn file JSON chứa danh sách service
|
|
SERVICES_FILE = os.path.join(os.path.dirname(__file__), "data", "services.json")
|
|
|
|
def load_services():
|
|
"""Đọc danh sách services từ file JSON"""
|
|
with open(SERVICES_FILE, "r", encoding="utf-8") as file:
|
|
return json.load(file)
|
|
|
|
@app.route("/")
|
|
def home():
|
|
"""Trang chủ: Hiển thị danh sách service (yêu cầu đăng nhập)"""
|
|
if "user" not in session:
|
|
return redirect(url_for("login"))
|
|
|
|
listService = [s for s in load_services() if s.get("status", "active") == "active"]
|
|
return render_template("index.html", listService=listService)
|
|
|
|
@app.route("/login", methods=["GET", "POST"])
|
|
def login():
|
|
"""Xử lý đăng nhập"""
|
|
if request.method == "POST":
|
|
username = request.form.get("username")
|
|
password = request.form.get("password")
|
|
|
|
if username in USERS and USERS[username] == password:
|
|
session["user"] = username
|
|
session.permanent = True
|
|
return redirect(url_for("home"))
|
|
else:
|
|
return render_template("login.html", error="Invalid username or password")
|
|
|
|
return render_template("login.html")
|
|
|
|
@app.route("/logout")
|
|
def logout():
|
|
"""Đăng xuất"""
|
|
session.pop("user", None)
|
|
return redirect(url_for("login"))
|
|
|
|
def run_shell_command(command_str):
|
|
"""Chạy một lệnh shell và gửi output theo thời gian thực"""
|
|
process = subprocess.Popen(command_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, executable="/bin/bash")
|
|
|
|
for line in iter(process.stdout.readline, ''):
|
|
yield f"data: {line.strip()}\n\n"
|
|
time.sleep(0.1)
|
|
|
|
for line in iter(process.stderr.readline, ''):
|
|
yield f"data: [] {line.strip()}\n\n"
|
|
time.sleep(0.1)
|
|
|
|
process.wait()
|
|
if process.returncode == 0:
|
|
yield f"data: SUCCESS\n\n"
|
|
else:
|
|
yield f"data: ERROR\n\n"
|
|
|
|
def generate_output(command_list):
|
|
"""Chạy command từ JSON, sau đó restart Nginx"""
|
|
command_str = " ".join(command_list)
|
|
yield from run_shell_command(command_str)
|
|
|
|
nginx_project_path = os.getenv("NGINX_PROJECT_PATH", "/projects/nginx")
|
|
nginx_command = f"cd {nginx_project_path} && docker compose down && docker compose up -d"
|
|
yield f"data: === Restarting Nginx ===\n\n"
|
|
yield from run_shell_command(nginx_command)
|
|
|
|
@app.route("/run-command", methods=["GET"])
|
|
def run_command():
|
|
"""API chạy command từ frontend"""
|
|
if "user" not in session:
|
|
return jsonify({"error": "Unauthorized"}), 401
|
|
|
|
command_list = request.args.getlist("command[]")
|
|
|
|
if not command_list:
|
|
return jsonify({"error": "No command provided"}), 400
|
|
|
|
return Response(generate_output(command_list), mimetype="text/event-stream")
|
|
|
|
if __name__ == "__main__":
|
|
app.run(host="0.0.0.0", port=5000, debug=True)
|
|
|