From 451429c5c4e0c1b1c77dbc84fa105f6b55f5edbc Mon Sep 17 00:00:00 2001 From: clux Date: Sat, 27 Feb 2021 21:25:21 +0000 Subject: [PATCH] support multi-doc kubeconfigs - fixes #440 --- examples/Cargo.toml | 2 +- kube-derive/Cargo.toml | 2 +- kube/Cargo.toml | 2 +- kube/src/config/file_config.rs | 58 +++++++++++++++++++++------------- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f8590df62..332a4c5f7 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -28,7 +28,7 @@ k8s-openapi = { version = "0.11.0", features = ["v1_20"], default-features = fal log = "0.4.11" serde = { version = "1.0.118", features = ["derive"] } serde_json = "1.0.61" -serde_yaml = "0.8.14" +serde_yaml = "0.8.17" tokio = { version = "1.0.1", features = ["full"] } color-eyre = "0.5.10" snafu = { version = "0.6.10", features = ["futures"] } diff --git a/kube-derive/Cargo.toml b/kube-derive/Cargo.toml index 690751fb6..683dfd7f5 100644 --- a/kube-derive/Cargo.toml +++ b/kube-derive/Cargo.toml @@ -28,7 +28,7 @@ schema = [] [dev-dependencies] serde = { version = "1.0.118", features = ["derive"] } -serde_yaml = "0.8.14" +serde_yaml = "0.8.17" k8s-openapi = { version = "0.11.0", default-features = false, features = ["v1_20"] } schemars = { version = "0.8.0", features = ["chrono"] } chrono = "0.4.19" diff --git a/kube/Cargo.toml b/kube/Cargo.toml index 47744ee6b..91bf80d9b 100644 --- a/kube/Cargo.toml +++ b/kube/Cargo.toml @@ -36,7 +36,7 @@ chrono = "0.4.19" dirs = { package = "dirs-next", version = "2.0.0" } serde = { version = "1.0.118", features = ["derive"] } serde_json = "1.0.61" -serde_yaml = "0.8.14" +serde_yaml = "0.8.17" http = "0.2.2" url = "2.2.0" log = "0.4.11" diff --git a/kube/src/config/file_config.rs b/kube/src/config/file_config.rs index f485c94ed..32943f709 100644 --- a/kube/src/config/file_config.rs +++ b/kube/src/config/file_config.rs @@ -1,6 +1,6 @@ #![allow(missing_docs)] -use std::{collections::HashMap, fs::File, path::Path}; +use std::{collections::HashMap, fs, path::Path}; use crate::{config::utils, error::ConfigError, Result}; @@ -139,40 +139,54 @@ const KUBECONFIG: &str = "KUBECONFIG"; impl Kubeconfig { /// Read a Config from an arbitrary location pub fn read_from>(path: P) -> Result { - let f = File::open(&path).map_err(|source| ConfigError::ReadFile { + let data = fs::read_to_string(&path).map_err(|source| ConfigError::ReadFile { path: path.as_ref().into(), source, })?; - let mut config: Kubeconfig = serde_yaml::from_reader(f).map_err(ConfigError::ParseYaml)?; + // support multiple documents + let mut documents: Vec = vec![]; + for doc in serde_yaml::Deserializer::from_str(&data) { + let value = serde_yaml::Value::deserialize(doc).map_err(ConfigError::ParseYaml)?; + let kconf = serde_yaml::from_value(value).map_err(ConfigError::ParseYaml)?; + documents.push(kconf) + } // Remap all files we read to absolute paths. - if let Some(dir) = path.as_ref().parent() { - for named in config.clusters.iter_mut() { - if let Some(path) = &named.cluster.certificate_authority { - if let Some(abs_path) = to_absolute(dir, path) { - named.cluster.certificate_authority = Some(abs_path); + let mut merged_docs = None; + for mut config in documents { + if let Some(dir) = path.as_ref().parent() { + for named in config.clusters.iter_mut() { + if let Some(path) = &named.cluster.certificate_authority { + if let Some(abs_path) = to_absolute(dir, path) { + named.cluster.certificate_authority = Some(abs_path); + } } } - } - for named in config.auth_infos.iter_mut() { - if let Some(path) = &named.auth_info.client_certificate { - if let Some(abs_path) = to_absolute(dir, path) { - named.auth_info.client_certificate = Some(abs_path); + for named in config.auth_infos.iter_mut() { + if let Some(path) = &named.auth_info.client_certificate { + if let Some(abs_path) = to_absolute(dir, path) { + named.auth_info.client_certificate = Some(abs_path); + } } - } - if let Some(path) = &named.auth_info.client_key { - if let Some(abs_path) = to_absolute(dir, path) { - named.auth_info.client_key = Some(abs_path); + if let Some(path) = &named.auth_info.client_key { + if let Some(abs_path) = to_absolute(dir, path) { + named.auth_info.client_key = Some(abs_path); + } } - } - if let Some(path) = &named.auth_info.token_file { - if let Some(abs_path) = to_absolute(dir, path) { - named.auth_info.token_file = Some(abs_path); + if let Some(path) = &named.auth_info.token_file { + if let Some(abs_path) = to_absolute(dir, path) { + named.auth_info.token_file = Some(abs_path); + } } } } + if let Some(c) = merged_docs { + merged_docs = Some(Kubeconfig::merge(c, config)?); + } else { + merged_docs = Some(config); + } } - Ok(config) + Ok(merged_docs.expect("Need at least one yaml document in KUBECONFIG file")) } /// Read a Config from `KUBECONFIG` or the the default location.