CoolFace
Apppublic

kpinquan/serv00_process

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
vps_monitor.py446 linesDownload Raw Back to root
1import paramiko2import schedule3import time4import os5import sys6from flask import Flask, jsonify, render_template_string, request, redirect, session7from threading import Thread8import logging9from functools import wraps10 11app = Flask(__name__)12app.secret_key = 'your_secret_key'  # 请替换为一个随机的安全密钥13 14vps_status = {}15start_time = time.time()16 17logging.basicConfig(18    level=logging.INFO,19    format='%(asctime)s - %(levelname)s - %(message)s',20    handlers=[21        logging.StreamHandler(sys.stdout),22        logging.StreamHandler(sys.stderr)23    ]24)25logger = logging.getLogger()26 27# 设置访问密码28ADMIN_PASSWORD = os.environ.get('ADMIN_PASSWORD', 'your_default_password') 29 30def get_vps_configs():31    configs = []32    index = 133    while True:34        hostname = os.environ.get(f'HOSTNAME_{index}')35        if not hostname:36            break37        38        username = os.environ.get(f'USERNAME_{index}')39        password = os.environ.get(f'PASSWORD_{index}')40        41        script_paths = []42        script_index = 143        while True:44            script_path = os.environ.get(f'SCRIPT_PATHS_{index}_{script_index}')45            if not script_path:46                break47            port = os.environ.get(f'PORTS_{index}_{script_index}')48            script_paths.append((script_path.strip(), port))49            script_index += 150        51        for script_path, port in script_paths:52            configs.append({53                'index': index,54                'hostname': hostname,55                'username': username,56                'password': password,57                'script_path': script_path,58                'port': port59            })60        61        index += 162    return configs63 64def check_and_run_script(config):65    logger.info(f"Checking VPS {config['index']}: {config['hostname']} - {config['script_path']}")66    client = None67    try:68        client = paramiko.SSHClient()69        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())70        client.connect(hostname=config['hostname'], username=config['username'], password=config['password'], port=22)71        72        port = config.get('port')73        script_path = config['script_path']74        script_name = os.path.basename(script_path)75        key = f"{config['index']}:{config['hostname']}:{script_name}"76        77        if port:78            check_command = f"sockstat -4 -l | grep ':{port}'"79            stdin, stdout, stderr = client.exec_command(check_command)80            output = stdout.read().decode('utf-8').strip()81            82            if output:83                # 解析输出获取 'user', 'command', 'pid'84                lines = output.strip().split('\n')85                line = lines[0]86                parts = line.split()87                if len(parts) >= 3:88                    user = parts[0]89                    command = parts[1]90                    pid = parts[2]91                else:92                    user = command = pid = 'N/A'93                94                status = "Running"95                vps_status[key] = {96                    'index': config['index'],97                    'status': status,98                    'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),99                    'username': config['username'],100                    'script_name': script_name,101                    'user': user,102                    'command': command,103                    'pid': pid104                }105                logger.info(f"Port {port} is in use on VPS {config['index']} ({config['hostname']}), process is running.")106                # 服务正在运行,无需执行后续脚本检查107                return108            else:109                # 端口未被占用,继续检查脚本进程或启动脚本110                logger.info(f"Port {port} is not in use on VPS {config['index']} ({config['hostname']}), proceeding to check script process.")111        112        # 现在继续检查脚本是否正在运行113        check_command = f"ps aux | grep '{script_path}' | grep -v grep"114        stdin, stdout, stderr = client.exec_command(check_command)115        output = stdout.read().decode('utf-8').strip()116        117        if output and script_path in output:118            status = "Running"119            # 解析输出获取 PID 等信息120            lines = output.strip().split('\n')121            line = lines[0]122            parts = line.split()123            if len(parts) >= 2:124                user = parts[0]125                pid = parts[1]126            else:127                user = pid = 'N/A'128            command = script_name129            vps_status[key] = {130                'index': config['index'],131                'status': status,132                'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),133                'username': config['username'],134                'script_name': script_name,135                'user': user,136                'command': command,137                'pid': pid138            }139        else:140            logger.info(f"Script {script_name} not running. Attempting to restart.")141            stdin, stdout, stderr = client.exec_command(f"nohup /bin/sh {script_path} > /dev/null 2>&1 & echo $!")142            new_pid = stdout.read().decode('utf-8').strip()143            144            if new_pid.isdigit():145                status = "Restarted"146                pid = new_pid147                user = config['username']148                command = script_name149            else:150                status = "Restart Failed"151                pid = user = command = 'N/A'152            153            vps_status[key] = {154                'index': config['index'],155                'status': status,156                'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),157                'username': config['username'],158                'script_name': script_name,159                'user': user,160                'command': command,161                'pid': pid162            }163            164    except Exception as e:165        logger.error(f"Error occurred while checking VPS {config['index']} - {config['hostname']} - {script_name}: {str(e)}")166        vps_status[f"{config['index']}:{config['hostname']}:{script_name}"] = {167            'index': config['index'],168            'status': f"Error: {str(e)}",169            'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),170            'username': config['username'],171            'script_name': script_name,172            'user': 'N/A',173            'command': 'N/A',174            'pid': 'N/A'175        }176    finally:177        if client:178            client.close()179 180def check_all_vps():181    logger.info("Starting VPS check")182    for config in get_vps_configs():183        check_and_run_script(config)184    185    table = "+---------+-----------------------+------------------+----------+-------------------------+----------+----------+----------+----------+\n"186    table += "| Index   | Hostname              | Script Name      | Status   | Last Check              | Username | User     | Command  | PID      |\n"187    table += "+---------+-----------------------+------------------+----------+-------------------------+----------+----------+----------+----------+\n"188    189    for key, status in vps_status.items():190        index, hostname, script_name = key.split(':')191        table += "| {:<7} | {:<21} | {:<16} | {:<8} | {:<23} | {:<8} | {:<8} | {:<8} | {:<8} |\n".format(192            status['index'], hostname[:21], script_name[:16], status['status'][:8],193            status['last_check'], status['username'][:8],194            status.get('user', 'N/A')[:8], status.get('command', 'N/A')[:8], status.get('pid', 'N/A')[:8]195        )196        table += "+---------+-----------------------+------------------+----------+-------------------------+----------+----------+----------+----------+\n"197    198    logger.info("\n" + table)199 200# 登录功能201def login_required(f):202    @wraps(f)203    def decorated_function(*args, **kwargs):204        if not session.get('logged_in'):205            return redirect('/login')206        return f(*args, **kwargs)207    return decorated_function208 209@app.route('/login', methods=['GET', 'POST'])210def login():211    if request.method == 'POST':212        password = request.form.get('password', '')213        if password == ADMIN_PASSWORD:214            session['logged_in'] = True215            return redirect('/')216        else:217            return render_template_string('''218                <!DOCTYPE html>219                <html lang="zh-CN">220                <head>221                    <meta charset="UTF-8">222                    <title>登录</title>223                    <style>224                        body {225                            display: flex;226                            justify-content: center;227                            align-items: center;228                            height: 100vh;229                            margin: 0;230                            background-color: #f2f2f2;231                        }232                        .login-container {233                            text-align: center;234                            background-color: #ffffff;235                            padding: 30px;236                            border-radius: 8px;237                            box-shadow: 0px 0px 10px 0px #aaaaaa;238                        }239                        p.error {240                            color: red;241                        }242                    </style>243                </head>244                <body>245                    <div class="login-container">246                        <h2>密码错误</h2>247                        <a href="/login">返回</a>248                    </div>249                </body>250                </html>251            ''')252    return render_template_string('''253        <!DOCTYPE html>254        <html lang="zh-CN">255        <head>256            <meta charset="UTF-8">257            <title>登录</title>258            <style>259                body {260                    display: flex;261                    justify-content: center;262                    align-items: center;263                    height: 100vh;264                    margin: 0;265                    background-color: #f2f2f2;266                }267                .login-container {268                    text-align: center;269                    background-color: #ffffff;270                    padding: 30px;271                    border-radius: 8px;272                    box-shadow: 0px 0px 10px 0px #aaaaaa;273                }274                input[type=password], input[type=submit] {275                    padding: 10px;276                    margin: 10px;277                    font-size: 16px;278                    width: 100%;279                }280                input[type=submit] {281                    width: 50%;282                }283            </style>284        </head>285        <body>286            <div class="login-container">287                <h2>请输入密码</h2>288                <form method="post">289                    <p><input type="password" name="password" placeholder="密码"></p>290                    <p><input type="submit" value="登录"></p>291                </form>292            </div>293        </body>294        </html>295    ''')296 297@app.route('/')298@login_required299def index():300    html = '''301    <!DOCTYPE html>302    <html lang="zh-CN">303    <head>304        <meta charset="UTF-8">305        <title>Serv00 状态概览</title>306        <style>307            body {308                font-family: Arial, sans-serif;309            }310            .container {311                width: 90%;312                margin: 0 auto;313            }314            h1 {315                text-align: center;316            }317            #executeButton {318                display: block;319                margin: 20px auto;320                padding: 10px 20px;321                font-size: 16px;322            }323            #result {324                text-align: center;325                color: green;326                font-weight: bold;327            }328            table {329                width: 100%;330                border-collapse: collapse;331                margin-top: 20px;332            }333            table, th, td {334                border: 1px solid #dddddd;335            }336            th, td {337                padding: 8px;338                text-align: center;339            }340            th {341                background-color: #f2f2f2;342            }343            tr:nth-child(even){344                background-color: #f9f9f9;345            }346        </style>347    </head>348    <body>349    <div class="container">350        <h1>Serv00 状态概览</h1>351        <button id="executeButton" onclick="executeTasks()">立即执行所有任务</button>352        <p id="result"></p>353        <table>354            <tr>355                <th>Index</th>356                <th>Hostname</th>357                <th>Script Name</th>358                <th>Status</th>359                <th>Last Check</th>360                <th>Username</th>361                <th>User</th>362                <th>Command</th>363                <th>PID</th>364            </tr>365            {% for key, data in vps_status.items() %}366            <tr>367                <td>{{ data.index }}</td>368                <td><a href="/status/{{ key }}">{{ key.split(':')[1] }}</a></td>369                <td>{{ data.script_name }}</td>370                <td>{{ data.status }}</td>371                <td>{{ data.last_check }}</td>372                <td>{{ data.username }}</td>373                <td>{{ data.user }}</td>374                <td>{{ data.command }}</td>375                <td>{{ data.pid }}</td>376            </tr>377            {% endfor %}378        </table>379    </div>380    <script>381    function executeTasks() {382        fetch('/execute', {383            method: 'POST',384            credentials: 'include'385        })386        .then(response => response.json())387        .then(data => {388            document.getElementById('result').innerText = data.status;389            setTimeout(function(){ location.reload(); }, 5000); // 5秒后刷新页面390        })391        .catch(error => {392            console.error('Error:', error);393            document.getElementById('result').innerText = '执行任务时出错。';394        });395    }396    </script>397    </body>398    </html>399    '''400    return render_template_string(html, vps_status=vps_status)401 402@app.route('/execute', methods=['POST'])403@login_required404def execute_tasks():405    # 异步执行任务,避免阻塞请求406    Thread(target=check_all_vps).start()407    return jsonify({"status": "所有任务正在执行,页面将在5秒后刷新。"})408 409@app.route('/status/<path:key>')410@login_required411def vps_status_detail(key):412    return jsonify(vps_status[key]) if key in vps_status else (jsonify({"error": "VPS or script not found"}), 404)413 414@app.route('/health')415def health_check():416    return jsonify({"status": "healthy", "uptime": time.time() - start_time}), 200417 418def run_flask():419    app.run(host='0.0.0.0', port=7860)420 421def main():422    global start_time423    start_time = time.time()424    425    logger.info("===== VPS monitoring script is starting =====")426    427    Thread(target=run_flask).start()428    logger.info("Flask server started in background")429 430    check_all_vps()431    schedule.every(4).hours.do(check_all_vps)432    logger.info("Scheduled VPS check every 4 hours")433    434    logger.info("===== VPS monitoring script is running =====")435    436    heartbeat_count = 0437    while True:438        schedule.run_pending()439        time.sleep(60)440        heartbeat_count += 1441        if heartbeat_count % 60 == 0:442            uptime_hours = heartbeat_count // 60443            logger.info(f"Heartbeat: Script is still running. Uptime: {uptime_hours} hours")444 445if __name__ == "__main__":446    main()