From 9548206532c50152a7fbb32659e218563f70dd98 Mon Sep 17 00:00:00 2001 From: "vy.boyko" Date: Sat, 25 Oct 2025 21:47:10 +0300 Subject: [PATCH] switching context --- README.md | 9 ++++++ k8s_tool/k8s_client.py | 62 +++++++++++++++++++++++++++++++++++++++++- k8s_tool/main.py | 46 +++++++++++++++++++++++++++++-- 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e6fd2ad..6fe9c04 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ## Особенности - 🎯 Интерактивное меню с навигацией стрелками +- 🔄 Переключение между Kubernetes контекстами/кластерами - ⭐ Избранные namespaces для быстрого доступа - 🎨 Красивый вывод с использованием Rich - 📦 Управление namespaces, deployments, pods, ConfigMaps @@ -57,6 +58,14 @@ poetry run k8s-tool ### Основные функции +#### Переключение контекста Kubernetes +Быстрое переключение между различными Kubernetes кластерами/контекстами: +- Просмотр всех доступных контекстов в виде таблицы +- Отображение текущего активного контекста (✓) +- Переключение на другой контекст +- Автоматическая переинициализация подключения к новому кластеру +- После переключения контекста namespace сбрасывается и нужно выбрать заново + #### Выбор Namespace Выберите namespace для работы. Все последующие операции будут выполняться в выбранном namespace. diff --git a/k8s_tool/k8s_client.py b/k8s_tool/k8s_client.py index 0823859..b109ee3 100644 --- a/k8s_tool/k8s_client.py +++ b/k8s_tool/k8s_client.py @@ -19,11 +19,52 @@ class K8sClient: config.load_kube_config() self.v1 = client.CoreV1Api() self.apps_v1 = client.AppsV1Api() - console.print("[green]✓[/green] Connected to Kubernetes cluster") + self.current_context = self.get_current_context() + console.print(f"[green]✓[/green] Connected to Kubernetes cluster") + if self.current_context: + console.print(f"[dim]Current context: {self.current_context}[/dim]") except Exception as e: console.print(f"[red]✗[/red] Failed to connect to Kubernetes: {e}") raise + def get_contexts(self) -> List[Dict[str, str]]: + """Get list of available contexts.""" + try: + contexts, active_context = config.list_kube_config_contexts() + return [{ + 'name': ctx['name'], + 'cluster': ctx['context'].get('cluster', ''), + 'user': ctx['context'].get('user', ''), + 'is_active': ctx['name'] == active_context['name'] + } for ctx in contexts] + except Exception as e: + console.print(f"[red]Error fetching contexts:[/red] {e}") + return [] + + def get_current_context(self) -> Optional[str]: + """Get current context name.""" + try: + contexts, active_context = config.list_kube_config_contexts() + return active_context['name'] if active_context else None + except Exception as e: + console.print(f"[red]Error getting current context:[/red] {e}") + return None + + def switch_context(self, context_name: str) -> bool: + """Switch to a different context.""" + try: + # Load the new context + config.load_kube_config(context=context_name) + # Reinitialize API clients + self.v1 = client.CoreV1Api() + self.apps_v1 = client.AppsV1Api() + self.current_context = context_name + console.print(f"[green]✓[/green] Switched to context: [cyan]{context_name}[/cyan]") + return True + except Exception as e: + console.print(f"[red]Error switching context:[/red] {e}") + return False + def get_namespaces(self) -> List[str]: """Get list of all namespaces.""" try: @@ -232,3 +273,22 @@ class K8sClient: ) console.print(table) + + def display_contexts_table(self, contexts: List[Dict[str, str]]): + """Display contexts in a table.""" + table = Table(title="Kubernetes Contexts") + table.add_column("Name", style="cyan") + table.add_column("Cluster", style="magenta") + table.add_column("User", style="yellow") + table.add_column("Active", style="green") + + for ctx in contexts: + active_mark = "✓" if ctx['is_active'] else "" + table.add_row( + ctx['name'], + ctx['cluster'], + ctx['user'], + active_mark + ) + + console.print(table) diff --git a/k8s_tool/main.py b/k8s_tool/main.py index 17730f8..0ee5a72 100644 --- a/k8s_tool/main.py +++ b/k8s_tool/main.py @@ -63,12 +63,18 @@ class K8sTool: def _main_menu(self): """Display main menu.""" + # Display current context + current_context = self.k8s_client.current_context or "[dim]unknown[/dim]" + console.print(f"[bold]Current context:[/bold] [cyan]{current_context}[/cyan]") + + # Display current namespace namespace_info = f"[cyan]{self.current_namespace}[/cyan]" if self.current_namespace else "[dim]not selected[/dim]" is_favorite = self.config.is_favorite(self.current_namespace) if self.current_namespace else False fav_indicator = " ⭐" if is_favorite else "" - console.print(f"\n[bold]Current namespace:[/bold] {namespace_info}{fav_indicator}") + console.print(f"[bold]Current namespace:[/bold] {namespace_info}{fav_indicator}") choices = [ + "Switch Context", "Select Namespace", "Manage Favorites", "List Deployments", @@ -86,7 +92,9 @@ class K8sTool: style=custom_style ).ask() - if action == "Select Namespace": + if action == "Switch Context": + self._switch_context() + elif action == "Select Namespace": self._select_namespace() elif action == "Manage Favorites": self._manage_favorites() @@ -144,6 +152,40 @@ class K8sTool: fav_text = " (favorite)" if is_fav else "" console.print(f"[green]✓[/green] Namespace set to: [cyan]{namespace}[/cyan]{fav_text}") + def _switch_context(self): + """Switch Kubernetes context.""" + console.print("[dim]Fetching contexts...[/dim]") + contexts = self.k8s_client.get_contexts() + + if not contexts: + console.print("[red]No contexts found[/red]") + return + + # Show contexts table + self.k8s_client.display_contexts_table(contexts) + + # Filter out current context for selection + available_contexts = [ctx['name'] for ctx in contexts if not ctx['is_active']] + + if not available_contexts: + console.print("[yellow]Only one context available[/yellow]") + return + + # Add option to view current + choices = available_contexts + [questionary.Separator(), "Cancel"] + + selected = questionary.select( + "Select context to switch to:", + choices=choices, + style=custom_style + ).ask() + + if selected and selected != "Cancel": + if self.k8s_client.switch_context(selected): + # Reset namespace selection after context switch + self.current_namespace = None + console.print("[yellow]Note:[/yellow] Namespace selection reset. Please select a namespace.") + def _manage_favorites(self): """Manage favorite namespaces.""" choices = []