|
# 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}
|
|
)
|