Initial project upload
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user