Repo-side rename only (Phases 1-3 of the migration plan); the live box (~/.castle, systemd units, /data/castle, domains) is a separate cutover. - Slug `castle` -> `wildpc`: CLI command, module names (wildpc_core/cli/api), dist names, entry point `wildpc = wildpc_cli.main:main`. - Identifiers: CastleConfig/NATSClient/DirError/MDNS -> Wildpc*. - Env/constants: CASTLE_* -> WILDPC_*; ~/.castle -> ~/.wildpc, castle.yaml -> wildpc.yaml, /data/castle -> /data/wildpc. - Systemd UNIT_PREFIX castle- -> wildpc-; own programs castle-api/gateway/etc. - Display prose "Castle" -> "Wild PC" in docs, agent-guide files, README, frontend. - Package dirs and bootstrap yaml renamed via git mv; lockfiles regenerated; redundant nested uv.lock files dropped (workspace root lock is authoritative). Tests: core 273, cli 47, wildpc-api 120 all pass. Frontend type-checks + builds. Fixed a stale test fixture (secret_env_path kind arg) broken pre-rename.
124 lines
3.7 KiB
Python
124 lines
3.7 KiB
Python
"""wildpc service create / wildpc job create — declare a deployment.
|
|
|
|
A service or job can run anything (a wildpc program or not). `--program`
|
|
records a convenience reference for description fallthrough; the run target is
|
|
the console script (python) or argv (command) to execute.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
|
|
from wildpc_cli.config import load_config, save_config
|
|
from wildpc_cli.manifest import (
|
|
DefaultsSpec,
|
|
ExposeSpec,
|
|
HttpExposeSpec,
|
|
HttpInternal,
|
|
ManageSpec,
|
|
Reach,
|
|
RunCommand,
|
|
RunPython,
|
|
SystemdDeployment,
|
|
SystemdSpec,
|
|
)
|
|
|
|
|
|
def _defaults(env_args: list[str] | None) -> DefaultsSpec | None:
|
|
"""Parse repeated --env KEY=VALUE into a DefaultsSpec, or None."""
|
|
if not env_args:
|
|
return None
|
|
env: dict[str, str] = {}
|
|
for item in env_args:
|
|
key, _, value = item.partition("=")
|
|
env[key.strip()] = value
|
|
return DefaultsSpec(env=env)
|
|
|
|
|
|
def _run_spec(launcher: str, target: str, name: str) -> RunPython | RunCommand:
|
|
if launcher == "command":
|
|
return RunCommand(launcher="command", argv=target.split() or [name])
|
|
return RunPython(launcher="python", program=target or name)
|
|
|
|
|
|
def _check_new(config: object, name: str, label: str) -> str | None:
|
|
"""Return an error message if the deployment name is taken, else None."""
|
|
if config.deployments_named(name):
|
|
return f"Error: {label} '{name}' already exists."
|
|
return None
|
|
|
|
|
|
def run_service_create(args: argparse.Namespace) -> int:
|
|
"""Create a service entry in wildpc.yaml."""
|
|
config = load_config()
|
|
name = args.name
|
|
if err := _check_new(config, name, "service"):
|
|
print(err)
|
|
return 1
|
|
|
|
run = _run_spec(args.launcher, args.run or args.program or name, name)
|
|
|
|
expose = None
|
|
reach = Reach.OFF
|
|
if args.port is not None:
|
|
expose = ExposeSpec(
|
|
http=HttpExposeSpec(
|
|
internal=HttpInternal(port=args.port),
|
|
health_path=args.health,
|
|
)
|
|
)
|
|
# Expose at <name>.<gateway.domain> (the subdomain is the service name).
|
|
reach = Reach.OFF if args.no_proxy else Reach.INTERNAL
|
|
|
|
config.services[name] = SystemdDeployment(
|
|
id=name,
|
|
manager="systemd",
|
|
program=args.program,
|
|
description=args.description or None,
|
|
run=run,
|
|
expose=expose,
|
|
reach=reach,
|
|
manage=ManageSpec(systemd=SystemdSpec()),
|
|
defaults=_defaults(args.env),
|
|
)
|
|
save_config(config)
|
|
|
|
print(f"Created service '{name}'.")
|
|
print(f" runs: {args.launcher} ({args.run or args.program or name})")
|
|
if expose:
|
|
print(f" port: {args.port}")
|
|
if reach != Reach.OFF:
|
|
print(f" subdomain: {name}.<gateway.domain>")
|
|
print(f"\nNext: wildpc apply {name}")
|
|
return 0
|
|
|
|
|
|
def run_job_create(args: argparse.Namespace) -> int:
|
|
"""Create a job entry in wildpc.yaml."""
|
|
config = load_config()
|
|
name = args.name
|
|
if err := _check_new(config, name, "job"):
|
|
print(err)
|
|
return 1
|
|
|
|
run = _run_spec(args.launcher, args.run or args.program or name, name)
|
|
|
|
# A job is a systemd deployment with a schedule (→ a .timer).
|
|
config.jobs[name] = SystemdDeployment(
|
|
id=name,
|
|
manager="systemd",
|
|
program=args.program,
|
|
description=args.description or None,
|
|
run=run,
|
|
schedule=args.schedule,
|
|
manage=ManageSpec(systemd=SystemdSpec()),
|
|
defaults=_defaults(args.env),
|
|
)
|
|
save_config(config)
|
|
|
|
print(f"Created job '{name}'.")
|
|
print(f" runs: {args.launcher} ({args.run or args.program or name})")
|
|
print(f" schedule: {args.schedule}")
|
|
print(f"\nNext: wildpc apply {name}")
|
|
return 0
|