package actions import ( "context" "encoding/json" "errors" "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/dynamic" "github.com/sophotechlabs/spinoza/internal/api" "github.com/sophotechlabs/spinoza/internal/unstr" ) const instantiateAnnotation = "cronjob.kubernetes.io/instantiate" var jobsGVR = schema.GroupVersionResource{Group: batchGroup, Version: "v1", Resource: "jobs"} func (s *Service) setSuspended(ctx context.Context, ref api.ObjectRef, suspended bool) (api.ActionResult, error) { patch, err := json.Marshal(map[string]any{ specField: map[string]any{"suspend": suspended}, }) if err != nil { return api.ActionResult{}, err } _, patchErr := s.target(ref).Patch(ctx, ref.Name, types.MergePatchType, patch, patchOptions()) if patchErr != nil { return api.ActionResult{}, patchErr } if suspended { return api.ActionResult{ Action: string(Suspend), Message: fmt.Sprintf("Suspended %s. Runs already going are left alone.", ref.Name), }, nil } return api.ActionResult{ Action: string(Resume), Message: fmt.Sprintf("Resumed %s.", ref.Name), }, nil } func (s *Service) trigger(ctx context.Context, ref api.ObjectRef) (api.ActionResult, error) { cron, err := s.target(ref).Get(ctx, ref.Name, metav1.GetOptions{}) if err != nil { return api.ActionResult{}, err } job, err := jobFrom(cron) if err != nil { return api.ActionResult{}, err } made, createErr := s.jobs(ref).Create(ctx, job, metav1.CreateOptions{FieldManager: fieldManager}) if createErr != nil { return api.ActionResult{}, createErr } return api.ActionResult{ Action: string(Trigger), Message: fmt.Sprintf("Started job %s.", made.GetName()), }, nil } func (s *Service) jobs(ref api.ObjectRef) dynamic.ResourceInterface { return s.dyn.Resource(jobsGVR).Namespace(ref.Namespace) } func jobFrom(cron *unstructured.Unstructured) (*unstructured.Unstructured, error) { spec, found := unstr.Map(cron, specField, "jobTemplate", specField) if !found { return nil, errors.New("the cron job carries no job template") } annotations, _ := unstr.Map(cron, specField, "jobTemplate", "metadata", "annotations") if annotations == nil { annotations = map[string]any{} } annotations[instantiateAnnotation] = "manual" meta := map[string]any{ "generateName": cron.GetName() + "-", "namespace": cron.GetNamespace(), "annotations": annotations, "ownerReferences": []any{map[string]any{ "apiVersion": batchGroup + "/v1", "kind": "CronJob", "name": cron.GetName(), "uid": string(cron.GetUID()), }}, } if labels, ok := unstr.Map(cron, specField, "jobTemplate", "metadata", "labels"); ok { meta["labels"] = labels } return &unstructured.Unstructured{Object: map[string]any{ "apiVersion": batchGroup + "/v1", "kind": "Job", "metadata": meta, specField: spec, }}, nil }