-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from DioCrafts/feature/frontend-helm-chart
Feature/frontend helm chart
- Loading branch information
Showing
38 changed files
with
1,536 additions
and
1,248 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
//! Handlers para la gestión de backends en el API Gateway. | ||
use actix_web::{web, HttpResponse, Responder}; | ||
use serde::{Deserialize, Serialize}; | ||
use std::sync::Mutex; | ||
|
||
// Estructura del backend | ||
#[derive(Serialize, Deserialize, Clone)] | ||
pub struct Backend { | ||
pub id: u32, | ||
pub name: String, | ||
pub address: String, | ||
pub port: u16, | ||
pub status: String, // Healthy, Unhealthy, Degraded | ||
pub weight: Option<u32>, // Para balanceo de carga ponderado | ||
} | ||
|
||
// Estado compartido del servidor | ||
pub struct AppState { | ||
pub backends: Mutex<Vec<Backend>>, | ||
} | ||
|
||
// Listar todos los backends | ||
pub async fn list_backends(data: web::Data<AppState>) -> impl Responder { | ||
let backends = data.backends.lock().unwrap(); | ||
HttpResponse::Ok().json(&*backends) | ||
} | ||
|
||
// Agregar un nuevo backend | ||
pub async fn add_backend(data: web::Data<AppState>, backend: web::Json<Backend>) -> impl Responder { | ||
let mut backends = data.backends.lock().unwrap(); | ||
let mut new_backend = backend.into_inner(); | ||
// Generar ID único para el nuevo backend | ||
new_backend.id = backends.last().map_or(1, |b| b.id + 1); | ||
new_backend.status = "Unknown".to_string(); // Inicialmente desconocido | ||
backends.push(new_backend); | ||
HttpResponse::Created().finish() | ||
} | ||
|
||
// Actualizar un backend existente | ||
pub async fn update_backend( | ||
data: web::Data<AppState>, | ||
id: web::Path<u32>, | ||
updated_backend: web::Json<Backend>, | ||
) -> impl Responder { | ||
let mut backends = data.backends.lock().unwrap(); | ||
let id = id.into_inner(); | ||
if let Some(backend) = backends.iter_mut().find(|b| b.id == id) { | ||
backend.name = updated_backend.name.clone(); | ||
backend.address = updated_backend.address.clone(); | ||
backend.port = updated_backend.port; | ||
backend.weight = updated_backend.weight; | ||
HttpResponse::Ok().finish() | ||
} else { | ||
HttpResponse::NotFound().finish() | ||
} | ||
} | ||
|
||
// Eliminar un backend por ID | ||
pub async fn delete_backend(data: web::Data<AppState>, id: web::Path<u32>) -> impl Responder { | ||
let mut backends = data.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().finish() | ||
} else { | ||
HttpResponse::NotFound().finish() | ||
} | ||
} | ||
|
||
// Health Check de los backends | ||
pub async fn health_check(data: web::Data<AppState>) -> impl Responder { | ||
let mut backends = data.backends.lock().unwrap(); | ||
for backend in backends.iter_mut() { | ||
let url = format!("http://{}:{}", backend.address, backend.port); | ||
if let Ok(response) = reqwest::get(&url).await { | ||
backend.status = if response.status().is_success() { | ||
"Healthy".to_string() | ||
} else { | ||
"Unhealthy".to_string() | ||
}; | ||
} else { | ||
backend.status = "Unhealthy".to_string(); | ||
} | ||
} | ||
HttpResponse::Ok().json(&*backends) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
pub mod handlers; | ||
pub mod routes; | ||
|
||
pub use routes::configure_routes; | ||
|
||
/// Inicializar el manejador de backends | ||
pub async fn start_backends_manager() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { | ||
println!("Starting Backends Manager..."); | ||
// Aquí iría la lógica específica de inicialización del manejador de backends | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
use actix_web::web; | ||
use super::handlers; | ||
|
||
pub fn configure_routes(cfg: &mut web::ServiceConfig) { | ||
cfg.service( | ||
web::scope("/api/backends") | ||
.route("", web::get().to(handlers::list_backends)) | ||
.route("", web::post().to(handlers::add_backend)) | ||
.route("/{id}", web::put().to(handlers::update_backend)) | ||
.route("/{id}", web::delete().to(handlers::delete_backend)) | ||
.route("/health-check", web::get().to(handlers::health_check)), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
//! src/gateway/crd/gateway.rs | ||
//! | ||
//! Gestión de los recursos Gateway en Kubernetes. | ||
//! | ||
//! Este módulo implementa el `GatewayManager`, que proporciona métodos para | ||
//! crear, listar, eliminar y configurar Gateways como CRDs. | ||
use kube::{Api, Client, CustomResourceExt}; | ||
use kube::api::{PostParams, DeleteParams, ListParams, ApiResource, DynamicObject}; | ||
use serde::{Deserialize, Serialize}; | ||
use schemars::JsonSchema; | ||
use kube_derive::CustomResource; | ||
use thiserror::Error; | ||
use kube::core::GroupVersionKind; | ||
|
||
/// Especificación interna para el recurso Gateway. | ||
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct GatewayInnerSpec { | ||
pub hostname: String, // Nombre del host | ||
pub tls_enabled: bool, // TLS habilitado o no | ||
pub certificate: Option<String>, // Certificado TLS (si aplica) | ||
pub routes: Vec<Route>, // Lista de rutas asociadas al Gateway | ||
} | ||
|
||
/// Definición de rutas asociadas al Gateway. | ||
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Route { | ||
pub path: String, // Path como "/api/v1/*" o expresiones regulares | ||
pub backend: String, // Backend al que se enruta | ||
pub methods: Vec<String>, // Métodos HTTP permitidos (GET, POST, etc.) | ||
} | ||
|
||
/// Definición del CRD `Gateway`. | ||
#[derive(CustomResource, Clone, Debug, Deserialize, Serialize, JsonSchema)] | ||
#[kube( | ||
group = "networking.k8s.io", // Grupo del CRD | ||
version = "v1alpha1", // Versión del API | ||
kind = "Gateway", // Tipo de recurso | ||
namespaced, // Es un recurso namespaced | ||
)] | ||
pub struct GatewaySpec { | ||
pub spec: GatewayInnerSpec, // Especificación principal del Gateway | ||
} | ||
|
||
/// Manager para interactuar con los recursos Gateway en Kubernetes. | ||
pub struct GatewayManager { | ||
client: Client, // Cliente de Kubernetes | ||
ar: ApiResource, // ApiResource que define los detalles del recurso DynamicObject | ||
} | ||
|
||
impl GatewayManager { | ||
/// Crear una nueva instancia del `GatewayManager`. | ||
pub fn new(client: Client) -> Self { | ||
// Definir el ApiResource para el recurso Gateway. | ||
let gvk = GroupVersionKind::gvk("networking.k8s.io", "v1alpha1", "Gateway"); | ||
let ar = ApiResource::from_gvk(&gvk); | ||
|
||
Self { client, ar } | ||
} | ||
|
||
/// Listar todos los Gateways en el namespace especificado. | ||
pub async fn list_gateways(&self, namespace: &str) -> Result<Vec<DynamicObject>, GatewayError> { | ||
let gateways: Api<DynamicObject> = Api::namespaced_with(self.client.clone(), namespace, &self.ar); | ||
let lp = ListParams::default(); | ||
let gateway_list = gateways.list(&lp).await?; | ||
Ok(gateway_list.items) | ||
} | ||
|
||
/// Crear un nuevo Gateway. | ||
pub async fn create_gateway( | ||
&self, | ||
namespace: &str, | ||
gateway: &GatewaySpec, | ||
) -> Result<DynamicObject, GatewayError> { | ||
let gateways: Api<DynamicObject> = Api::namespaced_with(self.client.clone(), namespace, &self.ar); | ||
let pp = PostParams::default(); | ||
|
||
// Usar el hostname como nombre del recurso. | ||
let name = gateway.spec.hostname.clone(); | ||
|
||
// Crear un DynamicObject con la información del Gateway. | ||
let mut crd = DynamicObject::new(&name, &self.ar); | ||
crd.data = serde_json::Value::Object( | ||
serde_json::to_value(gateway)?.as_object().cloned().unwrap_or_default() | ||
); | ||
|
||
let created_gateway = gateways.create(&pp, &crd).await?; | ||
Ok(created_gateway) | ||
} | ||
|
||
/// Eliminar un Gateway por nombre. | ||
pub async fn delete_gateway(&self, namespace: &str, name: &str) -> Result<(), GatewayError> { | ||
let gateways: Api<DynamicObject> = Api::namespaced_with(self.client.clone(), namespace, &self.ar); | ||
gateways.delete(name, &DeleteParams::default()).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Configurar TLS para un Gateway. | ||
pub async fn configure_tls( | ||
&self, | ||
namespace: &str, | ||
name: &str, | ||
certificate: &str, | ||
) -> Result<(), GatewayError> { | ||
let gateways: Api<DynamicObject> = Api::namespaced_with(self.client.clone(), namespace, &self.ar); | ||
|
||
// Obtener el Gateway existente. | ||
let mut existing_gateway = gateways.get(name).await?; | ||
let mut data = existing_gateway.data.clone(); // Clonar el campo data | ||
|
||
// Actualizar el certificado y habilitar TLS. | ||
if let Some(spec) = data.get_mut("spec") { | ||
if let Some(spec_obj) = spec.as_object_mut() { | ||
spec_obj.insert("tlsEnabled".to_string(), serde_json::Value::Bool(true)); | ||
spec_obj.insert("certificate".to_string(), serde_json::Value::String(certificate.to_string())); | ||
} | ||
} | ||
|
||
// Reemplazar el Gateway con los cambios actualizados. | ||
existing_gateway.data = data; // Actualizar el campo data después de la edición | ||
gateways.replace(name, &PostParams::default(), &existing_gateway).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Obtener métricas simuladas de los Gateways. | ||
pub async fn get_metrics(&self) -> Result<Vec<(String, String, u64)>, GatewayError> { | ||
// Ejemplo de métricas simuladas. | ||
Ok(vec![ | ||
("gateway_1".to_string(), "latency".to_string(), 120), | ||
("gateway_1".to_string(), "requests".to_string(), 1500), | ||
]) | ||
} | ||
} | ||
|
||
/// Definición de errores específicos para los Gateways. | ||
#[derive(Error, Debug)] | ||
pub enum GatewayError { | ||
#[error("Error en la API de Kubernetes: {0}")] | ||
KubeError(#[from] kube::Error), | ||
#[error("Error de serialización/deserialización: {0}")] | ||
SerdeError(#[from] serde_json::Error), | ||
} | ||
|
||
/// Implementación de conversión de `models::Route` a `gateway::crd::gateway::Route`. | ||
impl From<crate::gateway::models::Route> for Route { | ||
fn from(route: crate::gateway::models::Route) -> Self { | ||
Route { | ||
path: route.path.unwrap_or_default(), | ||
backend: route.backend, | ||
methods: route.methods, | ||
} | ||
} | ||
} |
Oops, something went wrong.