proxmox-rdp-autosetup/rdp_control_web.py
root 9d0adf6f8b feat: RDP 자동 로그인 웹 제어 패널 추가
- Flask 기반 웹 제어 패널 구현
- 토글 스위치로 RDP 자동 로그인 제어
- Tailscale IP 기반 접속 정보 표시
- Python venv 환경 사용
- systemd 서비스로 자동 실행
- PBS 자동 등록 스크립트 기획서 추가

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-06 00:33:02 +09:00

228 lines
7.1 KiB
Python

#!/usr/bin/env python3
import os
import subprocess
import json
from flask import Flask, render_template, jsonify, request
from flask_cors import CORS
import logging
from pathlib import Path
app = Flask(__name__)
CORS(app)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
CONFIG_FILE = "/etc/xrdp/auto_login.conf"
SYSTEMD_SERVICE = "xrdp-autologin.service"
def get_auto_login_status():
"""자동 로그인 상태 확인"""
try:
# systemd 서비스 상태 확인
result = subprocess.run(
["systemctl", "is-active", SYSTEMD_SERVICE],
capture_output=True,
text=True
)
service_active = result.stdout.strip() == "active"
# 설정 파일 존재 여부 확인
config_exists = os.path.exists(CONFIG_FILE)
# systemd 서비스 enabled 상태 확인
result = subprocess.run(
["systemctl", "is-enabled", SYSTEMD_SERVICE],
capture_output=True,
text=True
)
service_enabled = result.stdout.strip() == "enabled"
return {
"enabled": service_enabled,
"active": service_active,
"config_exists": config_exists
}
except Exception as e:
logger.error(f"상태 확인 실패: {str(e)}")
return {
"enabled": False,
"active": False,
"config_exists": False,
"error": str(e)
}
def set_auto_login(enabled):
"""자동 로그인 활성화/비활성화"""
try:
if enabled:
# 서비스 활성화 및 시작
subprocess.run(["systemctl", "enable", SYSTEMD_SERVICE], check=True)
subprocess.run(["systemctl", "start", SYSTEMD_SERVICE], check=True)
# xrdp 서비스 재시작
subprocess.run(["systemctl", "restart", "xrdp"], check=True)
subprocess.run(["systemctl", "restart", "xrdp-sesman"], check=True)
logger.info("RDP 자동 로그인 활성화됨")
return True, "RDP 자동 로그인이 활성화되었습니다."
else:
# 서비스 중지 및 비활성화
subprocess.run(["systemctl", "stop", SYSTEMD_SERVICE], check=True)
subprocess.run(["systemctl", "disable", SYSTEMD_SERVICE], check=True)
# 자동 로그인 설정 제거
if os.path.exists(CONFIG_FILE):
backup_file = f"{CONFIG_FILE}.backup"
subprocess.run(["mv", CONFIG_FILE, backup_file], check=True)
# xrdp 서비스 재시작
subprocess.run(["systemctl", "restart", "xrdp"], check=True)
subprocess.run(["systemctl", "restart", "xrdp-sesman"], check=True)
logger.info("RDP 자동 로그인 비활성화됨")
return True, "RDP 자동 로그인이 비활성화되었습니다."
except subprocess.CalledProcessError as e:
logger.error(f"명령 실행 실패: {str(e)}")
return False, f"설정 변경 실패: {str(e)}"
except Exception as e:
logger.error(f"예외 발생: {str(e)}")
return False, f"오류 발생: {str(e)}"
def get_system_info():
"""시스템 정보 가져오기"""
try:
# 호스트명
hostname = subprocess.run(
["hostname"],
capture_output=True,
text=True
).stdout.strip()
# IP 주소
ip_result = subprocess.run(
["ip", "-4", "addr", "show", "scope", "global"],
capture_output=True,
text=True
)
ip_addresses = []
for line in ip_result.stdout.split('\n'):
if 'inet' in line:
ip = line.strip().split()[1].split('/')[0]
ip_addresses.append(ip)
# RDP 포트 확인
rdp_port = "3389"
# Tailscale 상태
tailscale_ip = None
try:
ts_result = subprocess.run(
["tailscale", "ip", "-4"],
capture_output=True,
text=True
)
if ts_result.returncode == 0:
tailscale_ip = ts_result.stdout.strip()
except:
pass
return {
"hostname": hostname,
"ip_addresses": ip_addresses,
"rdp_port": rdp_port,
"tailscale_ip": tailscale_ip
}
except Exception as e:
logger.error(f"시스템 정보 가져오기 실패: {str(e)}")
return {}
@app.route('/')
def index():
"""메인 페이지"""
return render_template('index.html')
@app.route('/api/status', methods=['GET'])
def get_status():
"""현재 상태 조회 API"""
status = get_auto_login_status()
system_info = get_system_info()
return jsonify({
"status": status,
"system": system_info
})
@app.route('/api/toggle', methods=['POST'])
def toggle_auto_login():
"""자동 로그인 토글 API"""
data = request.get_json()
enabled = data.get('enabled', False)
success, message = set_auto_login(enabled)
if success:
return jsonify({
"success": True,
"message": message,
"status": get_auto_login_status()
})
else:
return jsonify({
"success": False,
"message": message,
"status": get_auto_login_status()
}), 500
@app.route('/api/logs', methods=['GET'])
def get_logs():
"""최근 로그 조회 API"""
try:
# xrdp 로그
xrdp_logs = subprocess.run(
["journalctl", "-u", "xrdp", "-n", "20", "--no-pager"],
capture_output=True,
text=True
).stdout
# 자동 로그인 서비스 로그
autologin_logs = subprocess.run(
["journalctl", "-u", SYSTEMD_SERVICE, "-n", "20", "--no-pager"],
capture_output=True,
text=True
).stdout
return jsonify({
"xrdp_logs": xrdp_logs,
"autologin_logs": autologin_logs
})
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/restart', methods=['POST'])
def restart_services():
"""서비스 재시작 API"""
try:
subprocess.run(["systemctl", "restart", "xrdp"], check=True)
subprocess.run(["systemctl", "restart", "xrdp-sesman"], check=True)
status = get_auto_login_status()
if status['enabled']:
subprocess.run(["systemctl", "restart", SYSTEMD_SERVICE], check=True)
return jsonify({
"success": True,
"message": "서비스가 재시작되었습니다."
})
except Exception as e:
return jsonify({
"success": False,
"message": f"재시작 실패: {str(e)}"
}), 500
if __name__ == '__main__':
# templates 디렉토리 생성
Path("templates").mkdir(exist_ok=True)
# 개발 서버 실행 (프로덕션에서는 gunicorn 사용 권장)
app.run(host='0.0.0.0', port=5000, debug=False)