From 8d55cab91fb651c0b0758853c419fb526faf7f32 Mon Sep 17 00:00:00 2001 From: Vignesh Rajasekaran Date: Tue, 17 May 2022 03:16:47 +0800 Subject: [PATCH] feat: clone ctx Signed-off-by: Vignesh Rajasekaran --- src/cmd/context.rs | 78 +++++++++++++++++++++++++++++++++++----------- src/cmd/meta.rs | 4 +++ src/main.rs | 3 +- src/session.rs | 6 +++- 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/cmd/context.rs b/src/cmd/context.rs index 5b557ff5..33965761 100644 --- a/src/cmd/context.rs +++ b/src/cmd/context.rs @@ -11,21 +11,67 @@ use crate::shell::spawn_shell; use crate::state::State; use crate::vars; -fn enter_context( +fn enter_cloned_context( settings: &Settings, installed: Installed, - context_name: &str, namespace_name: Option<&str>, recursive: bool, ) -> Result<()> { + let session = Session::load()?; + + let previous_ctx = session + .get_last_context() + .context("There is no previous context to switch to.")?; + let namespace_name = namespace_name.or(previous_ctx.namespace.as_deref()); + let kubeconfig = installed.make_kubeconfig_for_context(&previous_ctx.context, namespace_name)?; + + if settings.behavior.validate_namespaces { + if let Some(namespace_name) = namespace_name { + let namespaces = kubectl::get_namespaces(Some(&kubeconfig))?; + if !namespaces.iter().any(|x| x == namespace_name) { + eprintln!("Warning: namespace {} does not exist.", namespace_name); + } + } + } + + if vars::is_kubie_active() && !recursive { + let path = kubeconfig::get_kubeconfig_path()?; + let file = File::create(&path).context("could not write in temporary KUBECONFIG file")?; + kubeconfig.write_to(file)?; + session.save(None)?; + } else { + spawn_shell(settings, kubeconfig, &session)?; + } + + Ok(()) +} + +fn enter_context( + settings: &Settings, + mut installed: Installed, + context_name: Option, + mut namespace_name: Option<&str>, + recursive: bool, +) -> Result<()> { + let context_name = match context_name { + Some(context_name) => context_name, + None => match select_or_list_context(&mut installed)? { + SelectResult::Selected(x) => { + namespace_name = None; + x + } + _ => return Ok(()), + }, + }; + let state = State::load()?; let mut session = Session::load()?; - let namespace_name = namespace_name.or(state.namespace_history.get(context_name).and_then(|s| s.as_deref())); + let namespace_name = namespace_name.or(state.namespace_history.get(&context_name).and_then(|s| s.as_deref())); - let kubeconfig = if context_name == "-" { + let kubeconfig = if &context_name == "-" { let previous_ctx = session - .get_last_context() + .get_previous_context() .context("There is no previous context to switch to.")?; installed.make_kubeconfig_for_context(&previous_ctx.context, previous_ctx.namespace.as_deref())? } else { @@ -61,26 +107,20 @@ fn enter_context( pub fn context( settings: &Settings, context_name: Option, - mut namespace_name: Option, + namespace_name: Option, kubeconfigs: Vec, + clone: bool, recursive: bool, ) -> Result<()> { - let mut installed = if kubeconfigs.is_empty() { + let installed = if kubeconfigs.is_empty() { kubeconfig::get_installed_contexts(settings)? } else { kubeconfig::get_kubeconfigs_contexts(&kubeconfigs)? }; - let context_name = match context_name { - Some(context_name) => context_name, - None => match select_or_list_context(&mut installed)? { - SelectResult::Selected(x) => { - namespace_name = None; - x - } - _ => return Ok(()), - }, - }; - - enter_context(settings, installed, &context_name, namespace_name.as_deref(), recursive) + if clone { + enter_cloned_context(settings, installed, namespace_name.as_deref(), recursive) + } else { + enter_context(settings, installed, context_name, namespace_name.as_deref(), recursive) + } } diff --git a/src/cmd/meta.rs b/src/cmd/meta.rs index 08f4241e..194635b3 100644 --- a/src/cmd/meta.rs +++ b/src/cmd/meta.rs @@ -22,6 +22,10 @@ pub enum Kubie { #[structopt(short = "r", long = "recursive")] recursive: bool, + /// Spawn a new shell by cloning current shell context + #[structopt(short = "c", long = "clone")] + clone: bool, + /// Name of the context to enter. Use '-' to switch back to the previous context. context_name: Option, }, diff --git a/src/main.rs b/src/main.rs index c7a17509..44ba695c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,9 +24,10 @@ fn main() -> Result<()> { namespace_name, context_name, kubeconfigs, + clone, recursive, } => { - cmd::context::context(&settings, context_name, namespace_name, kubeconfigs, recursive)?; + cmd::context::context(&settings, context_name, namespace_name, kubeconfigs, clone, recursive)?; } Kubie::Namespace { namespace_name, diff --git a/src/session.rs b/src/session.rs index 620e6d98..987f2105 100644 --- a/src/session.rs +++ b/src/session.rs @@ -51,7 +51,7 @@ impl Session { }) } - pub fn get_last_context(&self) -> Option<&HistoryEntry> { + pub fn get_previous_context(&self) -> Option<&HistoryEntry> { let current_context = self.history.last()?; for entry in self.history.iter().rev().skip(1) { if current_context.context != entry.context { @@ -61,6 +61,10 @@ impl Session { None } + pub fn get_last_context(&self) -> Option<&HistoryEntry> { + return self.history.last() + } + pub fn get_last_namespace(&self) -> Option<&str> { let current_context = self.history.last()?; for entry in self.history.iter().rev().skip(1) {