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
2 changes: 1 addition & 1 deletion resources/charts/namespaces/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ roles:
resources: ["pods", "services"]
verbs: ["get", "list", "watch", "create", "delete", "update"]
- apiGroups: [""]
resources: ["pods"]
resources: ["pods", "secrets"]
verbs: ["get", "list", "watch", "create", "delete", "update", "patch"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/attach", "pods/portforward"]
Expand Down
43 changes: 22 additions & 21 deletions src/warnet/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
)
from .k8s import (
can_delete_pods,
delete_persistent_volume_claim,
delete_pod,
delete_release_secrets,
get_default_namespace,
get_default_namespace_or,
get_mission,
Expand Down Expand Up @@ -149,30 +151,17 @@ def stop_all_scenarios(scenarios) -> None:

@click.command()
def down():
"""Bring down a running warnet quickly"""

def uninstall_release(namespace, release_name):
cmd = f"helm uninstall {release_name} --namespace {namespace} --wait"
print(f"Initiating uninstall of {release_name} in namespace {namespace}")
subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return f"Uninstalled {release_name} in namespace {namespace}"

def delete_pod(pod_name, namespace):
cmd = f"kubectl delete pod --ignore-not-found=true {pod_name} -n {namespace} --wait"
print(f"Initiated deletion of pod: {pod_name} in namespace {namespace}")
subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return f"Deleted pod: {pod_name} in namespace {namespace}"

def delete_persistent_volume_claim(pvc_name, namespace):
cmd = f"kubectl delete pvc --ignore-not-found=true {pvc_name} -n {namespace} --wait"
print(f"Initiated deletion of PVC: {pvc_name} in namespace {namespace}")
subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return f"Deleted PVC: {pvc_name} in namespace {namespace}"
"""Bring down a running warnet carefully"""

if not can_delete_pods():
click.secho("You do not have permission to bring down the network.", fg="red")
return

def uninstall_release(namespace, release_name):
cmd = f"helm uninstall {release_name} --namespace {namespace} --wait"
print(f"Initiating uninstall of {release_name} in namespace {namespace}")
return subprocess.run(cmd, shell=True, capture_output=True, text=True)

namespaces = get_namespaces()
release_list: list[dict[str, str]] = []
pvc_list: list[dict[str, str]] = []
Expand Down Expand Up @@ -261,7 +250,11 @@ def delete_persistent_volume_claim(pvc_name, namespace):

# Wait for all tasks to complete and print results
for future in as_completed(futures):
console.print(f"[yellow]{future.result()}[/yellow]")
result = future.result()
if result.returncode == 0:
console.print(f"[yellow]{result.stdout[:-1]}[/yellow]")
else:
console.print(f"[red]{result.stderr[:-1]}\n\tcmd: {result.args}[/red]")

with ThreadPoolExecutor(max_workers=10) as executor:
futures = []
Expand All @@ -278,9 +271,17 @@ def delete_persistent_volume_claim(pvc_name, namespace):
executor.submit(delete_persistent_volume_claim, pvc["name"], pvc["namespace"])
)

# Clean up Helm release secrets
for release in release_list:
futures.append(
executor.submit(delete_release_secrets, release["name"], release["namespace"])
)

# Wait for all tasks to complete and print results
for future in as_completed(futures):
console.print(f"[yellow]{future.result()}[/yellow]")
e = future.exception()
if e and e.status != 404:
console.print(f"[red]{e}[/red]")

console.print("[bold yellow]Teardown process initiated for all components.[/bold yellow]")
console.print("[bold yellow]Note: Some processes may continue in the background.[/bold yellow]")
Expand Down
45 changes: 39 additions & 6 deletions src/warnet/k8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@
import yaml
from kubernetes import client, config, watch
from kubernetes.client import CoreV1Api
from kubernetes.client.models import V1Namespace, V1Pod, V1PodList, V1TokenRequestSpec
from kubernetes.client.models import (
V1DeleteOptions,
V1Namespace,
V1Pod,
V1PodList,
V1TokenRequestSpec,
)
from kubernetes.client.rest import ApiException
from kubernetes.dynamic import DynamicClient
from kubernetes.stream import stream
Expand Down Expand Up @@ -150,14 +156,41 @@ def apply_kubernetes_yaml_obj(yaml_obj: str) -> None:


def delete_namespace(namespace: str) -> bool:
command = f"kubectl delete namespace {namespace} --ignore-not-found"
return run_command(command)
sclient = get_static_client()
sclient.sclient.delete_namespace(
name=namespace,
body=V1DeleteOptions,
)
print(f"Deleted namespace {namespace}")


def delete_pod(pod_name: str, namespace: Optional[str] = None) -> bool:
def delete_pod(pod_name: str, namespace: Optional[str] = None):
namespace = get_default_namespace_or(namespace)
command = f"kubectl -n {namespace} delete pod {pod_name}"
return stream_command(command)
sclient = get_static_client()
sclient.delete_namespaced_pod(name=pod_name, namespace=namespace, body=V1DeleteOptions())
print(f"Deleted pod {pod_name}.{namespace}")


def delete_release_secrets(release_name: str, namespace: Optional[str] = None):
namespace = get_default_namespace_or(namespace)
sclient = get_static_client()
secrets = sclient.list_namespaced_secret(
namespace=namespace, label_selector=f"owner=helm,name={release_name}"
)
for secret in secrets.items:
sclient.delete_namespaced_secret(
name=secret.metadata.name, namespace=namespace, body=V1DeleteOptions()
)
print(f"Deleted secret {release_name}.{namespace}")


def delete_persistent_volume_claim(pvc_name: str, namespace: Optional[str] = None):
namespace = get_default_namespace_or(namespace)
sclient = get_static_client()
sclient.delete_namespaced_persistent_volume_claim(
name=pvc_name, namespace=namespace, body=V1DeleteOptions()
)
print(f"Deleted PVC {pvc_name}.{namespace}")


def get_default_namespace() -> str:
Expand Down