222 lines
8.8 KiB
Python
222 lines
8.8 KiB
Python
from flask import Blueprint, request, jsonify, current_app
|
|
from datetime import datetime
|
|
|
|
bp = Blueprint('api', __name__, url_prefix='/api')
|
|
|
|
def authenticate_node(node_name, api_key):
|
|
"""Authenticate a node using its name and API key."""
|
|
auth_query = """
|
|
SELECT node_id
|
|
FROM node_auth
|
|
WHERE node_name = ? AND api_key = ? AND status = 'active'
|
|
"""
|
|
result = current_app.db.execute_read_sync(auth_query, (node_name, api_key))
|
|
return result.data[0][0] if result.success and result.data else None
|
|
|
|
def authenticate_admin(api_key):
|
|
"""Authenticate an admin using the API key."""
|
|
return api_key == current_app.config['ADMIN_API_KEY']
|
|
|
|
@bp.route('/node-stats', methods=['POST'])
|
|
def node_stats():
|
|
# Use current_app instead of bp.app
|
|
# app = bp.app # Remove this line
|
|
|
|
# Expected JSON payload example:
|
|
# {
|
|
# "node_name": "node1",
|
|
# "api_key": "xxxx",
|
|
# "hostname": "node1.local",
|
|
# "cpu_percent": 45.5,
|
|
# "memory_used_mb": 2048,
|
|
# "memory_free_mb": 4096,
|
|
# "disk_used_gb": 100,
|
|
# "disk_free_gb": 400,
|
|
# "bytes_sent": 102400,
|
|
# "bytes_received": 51200
|
|
# }
|
|
|
|
try:
|
|
data = request.get_json()
|
|
if not data or not isinstance(data, dict):
|
|
return jsonify({'error': 'Invalid JSON payload'}), 400
|
|
|
|
# Required fields
|
|
required = ['node_name', 'api_key']
|
|
if not all(field in data for field in required):
|
|
return jsonify({'error': 'Missing required fields'}), 400
|
|
|
|
# Authenticate node
|
|
node_id = authenticate_node(data['node_name'], data['api_key'])
|
|
if not node_id:
|
|
return jsonify({'error': 'Authentication failed'}), 401
|
|
|
|
# Update or insert node_info
|
|
node_info_query = """
|
|
INSERT OR REPLACE INTO node_info (
|
|
node_id, hostname, node_nickname, ip_address, os_type,
|
|
cpu_cores, total_memory_mb, total_disk_gb, manufacturer,
|
|
model, location, last_updated
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
"""
|
|
current_app.db.execute_write(node_info_query, (
|
|
node_id,
|
|
data.get('hostname', ''),
|
|
data.get('node_nickname'),
|
|
data.get('ip_address'),
|
|
data.get('os_type'),
|
|
data.get('cpu_cores'),
|
|
data.get('total_memory_mb'),
|
|
data.get('total_disk_gb'),
|
|
data.get('manufacturer'),
|
|
data.get('model'),
|
|
data.get('location'),
|
|
datetime.utcnow().isoformat()
|
|
))
|
|
|
|
# Insert CPU usage
|
|
if 'cpu_percent' in data or 'cpu_temp_celsius' in data:
|
|
cpu_query = """
|
|
INSERT INTO cpu_usage (node_id, cpu_percent, cpu_temp_celsius, timestamp)
|
|
VALUES (?, ?, ?, ?)
|
|
"""
|
|
current_app.db.execute_write(cpu_query, (
|
|
node_id,
|
|
data.get('cpu_percent'),
|
|
data.get('cpu_temp_celsius'),
|
|
datetime.utcnow().isoformat()
|
|
))
|
|
|
|
# Insert memory usage
|
|
if any(k in data for k in ['memory_used_mb', 'memory_free_mb', 'memory_percent']):
|
|
memory_query = """
|
|
INSERT INTO memory_usage (node_id, memory_used_mb, memory_free_mb, memory_percent, timestamp)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
"""
|
|
current_app.db.execute_write(memory_query, (
|
|
node_id,
|
|
data.get('memory_used_mb', 0),
|
|
data.get('memory_free_mb', 0),
|
|
data.get('memory_percent', 0),
|
|
datetime.utcnow().isoformat()
|
|
))
|
|
|
|
# Insert disk usage
|
|
if any(k in data for k in ['disk_used_gb', 'disk_free_gb', 'disk_percent', 'partition_name']):
|
|
disk_query = """
|
|
INSERT INTO disk_usage (node_id, disk_used_gb, disk_free_gb, disk_percent, partition_name, timestamp)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
"""
|
|
current_app.db.execute_write(disk_query, (
|
|
node_id,
|
|
data.get('disk_used_gb', 0),
|
|
data.get('disk_free_gb', 0),
|
|
data.get('disk_percent', 0),
|
|
data.get('partition_name'),
|
|
datetime.utcnow().isoformat()
|
|
))
|
|
|
|
# Insert network usage
|
|
if any(k in data for k in ['bytes_sent', 'bytes_received', 'packets_sent', 'packets_received']):
|
|
network_query = """
|
|
INSERT INTO network_usage (node_id, bytes_sent, bytes_received, packets_sent, packets_received, timestamp)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
"""
|
|
current_app.db.execute_write(network_query, (
|
|
node_id,
|
|
data.get('bytes_sent', 0),
|
|
data.get('bytes_received', 0),
|
|
data.get('packets_sent', 0),
|
|
data.get('packets_received', 0),
|
|
datetime.utcnow().isoformat()
|
|
))
|
|
|
|
# Insert process stats
|
|
if 'process_count' in data or 'zombie_process_count' in data:
|
|
process_query = """
|
|
INSERT INTO process_stats (node_id, process_count, zombie_process_count, timestamp)
|
|
VALUES (?, ?, ?, ?)
|
|
"""
|
|
current_app.db.execute_write(process_query, (
|
|
node_id,
|
|
data.get('process_count', 0),
|
|
data.get('zombie_process_count', 0),
|
|
datetime.utcnow().isoformat()
|
|
))
|
|
|
|
# Insert node connections (if provided)
|
|
if 'target_node_name' in data and 'ping_latency_ms' in data:
|
|
target_node_query = "SELECT node_id FROM node_auth WHERE node_name = ? AND status = 'active'"
|
|
target_result = current_app.db.execute_read_sync(target_node_query, (data['target_node_name'],))
|
|
if target_result.success and target_result.data:
|
|
target_node_id = target_result.data[0][0]
|
|
conn_query = """
|
|
INSERT INTO node_connections (source_node_id, target_node_id, ping_latency_ms, packet_loss_percent, timestamp)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
"""
|
|
current_app.db.execute_write(conn_query, (
|
|
node_id,
|
|
target_node_id,
|
|
data.get('ping_latency_ms'),
|
|
data.get('packet_loss_percent', 0),
|
|
datetime.utcnow().isoformat()
|
|
))
|
|
|
|
return jsonify({'status': 'success', 'message': 'Stats recorded'}), 201
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': f'Internal server error: {str(e)}'}), 500
|
|
|
|
@bp.route('/admin/nodes', methods=['POST'])
|
|
def manage_nodes():
|
|
try:
|
|
data = request.get_json()
|
|
if not data or 'api_key' not in data:
|
|
return jsonify({'error': 'Admin API key required'}), 400
|
|
|
|
if not authenticate_admin(data['api_key']):
|
|
return jsonify({'error': 'Admin authentication failed'}), 401
|
|
|
|
# Expected payload:
|
|
# {
|
|
# "api_key": "admin-key",
|
|
# "action": "add|modify|delete",
|
|
# "node_name": "node1",
|
|
# "node_api_key": "xxxx" (for add/modify)
|
|
# }
|
|
action = data.get('action')
|
|
node_name = data.get('node_name')
|
|
|
|
if action == 'add':
|
|
node_api_key = data.get('node_api_key')
|
|
if not node_name or not node_api_key:
|
|
return jsonify({'error': 'node_name and node_api_key required'}), 400
|
|
query = """
|
|
INSERT INTO node_auth (node_name, api_key, status)
|
|
VALUES (?, ?, 'active')
|
|
ON CONFLICT(node_name) DO UPDATE SET api_key = ?, status = 'active'
|
|
"""
|
|
current_app.db.execute_write(query, (node_name, node_api_key, node_api_key))
|
|
return jsonify({'status': 'success', 'message': f'Node {node_name} added/updated'}), 201
|
|
|
|
elif action == 'modify':
|
|
node_api_key = data.get('node_api_key')
|
|
if not node_name or not node_api_key:
|
|
return jsonify({'error': 'node_name and node_api_key required'}), 400
|
|
query = "UPDATE node_auth SET api_key = ? WHERE node_name = ?"
|
|
current_app.db.execute_write(query, (node_api_key, node_name))
|
|
return jsonify({'status': 'success', 'message': f'Node {node_name} modified'}), 200
|
|
|
|
elif action == 'delete':
|
|
if not node_name:
|
|
return jsonify({'error': 'node_name required'}), 400
|
|
query = "UPDATE node_auth SET status = 'inactive' WHERE node_name = ?"
|
|
current_app.db.execute_write(query, (node_name,))
|
|
return jsonify({'status': 'success', 'message': f'Node {node_name} deleted'}), 200
|
|
|
|
else:
|
|
return jsonify({'error': 'Invalid action'}), 400
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': f'Internal server error: {str(e)}'}), 500
|