Thomas Zhang 2 месяцев назад
Родитель
Сommit
bec2306a1c
1 измененных файлов с 88 добавлено и 0 удалено
  1. 88 0
      internal/reconciler/job.go

+ 88 - 0
internal/reconciler/job.go

@@ -0,0 +1,88 @@
+/*
+Copyright 2026 LocoStack.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package reconciler
+
+import (
+	"context"
+	"fmt"
+	"maps"
+	"strings"
+
+	"github.com/LocoStack/loco-operator/api/v1alpha1"
+	batchv1 "k8s.io/api/batch/v1"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+)
+
+type JobReconciler struct {
+	client    client.Client
+	scheme    *runtime.Scheme
+	stack     *v1alpha1.Stack
+	component string
+	name      string
+	owner     metav1.Object
+}
+
+func NewJobReconciler(client client.Client, scheme *runtime.Scheme, stack *v1alpha1.Stack, component, name string, owner metav1.Object) *JobReconciler {
+	return &JobReconciler{
+		client:    client,
+		scheme:    scheme,
+		stack:     stack,
+		component: component,
+		name:      fmt.Sprintf("%s-%s", strings.ToLower(component), name),
+		owner:     owner,
+	}
+}
+
+func (r *JobReconciler) ReconcileJob(ctx context.Context, tmpl *v1alpha1.Template, variables map[string]string) (bool, bool, error) {
+	jobSpec, err := buildPodSpec(variables, tmpl)
+	if err != nil {
+		return false, true, fmt.Errorf("Failed to build job spec: %w", err)
+	}
+	jobSpec.RestartPolicy = v1.RestartPolicyOnFailure
+
+	stackName := ""
+	if r.stack != nil {
+		stackName = r.stack.Name
+	}
+	labels := ResourceLabels(stackName, r.component, r.name, "")
+	maps.Copy(labels, tmpl.Metadata.Labels)
+
+	job := &batchv1.Job{ObjectMeta: metav1.ObjectMeta{Name: r.name, Namespace: r.owner.GetNamespace()}}
+	jobCompleted := false
+	jobFailed := false
+	_, err = controllerutil.CreateOrUpdate(ctx, r.client, job, func() error {
+		if job.CreationTimestamp.IsZero() {
+			job.Labels = labels
+			job.Spec = batchv1.JobSpec{
+				Template: v1.PodTemplateSpec{
+					ObjectMeta: metav1.ObjectMeta{
+						Labels: labels,
+					},
+					Spec: jobSpec,
+				},
+			}
+		}
+		jobCompleted = job.Status.Succeeded >= 1
+		jobFailed = job.Status.Failed >= 1
+		return controllerutil.SetControllerReference(r.owner, job, r.scheme)
+	})
+	return jobCompleted, jobFailed, err
+}