Skip to content

Commit

Permalink
Merge pull request #17 from DioCrafts/feature/frontend-helm-chart
Browse files Browse the repository at this point in the history
fixing API Rest errors - Split App States
  • Loading branch information
DioCrafts authored Nov 21, 2024
2 parents 7e6c0c9 + fa40f13 commit 3700a24
Show file tree
Hide file tree
Showing 14 changed files with 286 additions and 107 deletions.
1 change: 1 addition & 0 deletions api-gateway/backend/src/backends/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//src/backends/handlers.rs
//! Handlers para la gestión de backends en el API Gateway.
use actix_web::{web, HttpResponse, Responder};
Expand Down
1 change: 1 addition & 0 deletions api-gateway/backend/src/backends/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//src/backends/mods.rs
pub mod handlers;
pub mod routes;

Expand Down
1 change: 1 addition & 0 deletions api-gateway/backend/src/backends/routes.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//src/backends/routers.rs
use actix_web::web;
use super::handlers;

Expand Down
2 changes: 1 addition & 1 deletion api-gateway/backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
}),

// Start REST API server
start_rest_server(rest_port).map_err(|e| {
start_rest_server(rest_port, client.clone()).map_err(|e| {
eprintln!("Error in start_rest_server: {:?}", e);
Box::<dyn std::error::Error + Send + Sync>::from(e)
}),
Expand Down
7 changes: 7 additions & 0 deletions api-gateway/backend/src/observability/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// src/observability/handlers.rs
//
//! Handlers para la observabilidad en el API Gateway.
//!
//! Este módulo gestiona métricas, logs y la integración con sistemas de monitoreo como Prometheus.
Expand Down Expand Up @@ -29,6 +31,7 @@ pub struct LogEntry {
pub struct ObservabilityState {
pub metrics: Mutex<Vec<Metric>>,
pub logs: Mutex<Vec<LogEntry>>,
pub alerts: Mutex<Vec<String>>, // Aquí añadimos el campo de alertas
}

impl ObservabilityState {
Expand Down Expand Up @@ -56,6 +59,10 @@ impl ObservabilityState {
latency_ms: 100,
},
]),
alerts: Mutex::new(vec![
"High CPU usage detected".to_string(),
"Memory consumption exceeded threshold".to_string(),
]), // Añadir alertas simuladas
}
}
}
Expand Down
196 changes: 164 additions & 32 deletions api-gateway/backend/src/rest/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,56 +1,188 @@
//src/rest/handlers.rs
//! REST API Handlers
//!
//! These functions handle incoming HTTP requests and return appropriate responses.
use actix_web::{web, HttpResponse, Responder};
use serde_json::json;
use crate::backends::handlers::AppState as BackendsState;
use crate::security::handlers::{AppState as SecurityState, SecurityPolicy};
use crate::observability::handlers::ObservabilityState;

use crate::backends::handlers::Backend;
use kube::Client;
use crate::gateway::crd::gateway::GatewayManager;

/// Handler for `GET /api/metrics`
///
/// Returns a list of metrics (mocked example data for now).
pub async fn get_metrics() -> impl Responder {
let metrics = json!([
{ "timestamp": "2024-11-17T12:00:00Z", "rps": 150, "latency": 200, "errors": 5 },
{ "timestamp": "2024-11-17T12:01:00Z", "rps": 160, "latency": 180, "errors": 3 }
]);
HttpResponse::Ok().json(metrics)
}

