kube_client/config/
incluster_config.rs1use std::env;
2use thiserror::Error;
3
4const SERVICE_HOSTENV: &str = "KUBERNETES_SERVICE_HOST";
5const SERVICE_PORTENV: &str = "KUBERNETES_SERVICE_PORT";
6
7const SERVICE_TOKENFILE: &str = "/var/run/secrets/kubernetes.io/serviceaccount/token";
9const SERVICE_CERTFILE: &str = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt";
10const SERVICE_DEFAULT_NS: &str = "/var/run/secrets/kubernetes.io/serviceaccount/namespace";
11
12#[derive(Error, Debug)]
14pub enum Error {
15 #[error("failed to read the default namespace: {0}")]
17 ReadDefaultNamespace(#[source] std::io::Error),
18
19 #[error("failed to read an incluster environment variable: {0}")]
21 ReadEnvironmentVariable(#[source] env::VarError),
22
23 #[error("failed to read a certificate bundle: {0}")]
25 ReadCertificateBundle(#[source] std::io::Error),
26
27 #[error("failed to parse cluster port: {0}")]
29 ParseClusterPort(#[source] std::num::ParseIntError),
30
31 #[error("failed to parse cluster url: {0}")]
33 ParseClusterUrl(#[source] http::uri::InvalidUri),
34
35 #[error("failed to parse PEM-encoded certificates: {0}")]
37 ParseCertificates(#[source] pem::PemError),
38}
39
40pub(super) fn kube_dns() -> http::Uri {
43 http::Uri::from_static("https://kubernetes.default.svc/")
44}
45
46pub(super) fn try_kube_from_env() -> Result<http::Uri, Error> {
50 let host = env::var(SERVICE_HOSTENV).map_err(Error::ReadEnvironmentVariable)?;
52 let port = env::var(SERVICE_PORTENV)
53 .map_err(Error::ReadEnvironmentVariable)?
54 .parse::<u16>()
55 .map_err(Error::ParseClusterPort)?;
56
57 try_uri(&host, port)
58}
59
60fn try_uri(host: &str, port: u16) -> Result<http::Uri, Error> {
61 const HTTPS: &str = "https";
65 let uri = match host.parse::<std::net::IpAddr>() {
66 Ok(ip) => {
67 if port == 443 {
68 if ip.is_ipv6() {
69 format!("{HTTPS}://[{ip}]")
70 } else {
71 format!("{HTTPS}://{ip}")
72 }
73 } else {
74 let addr = std::net::SocketAddr::new(ip, port);
75 format!("{HTTPS}://{addr}")
76 }
77 }
78 Err(_) => {
79 if port == 443 {
80 format!("{HTTPS}://{host}")
81 } else {
82 format!("{HTTPS}://{host}:{port}")
83 }
84 }
85 };
86
87 uri.parse().map_err(Error::ParseClusterUrl)
88}
89
90pub fn token_file() -> String {
91 SERVICE_TOKENFILE.to_owned()
92}
93
94pub fn cert_file() -> &'static str {
95 SERVICE_CERTFILE
96}
97
98pub fn load_cert() -> Result<Vec<Vec<u8>>, Error> {
100 let certs = std::fs::read(SERVICE_CERTFILE).map_err(Error::ReadCertificateBundle)?;
101 super::certs(&certs).map_err(Error::ParseCertificates)
102}
103
104pub fn load_default_ns() -> Result<String, Error> {
106 std::fs::read_to_string(SERVICE_DEFAULT_NS).map_err(Error::ReadDefaultNamespace)
107}
108
109#[test]
110fn test_kube_name() {
111 assert_eq!(
112 try_uri("fake.io", 8080).unwrap().to_string(),
113 "https://fake.io:8080/"
114 );
115}
116
117#[test]
118fn test_kube_name_default_port() {
119 assert_eq!(try_uri("kubernetes.default.svc", 443).unwrap(), kube_dns())
120}
121
122#[test]
123fn test_kube_ipv4() {
124 assert_eq!(
125 try_uri("10.11.12.13", 6443).unwrap().to_string(),
126 "https://10.11.12.13:6443/"
127 );
128}
129
130#[test]
131fn test_kube_ipv4_default_port() {
132 assert_eq!(
133 try_uri("10.11.12.13", 443).unwrap().to_string(),
134 "https://10.11.12.13/"
135 );
136}
137
138#[test]
139fn test_kube_ipv6() {
140 assert_eq!(
141 try_uri("2001:0db8:85a3:0000:0000:8a2e:0370:7334", 6443)
142 .unwrap()
143 .to_string(),
144 "https://[2001:db8:85a3::8a2e:370:7334]:6443/"
145 );
146}
147
148#[test]
149fn test_kube_ipv6_default_port() {
150 assert_eq!(
151 try_uri("2001:0db8:85a3:0000:0000:8a2e:0370:7334", 443)
152 .unwrap()
153 .to_string(),
154 "https://[2001:db8:85a3::8a2e:370:7334]/"
155 );
156}