use crate::internal::{Ingress, IngressType};
use k8s_crds_traefik::*;
use k8s_openapi::apimachinery::pkg::apis::meta::v1 as k8s_meta;
use k8s_openapi::apimachinery::pkg::util::intstr::IntOrString;
use slugify::slugify;
pub fn get_app_ingress(
domain: Option<String>,
sources: &[Ingress],
entrypoints: Vec<String>,
is_tls: bool,
user: &str,
protect: bool,
custom_prefix: Option<String>,
component_id: Option<String>,
has_wildcard: bool,
) -> IngressRoute {
let sources: Vec<&Ingress> = sources
.iter()
.filter(|source| source.component == component_id)
.collect();
let mapper = |source: &&Ingress| {
let mut middlewares = Vec::new();
if source.enable_compression {
middlewares.push(IngressRouteRoutesMiddlewares {
name: "compress-v2".to_owned(),
namespace: Some(n5i::distro::DISTRO_ID.to_string()),
})
}
if protect && !source.auth_exclude {
middlewares.push(IngressRouteRoutesMiddlewares {
name: format!("auth-{user}"),
namespace: Some(n5i::distro::DISTRO_ID.to_string()),
})
}
if let Some(custom_prefix) = custom_prefix.as_ref() {
middlewares.push(IngressRouteRoutesMiddlewares {
name: format!("strip-custom-prefix-{custom_prefix}"),
namespace: None,
})
};
if source.strip_prefix
&& source
.path_prefix
.as_ref()
.is_some_and(|prefix| prefix != "/")
{
middlewares.push(IngressRouteRoutesMiddlewares {
name: format!(
"strip-{}-prefix",
slugify!(source.path_prefix.as_ref().unwrap())
),
namespace: None,
})
}
IngressRouteRoutes {
kind: Some(IngressRouteRoutesKind::Rule),
r#match: if let Some(domain) = domain.as_ref() {
format!(
"PathPrefix(`{}`) && Host(`{}`)",
source.path_prefix.clone().unwrap_or("/".to_string()),
domain
)
} else {
format!(
"PathPrefix(`{}`)",
source.path_prefix.clone().unwrap_or("/".to_string())
)
},
middlewares: if middlewares.is_empty() {
None
} else {
Some(middlewares)
},
services: Some(
if let (Some(svc), Some(port)) =
(source.target_service.as_ref(), source.target_port)
{
vec![IngressRouteRoutesServices {
name: svc.clone(),
port: Some(IntOrString::Int(port as i32)),
namespace: source.target_ns.clone().or_else(|| {
source
.target_app
.as_ref()
.map(|app| format!("{user}-{app}"))
}),
scheme: if source.use_https {
Some("https".to_string())
} else {
None
},
servers_transport: if source.use_https && source.tls_insecure {
Some("insecure-https-transport".to_string())
} else {
None
},
..Default::default()
}]
} else {
vec![]
},
),
priority: None,
syntax: None,
observability: None,
}
};
let use_http_fallback_routes = !is_tls
&& sources
.iter()
.any(|source| source.r#type == IngressType::HttpFallback);
IngressRoute {
metadata: k8s_meta::ObjectMeta {
name: if let Some(domain) = domain.as_ref() {
Some(slugify!(domain))
} else {
Some("ingress".to_string())
},
..Default::default()
},
spec: IngressRouteSpec {
entry_points: Some(entrypoints),
parent_refs: None,
routes: sources
.iter()
.filter(|source| {
if use_http_fallback_routes {
source.r#type == IngressType::HttpFallback
} else {
source.r#type == IngressType::Https
}
})
.map(mapper)
.collect(),
tls: if is_tls && domain.is_some() && !has_wildcard {
Some(IngressRouteTls {
secret_name: Some(format!("{}-tls", slugify!(&domain.as_ref().unwrap()))),
..Default::default()
})
} else {
None
},
},
}
}
pub fn get_ingress_routes(
domain: String,
sources: &[Ingress],
user: &str,
protect: bool,
custom_prefix: Option<String>,
component_id: Option<String>,
has_wildcard: bool,
) -> [IngressRoute; 2] {
let sources: Vec<Ingress> = sources
.iter()
.filter_map(|source| {
if source.component == component_id {
Some(source.clone())
} else {
None
}
})
.collect();
let has_fallback = sources
.iter()
.any(|source| source.r#type == IngressType::HttpFallback);
let main_ingress = get_app_ingress(
Some(domain.clone()),
&sources,
vec!["websecure".to_string()],
true,
user,
protect,
custom_prefix.clone(),
component_id.clone(),
has_wildcard,
);
let http_route = if has_fallback {
let mut http_route = get_app_ingress(
Some(domain.clone()),
&sources,
vec!["web".to_string()],
false,
user,
protect,
custom_prefix,
component_id,
false,
);
http_route.metadata.name = Some(format!("{}-http", slugify!(&domain)));
http_route
} else {
let main_svc = main_ingress
.spec
.routes
.first()
.and_then(|r| r.services.as_ref())
.and_then(|s| s.first())
.map(|s| vec![s.clone()]);
IngressRoute {
metadata: k8s_meta::ObjectMeta {
name: Some(format!("{}-http", slugify!(&domain))),
..Default::default()
},
spec: IngressRouteSpec {
entry_points: Some(vec!["web".to_owned()]),
parent_refs: None,
routes: vec![IngressRouteRoutes {
kind: Some(IngressRouteRoutesKind::Rule),
r#match: format!("Host(`{domain}`)"),
priority: None,
middlewares: Some(vec![IngressRouteRoutesMiddlewares {
name: "https-redirect-v2".to_owned(),
namespace: Some(n5i::distro::DISTRO_ID.to_string()),
}]),
services: main_svc,
syntax: None,
observability: None,
}],
tls: None,
},
}
};
[main_ingress, http_route]
}