pub mod builder;
pub mod config;
pub mod connection;
pub mod error;
pub mod proxy;
pub mod utils;
pub use builder::{
create_client_with_specific_context,
warm_up_path_env,
};
pub use config::{
ConfigExtClone,
create_config_with_context,
get_kubeconfig_paths_from_option,
merge_kubeconfigs,
};
pub use connection::create_client_with_config;
pub use error::{
KubeClientError,
KubeResult,
};
#[derive(Clone)]
pub struct KubeConnection {
pub client: kube::Client,
pub cluster_url: http::Uri,
}
impl std::fmt::Debug for KubeConnection {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("KubeConnection")
.field("cluster_url", &self.cluster_url)
.finish_non_exhaustive()
}
}
pub fn cluster_identity(url: &http::Uri) -> String {
let scheme = url.scheme_str().unwrap_or("").to_ascii_lowercase();
let host = url.host().unwrap_or("").to_ascii_lowercase();
let default_port = match scheme.as_str() {
"https" => Some(443),
"http" => Some(80),
_ => None,
};
let port = url.port_u16().filter(|port| Some(*port) != default_port);
let path = url.path().trim_end_matches('/');
let mut identity = String::new();
if !scheme.is_empty() {
identity.push_str(&scheme);
identity.push_str("://");
}
if host.contains(':') && !host.starts_with('[') {
identity.push('[');
identity.push_str(&host);
identity.push(']');
} else {
identity.push_str(&host);
}
if let Some(port) = port {
identity.push(':');
identity.push_str(&port.to_string());
}
identity.push_str(path);
if let Some(query) = url.query() {
identity.push('?');
identity.push_str(query);
}
identity
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cluster_identity_drops_default_port_and_trailing_slash() {
let with_port: http::Uri = "https://host:443/".parse().unwrap();
let without_port: http::Uri = "https://host".parse().unwrap();
assert_eq!(
cluster_identity(&with_port),
cluster_identity(&without_port)
);
assert_eq!(cluster_identity(&with_port), "https://host");
}
#[test]
fn cluster_identity_lowercases_scheme_and_host() {
let mixed_case: http::Uri = "HTTPS://Host.Example.COM:6443/".parse().unwrap();
assert_eq!(
cluster_identity(&mixed_case),
"https://host.example.com:6443"
);
}
#[test]
fn cluster_identity_keeps_non_default_port_and_path() {
let url: http::Uri = "http://host:9443/api".parse().unwrap();
assert_eq!(cluster_identity(&url), "http://host:9443/api");
}
#[test]
fn cluster_identity_drops_trailing_slash_on_a_path_prefixed_url() {
let with_slash: http::Uri = "https://host/k8s/clusters/c-x/".parse().unwrap();
let without_slash: http::Uri = "https://host/k8s/clusters/c-x".parse().unwrap();
assert_eq!(
cluster_identity(&with_slash),
cluster_identity(&without_slash),
"a trailing slash on a path-prefixed API server URL must not change its identity"
);
assert_eq!(
cluster_identity(&with_slash),
"https://host/k8s/clusters/c-x"
);
}
#[test]
fn cluster_identity_brackets_ipv6_host() {
let url: http::Uri = "https://[2001:db8::1]:6443".parse().unwrap();
assert_eq!(cluster_identity(&url), "https://[2001:db8::1]:6443");
}
}