{{/* ConfigMap containing the API backend Python script Handles POST requests to /api/status and updates the status.json file */}} apiVersion: v1 kind: ConfigMap metadata: name: {{ include "gitops-status-server.fullname" . }}-api labels: {{- include "gitops-status-server.labels" . | nindent 4 }} data: app.py: | #!/usr/bin/env python3 """ Simple Flask API for updating status.json Listens on port 5000 and handles POST requests to /api/status """ import os import json import logging from flask import Flask, request, jsonify from datetime import datetime app = Flask(__name__) # Configuration STATUS_FILE = '/usr/share/nginx/html/status.json' API_PORT = int(os.environ.get('API_PORT', 5000)) API_HOST = os.environ.get('API_HOST', '127.0.0.1') # Setup logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) def load_status(): """Load the current status from file""" try: if os.path.exists(STATUS_FILE): with open(STATUS_FILE, 'r') as f: return json.load(f) else: # Default status if file doesn't exist return { "repo": "unknown", "server": "unknown", "sync_status": "UNKNOWN", "drift_count": 0, "files": [], "last_check": "" } except Exception as e: logger.error(f"Error loading status: {e}") return {} def save_status(status): """Save the status to file""" try: # Ensure directory exists (should already exist from mount) os.makedirs(os.path.dirname(STATUS_FILE), exist_ok=True) # Write with proper formatting with open(STATUS_FILE, 'w') as f: json.dump(status, f, indent=2) logger.info(f"Status saved successfully: {status['repo']}/{status['server']} -> {status['sync_status']}") return True except Exception as e: logger.error(f"Error saving status: {e}") return False @app.route('/api/status', methods=['GET', 'POST', 'OPTIONS']) def api_status(): """ GET: Retrieve current status POST: Update status with new data """ if request.method == 'OPTIONS': return '', 204 if request.method == 'GET': status = load_status() return jsonify(status), 200 if request.method == 'POST': try: # Parse incoming JSON incoming_data = request.get_json() if not incoming_data: return jsonify({"error": "No JSON data provided"}), 400 # Load current status status = load_status() # Update with incoming data (merge) status.update(incoming_data) # Ensure required fields exist if 'last_check' not in status or not status['last_check']: status['last_check'] = datetime.utcnow().isoformat() + 'Z' # Save updated status if save_status(status): return jsonify({ "success": True, "message": "Status updated successfully", "status": status }), 200 else: return jsonify({ "error": "Failed to save status" }), 500 except json.JSONDecodeError: return jsonify({"error": "Invalid JSON"}), 400 except Exception as e: logger.error(f"Error processing POST request: {e}") return jsonify({"error": str(e)}), 500 @app.route('/health', methods=['GET']) def health(): """Health check endpoint""" return jsonify({"status": "healthy"}), 200 @app.route('/ready', methods=['GET']) def ready(): """Readiness check - verify status file is accessible""" try: status = load_status() if status: return jsonify({"status": "ready"}), 200 else: return jsonify({"status": "not_ready", "reason": "status file empty"}), 503 except Exception as e: return jsonify({"status": "not_ready", "error": str(e)}), 503 if __name__ == '__main__': logger.info(f"Starting gitops-status-server API on {API_HOST}:{API_PORT}") logger.info(f"Status file: {STATUS_FILE}") app.run(host=API_HOST, port=API_PORT, debug=False)