import logging import json import os from datetime import datetime from flask import Blueprint, request, jsonify logger = logging.getLogger('picell') bp = Blueprint('services', __name__) @bp.route('/api/services/bus/status', methods=['GET']) def get_service_bus_status(): try: from app import service_bus return jsonify(service_bus.get_service_status_summary()) except Exception as e: logger.error(f"Error getting service bus status: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/services/bus/events', methods=['GET']) def get_service_bus_events(): try: from app import service_bus from service_bus import EventType event_type = request.args.get('type') source = request.args.get('source') limit = int(request.args.get('limit', 100)) events = service_bus.get_event_history( EventType(event_type) if event_type else None, source, limit ) return jsonify([{ 'event_id': e.event_id, 'event_type': e.event_type.value, 'source': e.source, 'data': e.data, 'timestamp': e.timestamp.isoformat() } for e in events]) except Exception as e: logger.error(f"Error getting service bus events: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/services/bus/services//start', methods=['POST']) def start_service(service_name): try: from app import service_bus success = service_bus.orchestrate_service_start(service_name) if success: return jsonify({"message": f"Service {service_name} started successfully"}) return jsonify({"error": f"Failed to start service {service_name}"}), 500 except Exception as e: logger.error(f"Error starting service {service_name}: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/services/bus/services//stop', methods=['POST']) def stop_service(service_name): try: from app import service_bus success = service_bus.orchestrate_service_stop(service_name) if success: return jsonify({"message": f"Service {service_name} stopped successfully"}) return jsonify({"error": f"Failed to stop service {service_name}"}), 500 except Exception as e: logger.error(f"Error stopping service {service_name}: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/services/bus/services//restart', methods=['POST']) def restart_service(service_name): try: from app import service_bus success = service_bus.orchestrate_service_restart(service_name) if success: return jsonify({"message": f"Service {service_name} restarted successfully"}) return jsonify({"error": f"Failed to restart service {service_name}"}), 500 except Exception as e: logger.error(f"Error restarting service {service_name}: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/services/', methods=['GET']) def get_service_logs(service): try: from app import log_manager level = request.args.get('level', 'INFO') lines = int(request.args.get('lines', 50)) logs = log_manager.get_service_logs(service, level, lines) return jsonify({"service": service, "logs": logs}) except Exception as e: logger.error(f"Error getting logs for {service}: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/search', methods=['POST']) def search_logs(): try: from app import log_manager data = request.get_json(silent=True) or {} results = log_manager.search_logs( data.get('query', ''), data.get('time_range'), data.get('services'), data.get('level') ) return jsonify({"results": results, "count": len(results)}) except Exception as e: logger.error(f"Error searching logs: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/export', methods=['POST']) def export_logs(): try: from app import log_manager data = request.get_json(silent=True) or {} format = data.get('format', 'json') log_data = log_manager.export_logs(format, data.get('filters', {})) return jsonify({"logs": log_data, "format": format}) except Exception as e: logger.error(f"Error exporting logs: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/statistics', methods=['GET']) def get_log_statistics(): try: from app import log_manager return jsonify(log_manager.get_log_statistics(request.args.get('service'))) except Exception as e: logger.error(f"Error getting log statistics: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/rotate', methods=['POST']) def rotate_logs(): try: from app import log_manager data = request.get_json(silent=True) or {} log_manager.rotate_logs(data.get('service')) return jsonify({"message": "Logs rotated successfully"}) except Exception as e: logger.error(f"Error rotating logs: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/files', methods=['GET']) def get_log_file_infos(): try: from app import log_manager return jsonify(log_manager.get_all_log_file_infos()) except Exception as e: logger.error(f"Error listing log files: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/verbosity', methods=['GET']) def get_log_verbosity(): try: from app import log_manager return jsonify(log_manager.get_service_levels()) except Exception as e: logger.error(f"Error getting log verbosity: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs/verbosity', methods=['PUT']) def set_log_verbosity(): try: from app import log_manager data = request.get_json(silent=True) or {} for service, level in data.items(): log_manager.set_service_level(service, level) levels_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config', 'log_levels.json') os.makedirs(os.path.dirname(levels_file), exist_ok=True) current = {} if os.path.exists(levels_file): try: with open(levels_file) as f: current = json.load(f) except Exception: pass current.update(data) with open(levels_file, 'w') as f: json.dump(current, f, indent=2) return jsonify({"message": "Log levels updated", "levels": log_manager.get_service_levels()}) except Exception as e: logger.error(f"Error setting log verbosity: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/services/status', methods=['GET']) def get_all_services_status(): try: from app import service_bus services_status = {} for service_name in service_bus.list_services(): try: service = service_bus.get_service(service_name) status = service.get_status() if isinstance(status, dict): clean_status = { 'status': status.get('status', 'unknown'), 'running': status.get('running', False), 'timestamp': status.get('timestamp', datetime.utcnow().isoformat()) } if service_name == 'network': clean_status.update({ 'dns_status': status.get('dns_running', False), 'dhcp_status': status.get('dhcp_running', False), 'ntp_status': status.get('ntp_running', False) }) elif service_name == 'wireguard': clean_status.update({ 'peers_count': status.get('peers_count', 0), 'interface': status.get('interface', 'unknown') }) elif service_name == 'email': clean_status.update({ 'users_count': status.get('users_count', 0), 'domain': status.get('domain', 'unknown') }) elif service_name == 'calendar': clean_status.update({ 'users_count': status.get('users_count', 0), 'calendars_count': status.get('calendars_count', 0) }) elif service_name == 'files': clean_status.update({ 'users_count': status.get('users_count', 0), 'storage_used': status.get('total_storage_used', {}) }) elif service_name == 'routing': clean_status.update({ 'nat_rules_count': status.get('nat_rules_count', 0), 'peer_routes_count': status.get('peer_routes_count', 0), 'firewall_rules_count': status.get('firewall_rules_count', 0) }) elif service_name == 'vault': clean_status.update({ 'certificates_count': status.get('certificates_count', 0), 'trusted_keys_count': status.get('trusted_keys_count', 0) }) services_status[service_name] = clean_status else: services_status[service_name] = {'status': str(status), 'running': bool(status)} except Exception as e: services_status[service_name] = {'error': str(e), 'status': 'offline', 'running': False} return jsonify({ "network": services_status.get('network', {}), "wireguard": services_status.get('wireguard', {}), "email": services_status.get('email', {}), "calendar": services_status.get('calendar', {}), "files": services_status.get('files', {}), "routing": services_status.get('routing', {}), "vault": services_status.get('vault', {}), "timestamp": datetime.utcnow().isoformat() }) except Exception as e: logger.error(f"Error getting all services status: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/services/connectivity', methods=['GET']) def test_all_services_connectivity(): try: from app import service_bus connectivity_results = {} for service_name in service_bus.list_services(): try: service = service_bus.get_service(service_name) if hasattr(service, 'test_connectivity'): connectivity_results[service_name] = service.test_connectivity() else: connectivity_results[service_name] = {'status': 'ok', 'message': 'No connectivity test available'} except Exception as e: connectivity_results[service_name] = {'status': 'error', 'message': str(e)} return jsonify({ "network": connectivity_results.get('network', {}), "wireguard": connectivity_results.get('wireguard', {}), "email": connectivity_results.get('email', {}), "calendar": connectivity_results.get('calendar', {}), "files": connectivity_results.get('files', {}), "routing": connectivity_results.get('routing', {}), "timestamp": datetime.utcnow().isoformat() }) except Exception as e: logger.error(f"Error testing all services connectivity: {e}") return jsonify({"error": str(e)}), 500 @bp.route('/api/logs', methods=['GET']) def get_backend_logs(): log_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'picell.log') lines = int(request.args.get('lines', 100)) try: if not os.path.exists(log_file): return jsonify({"error": "Log file not found."}), 404 with open(log_file, 'r', encoding='utf-8', errors='ignore') as f: all_lines = f.readlines() tail_lines = all_lines[-lines:] if lines > 0 else all_lines return jsonify({"log": ''.join(tail_lines)}) except Exception as e: logger.error(f"Error reading log file: {e}") return jsonify({"error": str(e)}), 500