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 load_cert() -> Result<Vec<Vec<u8>>, Error> {
96 let certs = std::fs::read(SERVICE_CERTFILE).map_err(Error::ReadCertificateBundle)?;
97 super::certs(&certs).map_err(Error::ParseCertificates)
98}
99
100pub fn load_default_ns() -> Result<String, Error> {
102 std::fs::read_to_string(SERVICE_DEFAULT_NS).map_err(Error::ReadDefaultNamespace)
103}
104
105#[test]
106fn test_kube_name() {
107 assert_eq!(
108 try_uri("fake.io", 8080).unwrap().to_string(),
109 "https://fake.io:8080/"
110 );
111}
112
113#[test]
114fn test_kube_name_default_port() {
115 assert_eq!(try_uri("kubernetes.default.svc", 443).unwrap(), kube_dns())
116}
117
118#[test]
119fn test_kube_ipv4() {
120 assert_eq!(
121 try_uri("10.11.12.13", 6443).unwrap().to_string(),
122 "https://10.11.12.13:6443/"
123 );
124}
125
126#[test]
127fn test_kube_ipv4_default_port() {
128 assert_eq!(
129 try_uri("10.11.12.13", 443).unwrap().to_string(),
130 "https://10.11.12.13/"
131 );
132}
133
134#[test]
135fn test_kube_ipv6() {
136 assert_eq!(
137 try_uri("2001:0db8:85a3:0000:0000:8a2e:0370:7334", 6443)
138 .unwrap()
139 .to_string(),
140 "https://[2001:db8:85a3::8a2e:370:7334]:6443/"
141 );
142}
143
144#[test]
145fn test_kube_ipv6_default_port() {
146 assert_eq!(
147 try_uri("2001:0db8:85a3:0000:0000:8a2e:0370:7334", 443)
148 .unwrap()
149 .to_string(),
150 "https://[2001:db8:85a3::8a2e:370:7334]/"
151 );
152}