kube_client/config/
file_loader.rs1#[cfg(any(feature = "http-proxy", feature = "socks5"))]
2use crate::config::no_proxy::NoProxy;
3
4use crate::{
5 config::{
6 KubeconfigError,
7 file_config::{AuthInfo, Cluster, Context, Kubeconfig},
8 },
9 util::nonempty,
10};
11
12#[derive(Default, Clone)]
14pub struct KubeConfigOptions {
15 pub context: Option<String>,
17 pub cluster: Option<String>,
19 pub user: Option<String>,
21}
22
23#[derive(Clone, Debug)]
26pub struct ConfigLoader {
27 pub current_context: Context,
28 pub cluster: Cluster,
29 pub user: AuthInfo,
30}
31
32impl ConfigLoader {
33 pub async fn new_from_options(options: &KubeConfigOptions) -> Result<Self, KubeconfigError> {
35 let config = Kubeconfig::read()?;
36 let loader = Self::load(
37 config,
38 options.context.as_ref(),
39 options.cluster.as_ref(),
40 options.user.as_ref(),
41 )
42 .await?;
43
44 Ok(loader)
45 }
46
47 pub async fn new_from_kubeconfig(
48 config: Kubeconfig,
49 options: &KubeConfigOptions,
50 ) -> Result<Self, KubeconfigError> {
51 let loader = Self::load(
52 config,
53 options.context.as_ref(),
54 options.cluster.as_ref(),
55 options.user.as_ref(),
56 )
57 .await?;
58
59 Ok(loader)
60 }
61
62 fn load_from_kubeconfig(
63 config: Kubeconfig,
64 context: Option<&String>,
65 cluster: Option<&String>,
66 user: Option<&String>,
67 ) -> Result<Self, KubeconfigError> {
68 let context_name = if let Some(name) = context {
69 name
70 } else if let Some(name) = &config.current_context {
71 name
72 } else {
73 return Err(KubeconfigError::CurrentContextNotSet);
74 };
75
76 let current_context = config
77 .contexts
78 .iter()
79 .find(|named_context| &named_context.name == context_name)
80 .and_then(|named_context| named_context.context.clone())
81 .ok_or_else(|| KubeconfigError::LoadContext(context_name.clone()))?;
82
83 let cluster_name = cluster.unwrap_or(¤t_context.cluster);
84 let cluster = config
85 .clusters
86 .iter()
87 .find(|named_cluster| &named_cluster.name == cluster_name)
88 .and_then(|named_cluster| named_cluster.cluster.clone())
89 .ok_or_else(|| KubeconfigError::LoadClusterOfContext(cluster_name.clone()))?;
90
91 let user_name = user.or_else(|| current_context.user.as_ref());
92
93 let mut auth_info = if let Some(user) = user_name {
96 config
97 .auth_infos
98 .iter()
99 .find(|named_user| &named_user.name == user)
100 .and_then(|named_user| named_user.auth_info.clone())
101 .unwrap_or_else(AuthInfo::default)
102 } else {
103 AuthInfo::default()
104 };
105
106 if let Some(exec_config) = &mut auth_info.exec
107 && exec_config.provide_cluster_info
108 {
109 exec_config.cluster = Some((&cluster).try_into()?);
110 }
111
112 Ok(ConfigLoader {
113 current_context,
114 cluster,
115 user: auth_info,
116 })
117 }
118
119 pub async fn load(
120 config: Kubeconfig,
121 context: Option<&String>,
122 cluster: Option<&String>,
123 user: Option<&String>,
124 ) -> Result<Self, KubeconfigError> {
125 Self::load_from_kubeconfig(config, context, cluster, user)
126 }
127
128 pub fn ca_bundle(&self) -> Result<Option<Vec<Vec<u8>>>, KubeconfigError> {
129 if let Some(bundle) = self.cluster.load_certificate_authority()? {
130 Ok(Some(
131 super::certs(&bundle).map_err(KubeconfigError::ParseCertificates)?,
132 ))
133 } else {
134 Ok(None)
135 }
136 }
137
138 pub fn proxy_url(&self) -> Result<Option<http::Uri>, KubeconfigError> {
139 if let Some(proxy) = nonempty(self.cluster.proxy_url.clone())
140 .or_else(|| nonempty(std::env::var("HTTPS_PROXY").ok()))
141 .or_else(|| nonempty(std::env::var("https_proxy").ok()))
142 {
143 let uri = proxy
144 .parse::<http::Uri>()
145 .map_err(KubeconfigError::ParseProxyUrl)?;
146
147 #[cfg(any(feature = "http-proxy", feature = "socks5"))]
148 {
149 let no_proxy = NoProxy::from_env().map_err(KubeconfigError::ParseNoProxy)?;
150
151 match no_proxy {
152 Some(no_proxy) if no_proxy.matches(&uri).map_err(KubeconfigError::ParseNoProxy)? => {
153 Ok(None)
154 }
155 _ => Ok(Some(uri)),
156 }
157 }
158
159 #[cfg(not(any(feature = "http-proxy", feature = "socks5")))]
160 Ok(Some(uri))
161 } else {
162 Ok(None)
163 }
164 }
165}
166
167impl TryFrom<Kubeconfig> for ConfigLoader {
168 type Error = KubeconfigError;
169
170 fn try_from(kubeconfig: Kubeconfig) -> Result<Self, KubeconfigError> {
171 Self::load_from_kubeconfig(kubeconfig, None, None, None)
172 }
173}