250 lines
9.2 KiB
Python
250 lines
9.2 KiB
Python
"""
|
|
Dell iDRAC 멀티 서버 관리 라우트
|
|
backend/routes/idrac_routes.py
|
|
- CSRF 보호 제외 추가
|
|
- 펌웨어 관리 기능 제거됨 (Server Config Analysis로 대체)
|
|
"""
|
|
|
|
from flask import Blueprint, request, jsonify, current_app
|
|
from backend.services.idrac_redfish_client import DellRedfishClient
|
|
from backend.models.idrac_server import IdracServer, db
|
|
from datetime import datetime
|
|
import threading
|
|
|
|
# Blueprint 생성
|
|
idrac_bp = Blueprint('idrac', __name__, url_prefix='/idrac')
|
|
|
|
# ========================================
|
|
# 페이지 라우트
|
|
# ========================================
|
|
|
|
@idrac_bp.route('/')
|
|
def index():
|
|
"""iDRAC 서버 관리 메인 페이지"""
|
|
from flask import render_template
|
|
return render_template('idrac_firmware.html')
|
|
|
|
# ========================================
|
|
# 서버 관리 API (CRUD)
|
|
# ========================================
|
|
|
|
@idrac_bp.route('/api/servers', methods=['GET'])
|
|
def get_servers():
|
|
"""서버 목록 조회"""
|
|
try:
|
|
group_filter = request.args.get('group')
|
|
query = IdracServer.query.filter_by(is_active=True)
|
|
|
|
if group_filter and group_filter != 'all':
|
|
query = query.filter_by(group_name=group_filter)
|
|
|
|
servers = query.order_by(IdracServer.name).all()
|
|
return jsonify({
|
|
'success': True,
|
|
'servers': [s.to_dict() for s in servers]
|
|
})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
@idrac_bp.route('/api/servers', methods=['POST'])
|
|
def add_server():
|
|
"""서버 추가"""
|
|
try:
|
|
data = request.json
|
|
# 필수 필드 체크
|
|
if not all(k in data for k in ['name', 'ip_address', 'password']):
|
|
return jsonify({'success': False, 'message': '필수 필드 누락'})
|
|
|
|
# 활성 서버 중복 체크
|
|
if IdracServer.query.filter_by(ip_address=data['ip_address'], is_active=True).first():
|
|
return jsonify({'success': False, 'message': '이미 등록된 IP입니다.'})
|
|
|
|
# Soft delete된 서버가 있는지 확인하고 재활성화
|
|
existing_server = IdracServer.query.filter_by(ip_address=data['ip_address'], is_active=False).first()
|
|
if existing_server:
|
|
# 기존 서버 재활성화 및 정보 업데이트
|
|
existing_server.is_active = True
|
|
existing_server.name = data['name']
|
|
existing_server.username = data.get('username', 'root')
|
|
existing_server.password = data['password']
|
|
existing_server.group_name = data.get('group_name')
|
|
existing_server.model = data.get('model')
|
|
existing_server.notes = data.get('notes')
|
|
existing_server.status = 'registered'
|
|
existing_server.updated_at = datetime.utcnow()
|
|
db.session.commit()
|
|
return jsonify({'success': True, 'message': '서버 재등록 완료', 'server': existing_server.to_dict()})
|
|
|
|
# 새 서버 생성
|
|
new_server = IdracServer(
|
|
name=data['name'],
|
|
ip_address=data['ip_address'],
|
|
username=data.get('username', 'root'),
|
|
password=data['password'],
|
|
group_name=data.get('group_name'),
|
|
model=data.get('model'),
|
|
notes=data.get('notes')
|
|
)
|
|
db.session.add(new_server)
|
|
db.session.commit()
|
|
return jsonify({'success': True, 'message': '서버 추가 완료', 'server': new_server.to_dict()})
|
|
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
@idrac_bp.route('/api/servers/<int:server_id>', methods=['DELETE'])
|
|
def delete_server(server_id):
|
|
"""서버 삭제 (Soft Delete)"""
|
|
try:
|
|
server = IdracServer.query.get(server_id)
|
|
if not server:
|
|
return jsonify({'success': False, 'message': '서버를 찾을 수 없습니다'})
|
|
|
|
# Soft delete: is_active를 False로 설정
|
|
# IP 주소는 유지하여 재등록 시 재활성화 가능
|
|
server.is_active = False
|
|
server.status = 'deleted'
|
|
db.session.commit()
|
|
return jsonify({'success': True, 'message': '서버 삭제 완료'})
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
@idrac_bp.route('/api/groups', methods=['GET'])
|
|
def get_groups():
|
|
"""등록된 그룹 목록"""
|
|
try:
|
|
groups = db.session.query(IdracServer.group_name).filter(
|
|
IdracServer.group_name != None,
|
|
IdracServer.is_active == True
|
|
).distinct().all()
|
|
return jsonify({
|
|
'success': True,
|
|
'groups': [g[0] for g in groups if g[0]]
|
|
})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
# ========================================
|
|
# 연결 테스트 API
|
|
# ========================================
|
|
|
|
@idrac_bp.route('/api/servers/<int:server_id>/test', methods=['POST'])
|
|
def test_connection(server_id):
|
|
"""단일 서버 연결 테스트"""
|
|
try:
|
|
server = IdracServer.query.get(server_id)
|
|
if not server:
|
|
return jsonify({'success': False, 'message': '서버 없음'})
|
|
|
|
client = DellRedfishClient(server.ip_address, server.username, server.password)
|
|
if client.check_connection():
|
|
server.status = 'online'
|
|
server.last_connected = datetime.utcnow()
|
|
db.session.commit()
|
|
return jsonify({'success': True, 'message': '연결 성공'})
|
|
else:
|
|
server.status = 'offline'
|
|
db.session.commit()
|
|
return jsonify({'success': False, 'message': '연결 실패'})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
@idrac_bp.route('/api/servers/test-multi', methods=['POST'])
|
|
def test_connections_multi():
|
|
"""다중 서버 연결 테스트"""
|
|
try:
|
|
data = request.json
|
|
server_ids = data.get('server_ids', [])
|
|
results = []
|
|
|
|
for sid in server_ids:
|
|
server = IdracServer.query.get(sid)
|
|
if not server: continue
|
|
|
|
try:
|
|
client = DellRedfishClient(server.ip_address, server.username, server.password)
|
|
if client.check_connection():
|
|
server.status = 'online'
|
|
server.last_connected = datetime.utcnow()
|
|
results.append({'server_id': sid, 'success': True})
|
|
else:
|
|
server.status = 'offline'
|
|
results.append({'server_id': sid, 'success': False, 'message': 'Failed'})
|
|
except Exception as e:
|
|
server.status = 'offline'
|
|
results.append({'server_id': sid, 'success': False, 'message': str(e)})
|
|
|
|
db.session.commit()
|
|
success = sum(1 for r in results if r['success'])
|
|
return jsonify({
|
|
'success': True,
|
|
'summary': {'success': success, 'failed': len(results)-success},
|
|
'results': results
|
|
})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
# ========================================
|
|
# 전원 제어 API
|
|
# ========================================
|
|
|
|
@idrac_bp.route('/api/servers/reboot-multi', methods=['POST'])
|
|
def reboot_servers_multi():
|
|
"""다중 서버 재부팅"""
|
|
try:
|
|
data = request.json
|
|
server_ids = data.get('server_ids', [])
|
|
reboot_type = data.get('type', 'GracefulRestart')
|
|
results = []
|
|
|
|
for sid in server_ids:
|
|
server = IdracServer.query.get(sid)
|
|
if not server: continue
|
|
|
|
try:
|
|
client = DellRedfishClient(server.ip_address, server.username, server.password)
|
|
if client.reboot_server(reboot_type):
|
|
results.append({'server_id': sid, 'success': True, 'message': 'Reboot initiated'})
|
|
else:
|
|
results.append({'server_id': sid, 'success': False, 'message': 'Reboot failed'})
|
|
except Exception as e:
|
|
results.append({'server_id': sid, 'success': False, 'message': str(e)})
|
|
|
|
success = sum(1 for r in results if r['success'])
|
|
return jsonify({
|
|
'success': True,
|
|
'summary': {'success': success, 'failed': len(results)-success},
|
|
'results': results
|
|
})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
|
|
# ========================================
|
|
# Blueprint 등록 함수
|
|
# ========================================
|
|
|
|
|
|
def register_idrac_routes(app):
|
|
"""
|
|
idrac_routes 등록 및 초기화
|
|
"""
|
|
# Blueprint 등록
|
|
app.register_blueprint(idrac_bp)
|
|
|
|
# CSRF 제외 - app에 이미 설정된 csrf 인스턴스 사용
|
|
try:
|
|
from flask_wtf.csrf import CSRFProtect
|
|
# app에 이미 csrf가 설정되어 있으므로, 해당 인스턴스를 가져와서 exempt 설정
|
|
csrf = app.extensions.get('csrf')
|
|
if csrf:
|
|
csrf.exempt(idrac_bp)
|
|
except Exception as e:
|
|
app.logger.warning(f"CSRF exemption failed for idrac_bp: {e}")
|
|
|
|
# DB 생성
|
|
with app.app_context():
|
|
db.create_all()
|