Skip to content

Commit edde112

Browse files
authored
Merge pull request #139 from bozemanpass/dboreham/explain-subcommand
Add experimental stack manage explain command
2 parents 70bf5ef + 6f4a11c commit edde112

2 files changed

Lines changed: 78 additions & 2 deletions

File tree

src/stack/deploy/deployment.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
)
3636
from stack.deploy.deploy_types import DeployCommandContext
3737
from stack.deploy.deployment_context import DeploymentContext
38+
from stack.deploy.explain import explain_op
3839
from stack.deploy.stack import Stack
3940
from stack.log import output_main
4041
from stack.util import error_exit
@@ -79,6 +80,14 @@ def make_deploy_context(ctx) -> DeployCommandContext:
7980
)
8081

8182

83+
@command.command()
84+
@click.pass_context
85+
def explain(ctx):
86+
"""Explain the deployment (experimental)"""
87+
ctx.obj = make_deploy_context(ctx)
88+
explain_op(ctx)
89+
90+
8291
@command.command()
8392
@click.option(
8493
"--stay-attached/--detatch-terminal",
@@ -93,7 +102,7 @@ def make_deploy_context(ctx) -> DeployCommandContext:
93102
@click.argument("extra_args", nargs=-1) # help: command: start <service1> <service2>
94103
@click.pass_context
95104
def start(ctx, stay_attached, skip_cluster_management, extra_args):
96-
"""start the stack"""
105+
"""start the deployment"""
97106
ctx.obj = make_deploy_context(ctx)
98107
services_list = list(extra_args) or None
99108
up_operation(ctx, services_list, stay_attached, skip_cluster_management)
@@ -109,7 +118,7 @@ def start(ctx, stay_attached, skip_cluster_management, extra_args):
109118
@click.argument("extra_args", nargs=-1) # help: command: down <service1> <service2>
110119
@click.pass_context
111120
def stop(ctx, delete_volumes, skip_cluster_management, extra_args):
112-
"""stop the stack and remove the containers"""
121+
"""stop the deployment and remove the containers"""
113122
# TODO: add cluster name and env file here
114123
ctx.obj = make_deploy_context(ctx)
115124
down_operation(ctx, delete_volumes, extra_args, skip_cluster_management)

src/stack/deploy/explain.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright © 2026 Bozeman Pass, Inc.
2+
3+
# This program is free software: you can redistribute it and/or modify
4+
# it under the terms of the GNU Affero General Public License as published by
5+
# the Free Software Foundation, either version 3 of the License, or
6+
# (at your option) any later version.
7+
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU Affero General Public License for more details.
12+
13+
# You should have received a copy of the GNU Affero General Public License
14+
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
15+
16+
import yaml
17+
18+
from kubernetes import client
19+
20+
from stack.deploy.k8s.deploy_k8s import K8sDeployer
21+
from stack.log import output_main
22+
from stack.util import error_exit
23+
24+
25+
def _k8s_object_to_yaml(obj):
26+
api_client = client.ApiClient()
27+
sanitized = api_client.sanitize_for_serialization(obj)
28+
return yaml.dump(sanitized, default_flow_style=False, sort_keys=False)
29+
30+
31+
def _print_section(title, objects):
32+
if not objects:
33+
return
34+
output_main(f"--- {title} ---")
35+
for obj in objects:
36+
output_main(_k8s_object_to_yaml(obj))
37+
38+
39+
def explain_op(ctx):
40+
deployer = ctx.obj.deployer
41+
42+
if not isinstance(deployer, K8sDeployer):
43+
error_exit("The explain command is currently only supported for k8s deployments")
44+
45+
cluster_info = deployer.cluster_info
46+
is_kind = deployer.is_kind()
47+
48+
pvs = cluster_info.get_pvs()
49+
_print_section("PersistentVolumes", pvs)
50+
51+
pvcs = cluster_info.get_pvcs()
52+
_print_section("PersistentVolumeClaims", pvcs)
53+
54+
config_maps = cluster_info.get_configmaps()
55+
_print_section("ConfigMaps", config_maps)
56+
57+
deployments = cluster_info.get_deployments(image_pull_policy=None if is_kind else "Always")
58+
_print_section("Deployments", deployments)
59+
60+
services = cluster_info.get_services()
61+
_print_section("Services", services)
62+
63+
http_proxy_info = cluster_info.spec.get_http_proxy()
64+
use_tls = http_proxy_info and not is_kind
65+
ingress = cluster_info.get_ingress(use_tls=use_tls)
66+
if ingress:
67+
_print_section("Ingress", [ingress])

0 commit comments

Comments
 (0)