Add kind cluster reuse and list command
- Add get_kind_cluster() to detect existing kind clusters - Modify create_cluster() to reuse existing clusters automatically - Add 'laconic-so deploy k8s list cluster' command - Skip --stack requirement for k8s subcommand This allows multiple deployments to share the same kind cluster, simplifying local development workflows. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>afd-caddy-ingress
parent
3606b5dd90
commit
8426d99ed9
|
|
@ -42,6 +42,7 @@ from stack_orchestrator.deploy.deployment_context import DeploymentContext
|
|||
from stack_orchestrator.deploy.deployment_create import create as deployment_create
|
||||
from stack_orchestrator.deploy.deployment_create import init as deployment_init
|
||||
from stack_orchestrator.deploy.deployment_create import setup as deployment_setup
|
||||
from stack_orchestrator.deploy.k8s import k8s_command
|
||||
|
||||
|
||||
@click.group()
|
||||
|
|
@ -54,6 +55,10 @@ from stack_orchestrator.deploy.deployment_create import setup as deployment_setu
|
|||
def command(ctx, include, exclude, env_file, cluster, deploy_to):
|
||||
'''deploy a stack'''
|
||||
|
||||
# k8s subcommand doesn't require stack
|
||||
if ctx.invoked_subcommand == "k8s":
|
||||
return
|
||||
|
||||
# Although in theory for some subcommands (e.g. deploy create) the stack can be inferred,
|
||||
# Click doesn't allow us to know that here, so we make providing the stack mandatory
|
||||
stack = global_options2(ctx).stack
|
||||
|
|
@ -460,3 +465,4 @@ def _orchestrate_cluster_config(ctx, cluster_config, deployer, container_exec_en
|
|||
command.add_command(deployment_init)
|
||||
command.add_command(deployment_create)
|
||||
command.add_command(deployment_setup)
|
||||
command.add_command(k8s_command.command, "k8s")
|
||||
|
|
|
|||
|
|
@ -210,8 +210,12 @@ class K8sDeployer(Deployer):
|
|||
self.skip_cluster_management = skip_cluster_management
|
||||
if not opts.o.dry_run:
|
||||
if self.is_kind() and not self.skip_cluster_management:
|
||||
# Create the kind cluster
|
||||
create_cluster(self.kind_cluster_name, self.deployment_dir.joinpath(constants.kind_config_filename))
|
||||
# Create the kind cluster (or reuse existing one)
|
||||
kind_config = self.deployment_dir.joinpath(constants.kind_config_filename)
|
||||
actual_cluster = create_cluster(self.kind_cluster_name, kind_config)
|
||||
if actual_cluster != self.kind_cluster_name:
|
||||
# An existing cluster was found, use it instead
|
||||
self.kind_cluster_name = actual_cluster
|
||||
# Ensure the referenced containers are copied into kind
|
||||
load_images_into_kind(self.kind_cluster_name, self.cluster_info.image_set)
|
||||
self.connect_api()
|
||||
|
|
|
|||
|
|
@ -35,10 +35,51 @@ def _run_command(command: str):
|
|||
return result
|
||||
|
||||
|
||||
def get_kind_cluster():
|
||||
"""Get an existing kind cluster, if any.
|
||||
|
||||
Uses `kind get clusters` to find existing clusters.
|
||||
Returns the cluster name or None if no cluster exists.
|
||||
"""
|
||||
result = subprocess.run(
|
||||
"kind get clusters",
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
|
||||
clusters = result.stdout.strip().splitlines()
|
||||
if clusters:
|
||||
return clusters[0] # Return the first cluster found
|
||||
return None
|
||||
|
||||
|
||||
def create_cluster(name: str, config_file: str):
|
||||
"""Create a kind cluster, or reuse an existing one.
|
||||
|
||||
Checks if any kind cluster already exists. If so, uses that cluster
|
||||
instead of creating a new one. This allows multiple deployments to
|
||||
share the same kind cluster.
|
||||
|
||||
Args:
|
||||
name: The desired cluster name (used only if creating new)
|
||||
config_file: Path to kind config file (used only if creating new)
|
||||
|
||||
Returns:
|
||||
The name of the cluster being used (either existing or newly created)
|
||||
"""
|
||||
existing = get_kind_cluster()
|
||||
if existing:
|
||||
print(f"Using existing cluster: {existing}")
|
||||
return existing
|
||||
|
||||
print(f"Creating new cluster: {name}")
|
||||
result = _run_command(f"kind create cluster --name {name} --config {config_file}")
|
||||
if result.returncode != 0:
|
||||
raise DeployerException(f"kind create cluster failed: {result}")
|
||||
return name
|
||||
|
||||
|
||||
def destroy_cluster(name: str):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
# Copyright © 2024 Vulcanize
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
|
||||
|
||||
import click
|
||||
|
||||
from stack_orchestrator.deploy.k8s.helpers import get_kind_cluster
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.pass_context
|
||||
def command(ctx):
|
||||
'''k8s cluster management commands'''
|
||||
pass
|
||||
|
||||
|
||||
@command.group()
|
||||
@click.pass_context
|
||||
def list(ctx):
|
||||
'''list k8s resources'''
|
||||
pass
|
||||
|
||||
|
||||
@list.command()
|
||||
@click.pass_context
|
||||
def cluster(ctx):
|
||||
'''Show the existing kind cluster'''
|
||||
existing_cluster = get_kind_cluster()
|
||||
if existing_cluster:
|
||||
print(existing_cluster)
|
||||
else:
|
||||
print("No cluster found")
|
||||
Loading…
Reference in New Issue