|
# retoor <retoor@molodetz.nl>
|
|
|
|
from devplacepy.cli._shared import _audit_cli
|
|
|
|
|
|
def cmd_containers_list(args):
|
|
from devplacepy.services.containers import store
|
|
|
|
instances = store.all_instances()
|
|
if not instances:
|
|
print("No container instances")
|
|
return
|
|
for inst in instances:
|
|
print(
|
|
f"{inst['uid'][:8]} {inst.get('name', ''):24.24} {inst.get('status', ''):10} "
|
|
f"desired={inst.get('desired_state', '')} policy={inst.get('restart_policy', '')}"
|
|
)
|
|
|
|
|
|
def cmd_containers_reconcile(args):
|
|
import asyncio
|
|
from devplacepy.services.containers.service import ContainerService
|
|
|
|
asyncio.run(ContainerService().run_once())
|
|
_audit_cli("cli.containers.reconcile", "CLI ran one container reconcile pass")
|
|
print("Reconcile pass complete")
|
|
|
|
|
|
def cmd_containers_prune(args):
|
|
import asyncio
|
|
from devplacepy.services.containers.runtime import get_backend
|
|
from devplacepy.services.containers.service import ContainerService
|
|
|
|
async def run():
|
|
await ContainerService().run_once()
|
|
await get_backend().image_prune()
|
|
|
|
asyncio.run(run())
|
|
_audit_cli("cli.containers.prune", "CLI reaped orphan containers and dangling images")
|
|
print("Reaped orphans and pruned dangling images")
|
|
|
|
|
|
def cmd_containers_prune_builds(args):
|
|
import asyncio
|
|
from devplacepy.database import db, get_table
|
|
from devplacepy.services.containers.runtime import get_backend
|
|
|
|
async def run():
|
|
backend = get_backend()
|
|
removed = 0
|
|
if "builds" in db.tables:
|
|
for build in list(get_table("builds").find()):
|
|
tag = build.get("image_tag")
|
|
if tag:
|
|
await backend.remove_image(tag)
|
|
removed += 1
|
|
for table in ("builds", "dockerfile_versions", "dockerfiles"):
|
|
if table in db.tables:
|
|
get_table(table).delete()
|
|
return removed
|
|
|
|
removed = asyncio.run(run())
|
|
_audit_cli("cli.containers.prune_builds", "CLI removed legacy images and build tables", metadata={"removed": removed})
|
|
print(
|
|
f"Removed {removed} legacy per-project image(s) and cleared the dockerfiles/builds tables"
|
|
)
|
|
|
|
|
|
def cmd_containers_gc_workspaces(args):
|
|
import shutil
|
|
from pathlib import Path
|
|
from devplacepy import config
|
|
from devplacepy.services.containers import store
|
|
|
|
active = {inst["project_uid"] for inst in store.all_instances()}
|
|
base = Path(config.CONTAINER_WORKSPACES_DIR)
|
|
removed = 0
|
|
if base.is_dir():
|
|
for child in base.iterdir():
|
|
if child.is_dir() and child.name not in active:
|
|
shutil.rmtree(child, ignore_errors=True)
|
|
removed += 1
|
|
_audit_cli("cli.containers.gc_workspaces", f"CLI removed {removed} unused workspace dirs", metadata={"count": removed})
|
|
print(
|
|
f"Removed {removed} unused workspace director{'y' if removed == 1 else 'ies'}"
|
|
)
|
|
|
|
|
|
def register_containers(subparsers):
|
|
containers = subparsers.add_parser("containers", help="Container manager")
|
|
containers_sub = containers.add_subparsers(title="action", dest="action")
|
|
containers_sub.add_parser("list", help="List container instances").set_defaults(
|
|
func=cmd_containers_list
|
|
)
|
|
containers_sub.add_parser("reconcile", help="Run one reconcile pass").set_defaults(
|
|
func=cmd_containers_reconcile
|
|
)
|
|
containers_sub.add_parser(
|
|
"prune", help="Reap orphan containers and dangling images"
|
|
).set_defaults(func=cmd_containers_prune)
|
|
containers_sub.add_parser(
|
|
"prune-builds",
|
|
help="Remove legacy per-project images and clear the dockerfiles/builds tables",
|
|
).set_defaults(func=cmd_containers_prune_builds)
|
|
containers_sub.add_parser(
|
|
"gc-workspaces", help="Remove workspace dirs with no instances"
|
|
).set_defaults(func=cmd_containers_gc_workspaces)
|