Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/stack/deploy/deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
)
from stack.deploy.deploy_types import DeployCommandContext
from stack.deploy.deployment_context import DeploymentContext
from stack.deploy.explain import explain_op
from stack.deploy.stack import Stack
from stack.log import output_main
from stack.util import error_exit
Expand Down Expand Up @@ -79,6 +80,14 @@ def make_deploy_context(ctx) -> DeployCommandContext:
)


@command.command()
@click.pass_context
def explain(ctx):
"""Explain the deployment (experimental)"""
ctx.obj = make_deploy_context(ctx)
explain_op(ctx)


@command.command()
@click.option(
"--stay-attached/--detatch-terminal",
Expand All @@ -93,7 +102,7 @@ def make_deploy_context(ctx) -> DeployCommandContext:
@click.argument("extra_args", nargs=-1) # help: command: start <service1> <service2>
@click.pass_context
def start(ctx, stay_attached, skip_cluster_management, extra_args):
"""start the stack"""
"""start the deployment"""
ctx.obj = make_deploy_context(ctx)
services_list = list(extra_args) or None
up_operation(ctx, services_list, stay_attached, skip_cluster_management)
Expand All @@ -109,7 +118,7 @@ def start(ctx, stay_attached, skip_cluster_management, extra_args):
@click.argument("extra_args", nargs=-1) # help: command: down <service1> <service2>
@click.pass_context
def stop(ctx, delete_volumes, skip_cluster_management, extra_args):
"""stop the stack and remove the containers"""
"""stop the deployment and remove the containers"""
# TODO: add cluster name and env file here
ctx.obj = make_deploy_context(ctx)
down_operation(ctx, delete_volumes, extra_args, skip_cluster_management)
Expand Down
67 changes: 67 additions & 0 deletions src/stack/deploy/explain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright © 2026 Bozeman Pass, Inc.

# 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 yaml

from kubernetes import client

from stack.deploy.k8s.deploy_k8s import K8sDeployer
from stack.log import output_main
from stack.util import error_exit


def _k8s_object_to_yaml(obj):
api_client = client.ApiClient()
sanitized = api_client.sanitize_for_serialization(obj)
return yaml.dump(sanitized, default_flow_style=False, sort_keys=False)


def _print_section(title, objects):
if not objects:
return
output_main(f"--- {title} ---")
for obj in objects:
output_main(_k8s_object_to_yaml(obj))


def explain_op(ctx):
deployer = ctx.obj.deployer

if not isinstance(deployer, K8sDeployer):
error_exit("The explain command is currently only supported for k8s deployments")

cluster_info = deployer.cluster_info
is_kind = deployer.is_kind()

pvs = cluster_info.get_pvs()
_print_section("PersistentVolumes", pvs)

pvcs = cluster_info.get_pvcs()
_print_section("PersistentVolumeClaims", pvcs)

config_maps = cluster_info.get_configmaps()
_print_section("ConfigMaps", config_maps)

deployments = cluster_info.get_deployments(image_pull_policy=None if is_kind else "Always")
_print_section("Deployments", deployments)

services = cluster_info.get_services()
_print_section("Services", services)

http_proxy_info = cluster_info.spec.get_http_proxy()
use_tls = http_proxy_info and not is_kind
ingress = cluster_info.get_ingress(use_tls=use_tls)
if ingress:
_print_section("Ingress", [ingress])
Loading