/// Handler for `GET /api/backends`
///
/// Returns a list of backend services.
pub async fn get_backends() -> impl Responder {
let backends = json!([
{ "id": 1, "name": "Backend 1", "address": "192.168.1.10", "port": 80, "status": "Healthy" },
{ "id": 2, "name": "Backend 2", "address": "192.168.1.11", "port": 8080, "status": "Unhealthy" }
]);
HttpResponse::Ok().json(backends)
/// Delegates to the backend module to list backends.
pub async fn get_backends(data: web::Data<BackendsState>) -> impl Responder {
crate::backends::handlers::list_backends(data).await
}

/// Handler for `POST /api/backends`
///
/// Adds a new backend service.
pub async fn add_backend(backend: web::Json<serde_json::Value>) -> impl Responder {
println!("Adding new backend: {:?}", backend);
HttpResponse::Created().json(json!({ "message": "Backend added", "backend": backend }))
pub async fn add_backend(
app_state: web::Data<BackendsState>,
backend: web::Json<Backend>,
) -> impl Responder {
let mut backends = app_state.backends.lock().unwrap();
let mut new_backend = backend.into_inner();
new_backend.id = backends.last().map_or(1, |b| b.id + 1);
new_backend.status = "Unknown".to_string();
backends.push(new_backend);

HttpResponse::Created().json(json!({ "message": "Backend added successfully" }))
}

/// Handler for `DELETE /api/backends/{id}`
///
/// Deletes a backend service by ID.
pub async fn delete_backend(path: web::Path<u32>) -> impl Responder {
let id = path.into_inner(); // Extraer el valor de Path
println!("Deleting backend with ID: {}", id);
HttpResponse::Ok().json(json!({ "message": "Backend deleted", "id": id }))
pub async fn delete_backend(
app_state: web::Data<BackendsState>,
id: web::Path<u32>,
) -> impl Responder {
let mut backends = app_state.backends.lock().unwrap();
let id = id.into_inner();
let initial_len = backends.len();
backends.retain(|backend| backend.id != id);

if backends.len() < initial_len {
HttpResponse::Ok().json(json!({ "message": "Backend deleted successfully", "id": id }))
} else {
HttpResponse::NotFound().json(json!({ "error": "Backend not found", "id": id }))
}
}

/// Handler for `GET /api/security/policies`
///
/// Retrieves a list of security policies.
pub async fn get_policies(data: web::Data<SecurityState>) -> impl Responder {
let policies = data.policies.lock().unwrap();
HttpResponse::Ok().json(&*policies)
}

/// Handler for `POST /api/security/policies`
///
/// Adds a new security policy.
pub async fn add_policy(
data: web::Data<SecurityState>,
policy: web::Json<SecurityPolicy>,
) -> impl Responder {
let mut policies = data.policies.lock().unwrap();
let mut new_policy = policy.into_inner();
new_policy.id = policies.last().map_or(1, |p| p.id + 1);
policies.push(new_policy);

HttpResponse::Created().json(json!({ "message": "Policy added successfully" }))
}

/// Handler for `GET /api/alerts`

/// Handler for `GET /api/gateways`
///
/// Returns a list of alerts (mocked example data for now).
pub async fn get_alerts() -> impl Responder {
let alerts = json!([
{ "id": 1, "message": "High latency detected" },
{ "id": 2, "message": "Backend unreachable" }
]);
HttpResponse::Ok().json(alerts)
/// Returns a list of gateways from the Kubernetes cluster.
pub async fn get_gateways(client: web::Data<Client>) -> impl Responder {
let manager = GatewayManager::new(client.get_ref().clone());

match manager.list_gateways("default").await {
Ok(gateways) => HttpResponse::Ok().json(gateways),
Err(e) => {
eprintln!("Error listing Gateways: {:?}", e);
HttpResponse::InternalServerError().body("Failed to list Gateways.")
}
}
}

/// Handler for `POST /api/gateways`
pub async fn add_gateway(
client: web::Data<Client>,
gateway: web::Json<crate::gateway::models::Gateway>,
) -> impl Responder {
let manager = GatewayManager::new(client.get_ref().clone());
let gateway_spec = crate::gateway::crd::gateway::GatewaySpec {
spec: crate::gateway::crd::gateway::GatewayInnerSpec {
hostname: gateway.hostname.clone(),
tls_enabled: gateway.tls_enabled,
certificate: gateway.certificate.clone(),
routes: gateway.routes.iter().cloned().map(Into::into).collect(),
},
};

match manager.create_gateway("default", &gateway_spec).await {
Ok(_) => HttpResponse::Created().json(json!({ "message": "Gateway created successfully." })),
Err(e) => {
eprintln!("Error creating Gateway: {:?}", e);
HttpResponse::InternalServerError().body("Failed to create Gateway.")
}
}
}

/// Handler for `DELETE /api/gateways/{id}`
pub async fn delete_gateway(
client: web::Data<Client>,
id: web::Path<String>,
) -> impl Responder {
let manager = GatewayManager::new(client.get_ref().clone());

match manager.delete_gateway("default", &id.into_inner()).await {
Ok(_) => HttpResponse::Ok().json(json!({ "message": "Gateway deleted successfully." })),
Err(e) => {
eprintln!("Error deleting Gateway: {:?}", e);
HttpResponse::InternalServerError().body("Failed to delete Gateway.")
}
}
}

/// Handler for `GET /api/metrics`
///
/// Returns a list of metrics (from Observability module).
pub async fn get_metrics(data: web::Data<ObservabilityState>) -> impl Responder {
let metrics = data.metrics.lock().unwrap();
HttpResponse::Ok().json(&*metrics)
}

/// Handler for `GET /api/observability/alerts`
///
/// Returns a list of alerts from Observability state.
pub async fn get_observability_alerts(data: web::Data<ObservabilityState>) -> impl Responder {
let alerts = data.alerts.lock().unwrap(); // Acceso al nuevo campo `alerts`
HttpResponse::Ok().json(&*alerts)
}


/// Handler for `GET /api/observability/logs`
///
/// Returns a list of logs from Observability state.
pub async fn get_logs(data: web::Data<ObservabilityState>) -> impl Responder {
let logs = data.logs.lock().unwrap();
HttpResponse::Ok().json(&*logs)
}


/// Handler for `DELETE /api/security/policies/{id}`
///
/// Deletes a security policy by ID.
pub async fn delete_policy(
data: web::Data<SecurityState>,
id: web::Path<u32>,
) -> impl Responder {
let mut policies = data.policies.lock().unwrap();
let id = *id;
let initial_len = policies.len();
policies.retain(|policy| policy.id != id);

if policies.len() < initial_len {
HttpResponse::Ok().json(json!({ "message": "Policy deleted successfully", "id": id }))
} else {
HttpResponse::NotFound().json(json!({ "error": "Policy not found", "id": id }))
}
}

/// Handler for `GET /api/security/protected`
///
/// A protected endpoint for demonstration purposes.
pub async fn protected_endpoint() -> impl Responder {
HttpResponse::Ok().body("This is a protected endpoint!")
}
54 changes: 29 additions & 25 deletions api-gateway/backend/src/rest/mod.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
//! REST API Module for Flusso
//!
//! This module handles all REST endpoints for the backend, exposing data
//! for the frontend and other clients.
use actix_cors::Cors;
use actix_web::{App, HttpServer};
use actix_web::web::{Data, ServiceConfig};
use std::sync::Mutex;
use kube::Client; // Importa el cliente de Kubernetes

pub mod routes; // Declarar submódulo de rutas
pub mod handlers; // Declarar submódulo de handlers

use crate::rest::routes::configure_routes;
use crate::backends::handlers::AppState as BackendsState;
use crate::security::handlers::AppState as SecurityState;
use crate::observability::handlers::ObservabilityState;

/// Starts the REST API server.
///
/// # Arguments
/// - `port`: Port number for the REST server.
///
/// # Returns
/// A `Result` indicating whether the server started successfully.
pub async fn start_rest_server(port: u16) -> std::io::Result<()> {
pub async fn start_rest_server(port: u16, client: Client) -> std::io::Result<()> {
println!("Starting REST server on port {}", port);

HttpServer::new(move || {
// Configura el middleware CORS dentro del closure
let cors = Cors::default()
.allow_any_origin() // Permite cualquier origen; cambia esto en producción
.allow_any_header()
.allow_any_method();
let backends_state = Data::new(BackendsState {
backends: Mutex::new(vec![]),
});

let security_state = Data::new(SecurityState {
policies: Mutex::new(vec![]),
});

let observability_state = Data::new(ObservabilityState::new()); // Usa el método new()

// Si necesitas usar el cliente `client` en el futuro, puedes incluirlo aquí.

HttpServer::new(move || {
App::new()
.wrap(cors) // Aplica CORS al App
.configure(configure_routes) // Registra las rutas
.app_data(backends_state.clone())
.app_data(security_state.clone())
.app_data(observability_state.clone())
// Puedes registrar el cliente como parte del estado compartido si es necesario.
.app_data(Data::new(client.clone()))
.configure(|cfg: &mut ServiceConfig| configure_routes(cfg))
})
.bind(("0.0.0.0", port))?
.run()
.await
}

pub mod handlers;
pub mod routes;
36 changes: 26 additions & 10 deletions api-gateway/backend/src/rest/routes.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
//! Route configuration for the REST API
//src/rest/routes.rs

use actix_web::web;
use crate::rest::handlers;
use crate::rest::handlers::{get_backends, add_backend, delete_backend};
use crate::gateway::handlers::{list_gateways, add_gateway, delete_gateway, configure_tls, get_gateway_metrics};
use crate::observability::handlers::{get_metrics, get_logs, export_prometheus_metrics}; // Importa handlers correctos
use crate::security::handlers::{list_policies, add_policy, delete_policy, protected_endpoint};

/// Configures the REST API routes.
///
/// This function is used to register all the available endpoints for the REST API.
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/api")
.route("/metrics", web::get().to(handlers::get_metrics)) // GET /api/metrics
.route("/alerts", web::get().to(handlers::get_alerts)) // GET /api/alerts
.route("/backends", web::get().to(handlers::get_backends)) // GET /api/backends
.route("/backends", web::post().to(handlers::add_backend)) // POST /api/backends
.route("/backends/{id}", web::delete().to(handlers::delete_backend)), // DELETE /api/backends/{id}
.route("/metrics", web::get().to(get_metrics)) // GET /api/metrics
.route("/logs", web::get().to(get_logs)) // GET /api/logs
.route("/metrics/export", web::get().to(export_prometheus_metrics)) // GET /api/metrics/export

// Backends
.route("/backends", web::get().to(get_backends)) // GET /api/backends
.route("/backends", web::post().to(add_backend)) // POST /api/backends
.route("/backends/{id}", web::delete().to(delete_backend)) // DELETE /api/backends/{id}

// Gateways
.route("/gateways", web::get().to(list_gateways)) // GET /api/gateways
.route("/gateways", web::post().to(add_gateway)) // POST /api/gateways
.route("/gateways/{id}", web::delete().to(delete_gateway)) // DELETE /api/gateways/{id}
.route("/gateways/tls", web::post().to(configure_tls)) // POST /api/gateways/tls
.route("/gateways/metrics", web::get().to(get_gateway_metrics)) // GET /api/gateways/metrics

// Security
.route("/security/policies", web::get().to(list_policies)) // GET /api/security/policies
.route("/security/policies", web::post().to(add_policy)) // POST /api/security/policies
.route("/security/policies/{id}", web::delete().to(delete_policy)) // DELETE /api/security/policies/{id}
.route("/security/protected", web::get().to(protected_endpoint)), // GET /api/security/protected
);
}

1 change: 1 addition & 0 deletions api-gateway/backend/src/security/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// src/security/handlers.rs
use actix_web::{web, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
Expand Down
1 change: 1 addition & 0 deletions api-gateway/backend/src/security/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// src/security/mod.rs
pub mod handlers;
pub mod routes;

Expand Down
1 change: 1 addition & 0 deletions api-gateway/backend/src/security/routes.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// src/security/routes.rs
use actix_web::web;
use super::handlers;

Expand Down
Loading

0 comments on commit 3700a24

Please sign in to comment.