Skip to content

Commit 628acb2

Browse files
committed
Rollup kubectl commands to a common library
1 parent f4711b2 commit 628acb2

File tree

9 files changed

+525
-236
lines changed

9 files changed

+525
-236
lines changed

src/kube_galaxy/cmd/status.py

Lines changed: 13 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
import typer
66

7+
from kube_galaxy.pkg.utils.client import get_context, get_nodes, wait_for_nodes, wait_for_pods
8+
from kube_galaxy.pkg.utils.errors import ClusterError
79
from kube_galaxy.pkg.utils.logging import error, info, print_dict, section, success, warning
8-
from kube_galaxy.pkg.utils.shell import ShellError, run
10+
from kube_galaxy.pkg.utils.shell import run
911

1012

1113
def status(wait: bool = False, timeout: int = 300) -> None:
@@ -39,21 +41,20 @@ def _print_cluster_context() -> None:
3941

4042
info("")
4143
try:
42-
result = run(["kubectl", "config", "current-context"], capture_output=True, check=False)
43-
context = result.stdout.strip() if result.returncode == 0 else "none"
44+
context = get_context()
4445
info(f"Active Cluster: {context}")
45-
except Exception:
46+
except ClusterError:
4647
info("Active Cluster: error checking")
4748

4849
try:
49-
result = run(["kubectl", "get", "nodes"], capture_output=True, check=False)
50-
if result.returncode == 0 and result.stdout:
51-
lines = result.stdout.strip().split("\n")
50+
nodes_output = get_nodes()
51+
if nodes_output:
52+
lines = nodes_output.strip().split("\n")
5253
info(f"Cluster Nodes: {len(lines) - 1}")
5354
for line in lines[1:]:
5455
if line:
5556
info(f" {line}")
56-
except Exception:
57+
except ClusterError:
5758
pass
5859

5960

@@ -63,54 +64,17 @@ def _verify_cluster_health(timeout: int) -> None:
6364
error("kubectl is required for --wait health checks", show_traceback=False)
6465
raise typer.Exit(code=1)
6566

66-
timeout_arg = f"--timeout={timeout}s"
6767
section("Cluster Health Verification")
6868
info("Waiting for nodes to be Ready...")
6969

7070
try:
71-
run(
72-
["kubectl", "wait", "--for=condition=Ready", "node", "--all", timeout_arg],
73-
capture_output=True,
74-
)
75-
run(
76-
[
77-
"kubectl",
78-
"wait",
79-
"--for=condition=Ready",
80-
"pod",
81-
"--all",
82-
"-n",
83-
"kube-system",
84-
timeout_arg,
85-
],
86-
capture_output=True,
87-
)
88-
except ShellError as exc:
89-
if exc.stderr.strip():
90-
error(exc.stderr.strip(), show_traceback=False)
71+
wait_for_nodes(timeout=timeout)
72+
wait_for_pods(namespace="kube-system", timeout=timeout)
73+
except ClusterError as exc:
74+
error(str(exc), show_traceback=False)
9175
error("Cluster readiness checks failed", show_traceback=False)
9276
raise typer.Exit(code=1) from exc
9377

94-
_print_command_output(["kubectl", "cluster-info"], "Cluster Info")
95-
_print_command_output(["kubectl", "get", "nodes", "-o", "wide"], "Nodes")
96-
_print_command_output(["kubectl", "get", "pods", "-A", "-o", "wide"], "Pods")
97-
98-
99-
def _print_command_output(command: list[str], title: str) -> None:
100-
"""Run command and print its output with a section label."""
101-
info("")
102-
info(f"{title}:")
103-
try:
104-
result = run(command, capture_output=True)
105-
output = result.stdout.strip()
106-
if output:
107-
info(output)
108-
except ShellError as exc:
109-
if exc.stderr.strip():
110-
error(exc.stderr.strip(), show_traceback=False)
111-
error(f"Failed to run: {' '.join(command)}", show_traceback=False)
112-
raise typer.Exit(code=1) from exc
113-
11478

11579
def _check_command(cmd: str) -> str:
11680
"""Check if a command is installed and return status."""

