# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from fastapi import Depends, APIRouter, Request
from devplacepy.models import ContainerScheduleForm
from devplacepy.responses import action_result, json_error
from devplacepy.services.containers import api, store
from devplacepy.services.containers.api import ContainerError
from devplacepy.services.devii.tasks.schedule import Schedule, from_iso
from devplacepy.services.audit import record as audit
from devplacepy.utils import require_admin
from devplacepy.dependencies import json_or_form
from devplacepy.routers.projects.containers._shared import (
instance_for,
manage_guard,
project_for,
slug_of,
)
logger = logging.getLogger(__name__)
router = APIRouter()
@router.post("/{project_slug}/containers/instances/{uid}/schedules")
async def create_schedule(
request: Request,
project_slug: str,
uid: str,
data: Annotated[ContainerScheduleForm, Depends(json_or_form(ContainerScheduleForm))],
):
user = require_admin(request)
project = project_for(project_slug, user)
inst = instance_for(project, uid)
denied = manage_guard(request, user, project, inst, "container.schedule.create")
if denied:
return denied
try:
schedule = Schedule(
kind=data.kind,
cron=data.cron or None,
run_at=from_iso(data.run_at) if data.run_at else None,
delay_seconds=data.delay_seconds,
every_seconds=data.every_seconds,
max_runs=data.max_runs,
)
sched = api.add_schedule(inst, data.action, schedule)
except (ContainerError, ValueError) as exc:
return json_error(400, str(exc))
audit.record(
request,
"container.schedule.create",
user=user,
target_type="instance",
target_uid=inst["uid"],
target_label=inst.get("name"),
metadata={"action": data.action, "kind": data.kind, "cron": data.cron},
summary=f"admin {user['username']} scheduled {data.action} on instance {inst.get('name')}",
links=[audit.instance(inst["uid"], inst.get("name")), audit.schedule(sched.get("uid") if isinstance(sched, dict) else None)],
)
return action_result(
request, f"/projects/{slug_of(project)}/containers", data={"schedule": sched}
)
@router.post("/{project_slug}/containers/instances/{uid}/schedules/{sid}/delete")
async def delete_schedule(request: Request, project_slug: str, uid: str, sid: str):
user = require_admin(request)
project = project_for(project_slug, user)
inst = instance_for(project, uid)
denied = manage_guard(request, user, project, inst, "container.schedule.delete")
if denied:
return denied
store.delete_schedule(sid)
audit.record(
request,
"container.schedule.delete",
user=user,
target_type="instance",
target_uid=inst["uid"],
target_label=inst.get("name"),
metadata={"schedule_uid": sid},
summary=f"admin {user['username']} deleted a schedule on instance {inst.get('name')}",
links=[audit.instance(inst["uid"], inst.get("name")), audit.schedule(sid)],
)
return action_result(
request, f"/projects/{slug_of(project)}/containers", data={"uid": sid}
)