From 13f04e1d84ad849f2be0d5243ea020b043288ab1 Mon Sep 17 00:00:00 2001 From: Bapung Date: Sun, 11 Jan 2026 21:32:35 +0800 Subject: [PATCH] fix label logic --- config/manager/kustomization.yaml | 2 +- internal/controller/runnergroup_controller.go | 48 +++++++++++++++++-- internal/gitea/client.go | 36 +++++++------- 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 617abe7..81dc759 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -5,7 +5,7 @@ kind: Kustomization images: - name: controller newName: ghcr.io/bapung/gitea-runner-operator - newTag: sha-00496f8 + newTag: sha-a34dedb patchesStrategicMerge: - image_pull_secret_patch.yaml diff --git a/internal/controller/runnergroup_controller.go b/internal/controller/runnergroup_controller.go index be4f374..7ca0448 100644 --- a/internal/controller/runnergroup_controller.go +++ b/internal/controller/runnergroup_controller.go @@ -117,6 +117,9 @@ func (r *RunnerGroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) logger.Info("Checking Gitea for queued jobs", "url", runnerGroup.Spec.GiteaURL, "scope", runnerGroup.Spec.Scope) + // Calculate effective labels (spec labels + defaults) + effectiveLabels := r.getEffectiveLabels(runnerGroup.Spec.Labels) + // Query for queued workflow runs queuedJobs, err := r.GiteaClient.GetQueuedRuns( ctx, @@ -125,7 +128,7 @@ func (r *RunnerGroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) runnerGroup.Spec.Scope, runnerGroup.Spec.Org, runnerGroup.Spec.Repo, - runnerGroup.Spec.Labels, + effectiveLabels, ) if err != nil { logger.Error(err, "Failed to query Gitea for queued runs") @@ -153,7 +156,7 @@ func (r *RunnerGroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) // Spawn jobs for i := 0; i < toSpawn; i++ { - job, err := r.constructJobForRunnerGroup(runnerGroup, registrationToken) + job, err := r.constructJobForRunnerGroup(runnerGroup, registrationToken, effectiveLabels) if err != nil { logger.Error(err, "Failed to construct Job") return ctrl.Result{}, err @@ -191,8 +194,43 @@ func (r *RunnerGroupReconciler) getSecretValue(ctx context.Context, namespace st return string(value), nil } +// getEffectiveLabels merges spec labels with default labels +func (r *RunnerGroupReconciler) getEffectiveLabels(specLabels []string) []string { + defaultLabels := []string{ + "ubuntu-latest:docker://node:16-bullseye", + "ubuntu-22.04:docker://node:16-bullseye", + "ubuntu-20.04:docker://node:16-bullseye", + "ubuntu-18.04:docker://node:16-buster", + } + + effectiveLabels := make([]string, len(specLabels)) + copy(effectiveLabels, specLabels) + + for _, defaultLabel := range defaultLabels { + // Check if this default label key is already overridden in specLabels + // defaultLabel format is "key:schema" + parts := strings.SplitN(defaultLabel, ":", 2) + key := parts[0] + + found := false + for _, specLabel := range specLabels { + // Spec label can be "key" or "key:schema" + if specLabel == key || strings.HasPrefix(specLabel, key+":") { + found = true + break + } + } + + if !found { + effectiveLabels = append(effectiveLabels, defaultLabel) + } + } + + return effectiveLabels +} + // constructJobForRunnerGroup creates a Job object for the RunnerGroup -func (r *RunnerGroupReconciler) constructJobForRunnerGroup(runnerGroup *giteav1alpha1.RunnerGroup, registrationToken string) (*batchv1.Job, error) { +func (r *RunnerGroupReconciler) constructJobForRunnerGroup(runnerGroup *giteav1alpha1.RunnerGroup, registrationToken string, labels []string) (*batchv1.Job, error) { // Generate random suffix for name name := fmt.Sprintf("%s-%s", runnerGroup.Name, randString(8)) @@ -206,8 +244,8 @@ func (r *RunnerGroupReconciler) constructJobForRunnerGroup(runnerGroup *giteav1a {Name: "DOCKER_TLS_VERIFY", Value: "1"}, } - if len(runnerGroup.Spec.Labels) > 0 { - labelsStr := strings.Join(runnerGroup.Spec.Labels, ",") + if len(labels) > 0 { + labelsStr := strings.Join(labels, ",") envVars = append(envVars, corev1.EnvVar{Name: "GITEA_RUNNER_LABELS", Value: labelsStr}) } diff --git a/internal/gitea/client.go b/internal/gitea/client.go index 3f29d47..53676b8 100644 --- a/internal/gitea/client.go +++ b/internal/gitea/client.go @@ -465,16 +465,11 @@ func (c *HTTPClient) fetchUserRepos(ctx context.Context, giteaURL, authToken str } // filterQueuedJobs filters workflow jobs by labels -func (c *HTTPClient) filterQueuedJobs(jobs []ActionWorkflowJob, requiredLabels []string) int { - if len(requiredLabels) == 0 { - // No label filtering required, return all queued jobs - return len(jobs) - } - +func (c *HTTPClient) filterQueuedJobs(jobs []ActionWorkflowJob, runnerLabels []string) int { count := 0 for _, job := range jobs { - match := c.jobMatchesLabels(job.Labels, requiredLabels) - fmt.Printf("DEBUG: Job %d (Status: %s, Labels: %v) matches requirements %v? %v\n", job.ID, job.Status, job.Labels, requiredLabels, match) + match := c.jobMatchesLabels(job.Labels, runnerLabels) + fmt.Printf("DEBUG: Job %d (Status: %s, Labels: %v) matches runner capabilities %v? %v\n", job.ID, job.Status, job.Labels, runnerLabels, match) if match { count++ } @@ -482,17 +477,24 @@ func (c *HTTPClient) filterQueuedJobs(jobs []ActionWorkflowJob, requiredLabels [ return count } -// jobMatchesLabels checks if a job's labels match the required labels -func (c *HTTPClient) jobMatchesLabels(jobLabels, requiredLabels []string) bool { - // Convert job labels to map for faster lookup - labelSet := make(map[string]bool) - for _, label := range jobLabels { - labelSet[label] = true +// jobMatchesLabels checks if a job's requirements are satisfied by the runner's supported labels +func (c *HTTPClient) jobMatchesLabels(jobLabels, supportedLabels []string) bool { + if len(jobLabels) == 0 { + return true } - // Check if all required labels are present - for _, required := range requiredLabels { - if !labelSet[required] { + // For each label required by the job, check if the runner supports it + for _, req := range jobLabels { + found := false + for _, supp := range supportedLabels { + // Check for exact match or schema match (label:schema) + // e.g. Job asks for "ubuntu-latest", Runner has "ubuntu-latest:docker://..." + if req == supp || strings.HasPrefix(supp, req+":") { + found = true + break + } + } + if !found { return false } }