src/kube_galaxy/cmd/test.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Test command handler."""
22

3-
import subprocess
43
from pathlib import Path
54

65
import typer
@@ -9,6 +8,8 @@
98
from kube_galaxy.pkg.manifest.loader import load_manifest
109
from kube_galaxy.pkg.manifest.validator import validate_manifest
1110
from kube_galaxy.pkg.testing.spread import collect_test_results, run_spread_tests
11+
from kube_galaxy.pkg.utils.client import get_context, verify_connectivity
12+
from kube_galaxy.pkg.utils.errors import ClusterError
1213
from kube_galaxy.pkg.utils.logging import error, exception, info, section, success, warning
1314

1415

@@ -22,25 +23,10 @@ def spread(manifest_path: str) -> None:
2223

2324
try:
2425
# Check if kubectl can connect
25-
result = subprocess.run(
26-
["kubectl", "cluster-info"],
27-
capture_output=True,
28-
text=True,
29-
check=False,
30-
)
31-
if result.returncode != 0:
32-
error("No Kubernetes cluster available. Please set up a cluster first.")
33-
info("You can create a test cluster with: kube-galaxy setup")
34-
raise typer.Exit(code=1)
26+
verify_connectivity()
3527

3628
# Get cluster context
37-
result = subprocess.run(
38-
["kubectl", "config", "current-context"],
39-
capture_output=True,
40-
text=True,
41-
check=True,
42-
)
43-
cluster_context = result.stdout.strip()
29+
cluster_context = get_context()
4430
success(f"Connected to cluster: {cluster_context}")
4531

4632
# Run spread tests from manifest
@@ -57,7 +43,7 @@ def spread(manifest_path: str) -> None:
5743

5844
success("Spread tests completed")
5945

60-
except Exception as e:
46+
except ClusterError as e:
6147
exception("Spread tests failed", e)
6248
raise typer.Exit(code=1) from e
6349

src/kube_galaxy/pkg/components/_base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from kube_galaxy.pkg.arch.detector import ArchInfo
1919
from kube_galaxy.pkg.literals import Commands, Permissions, SystemPaths, Timeouts
2020
from kube_galaxy.pkg.manifest.models import ComponentConfig, InstallMethod, Manifest
21+
from kube_galaxy.pkg.utils.client import apply_manifest
2122
from kube_galaxy.pkg.utils.components import (
2223
download_file,
2324
extract_archive,
@@ -243,8 +244,7 @@ def bootstrap_hook(self) -> None:
243244
raise ComponentError(
244245
f"{comp_name} manifest not downloaded. Run download hook first."
245246
)
246-
run(["kubectl", "apply", "-f", str(self.manifest_path)], check=True)
247-
info(f"Applied manifest for {comp_name}")
247+
apply_manifest(self.manifest_path)
248248

249249
pass
250250

src/kube_galaxy/pkg/components/kubeadm.py

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
from kube_galaxy.pkg.components import ClusterComponentBase, register_component
1616
from kube_galaxy.pkg.literals import Commands, SystemPaths, URLs
17+
from kube_galaxy.pkg.utils.client import (
18+
get_api_server_status,
19+
verify_connectivity,
20+
wait_for_nodes,
21+
)
1722
from kube_galaxy.pkg.utils.errors import ComponentError
1823
from kube_galaxy.pkg.utils.logging import info
1924
from kube_galaxy.pkg.utils.shell import run
@@ -184,26 +189,9 @@ def verify_hook(self) -> None:
184189
185190
Checks cluster connectivity and waits for nodes/pods to be ready.
186191
"""
187-
188-
# Check cluster info
189-
run(["kubectl", "cluster-info"], check=True)
190-
191-
# Wait for nodes to be ready
192-
run(
193-
["kubectl", "wait", "--for=condition=Ready", "nodes", "--all", "--timeout=300s"],
194-
check=True,
195-
)
196-
197-
# Wait for api-server to be ready
198-
run(
199-
[
200-
"kubectl",
201-
"get",
202-
"--raw=/readyz",
203-
"--request-timeout=300s",
204-
],
205-
check=True,
206-
)
192+
verify_connectivity()
193+
wait_for_nodes(timeout=300)
194+
get_api_server_status(timeout=300)
207195

208196
def stop_hook(self) -> None:
209197
"""

src/kube_galaxy/pkg/testing/spread.py

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
task_path_for_component,
1919
validate_component_test_structure,
2020
)
21+
from kube_galaxy.pkg.utils.client import create_namespace, delete_namespace, verify_connectivity
2122
from kube_galaxy.pkg.utils.errors import ClusterError
2223
from kube_galaxy.pkg.utils.logging import error, info, section, success, warning
2324
from kube_galaxy.pkg.utils.shell import ShellError, run
@@ -111,9 +112,7 @@ def run_spread_tests(
111112
def _verify_test_prerequisites() -> None:
112113
"""Verify kubectl and spread are available."""
113114
try:
114-
info("Verifying cluster connectivity...")
115-
run(["kubectl", "cluster-info"], check=True, capture_output=True)
116-
success("Connected to Kubernetes cluster")
115+
verify_connectivity()
117116

118117
# Check for spread
119118
info("Verifying spread test framework...")
@@ -148,23 +147,15 @@ def _create_test_namespace(component_name: str) -> str:
148147
namespace = f"kube-galaxy-test-{component_name.lower().replace('_', '-')}"
149148

150149
try:
151-
info(f" Creating test namespace: {namespace}")
152-
153-
# Apply with labels
154-
run(["kubectl", "create", "namespace", namespace], check=True)
155-
156-
# Label namespace
157-
label = "app.kubernetes.io/managed-by=kube-galaxy"
158-
run(
159-
["kubectl", "label", "namespace", namespace, label, f"component={component_name}"],
160-
check=True,
161-
)
162-
163-
success(f"Namespace created: {namespace}")
150+
labels = {
151+
"app.kubernetes.io/managed-by": "kube-galaxy",
152+
"component": component_name,
153+
}
154+
create_namespace(namespace, labels)
164155
return namespace
165156

166-
except ShellError as exc:
167-
raise ClusterError(f"Failed to create namespace {namespace}: {exc}") from exc
157+
except ClusterError:
158+
raise
168159

169160

170161
def _cleanup_test_namespace(namespace: str, timeout: int = 60) -> None:
@@ -179,22 +170,9 @@ def _cleanup_test_namespace(namespace: str, timeout: int = 60) -> None:
179170
ClusterError: If namespace deletion fails
180171
"""
181172
try:
182-
info(f" Cleaning up namespace: {namespace}")
183-
184-
# Delete namespace
185-
run(
186-
["kubectl", "delete", "namespace", namespace, "--timeout", f"{timeout}s"],
187-
check=True,
188-
)
189-
190-
success(f"Namespace deleted: {namespace}")
191-
192-
except ShellError as exc:
193-
# Don't fail if namespace doesn't exist
194-
if "not found" in str(exc):
195-
warning(f" Namespace {namespace} not found (may already be deleted)")
196-
else:
197-
raise ClusterError(f"Failed to delete namespace {namespace}: {exc}") from exc
173+
delete_namespace(namespace, timeout)
174+
except ClusterError:
175+
raise
198176

199177

200178
def _generate_orchestration_spread_yaml(

0 commit comments

Comments
 (0)