mirror of
https://github.com/actions-runner-controller/actions-runner-controller.git
synced 2026-09-30 11:20:24 +02:00
Use lazy copy for annotations
This commit is contained in:
@@ -19,11 +19,10 @@ package actionsgithubcom
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -78,7 +77,6 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
if err := r.Get(ctx, req.NamespacedName, &autoscalingListener); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
var original once[*v1alpha1.AutoscalingListener]
|
||||
|
||||
if !autoscalingListener.DeletionTimestamp.IsZero() {
|
||||
if !controllerutil.ContainsFinalizer(&autoscalingListener, autoscalingListenerFinalizerName) {
|
||||
@@ -93,15 +91,15 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
}
|
||||
if requeue {
|
||||
log.Info("Waiting for resources to be deleted before removing finalizer")
|
||||
return ctrl.Result{Requeue: true, RequeueAfter: time.Second}, nil
|
||||
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||
}
|
||||
|
||||
removeFinalizer := controllerutil.ContainsFinalizer(&autoscalingListener, autoscalingListenerFinalizerName)
|
||||
if removeFinalizer {
|
||||
original.Do(autoscalingListener.DeepCopy)
|
||||
original := newOnce(autoscalingListener.DeepCopy)
|
||||
if controllerutil.ContainsFinalizer(&autoscalingListener, autoscalingListenerFinalizerName) {
|
||||
original.Do()
|
||||
controllerutil.RemoveFinalizer(&autoscalingListener, autoscalingListenerFinalizerName)
|
||||
}
|
||||
if removeFinalizer {
|
||||
if original.Called() {
|
||||
log.Info("Removing finalizer")
|
||||
if err := r.Patch(ctx, &autoscalingListener, client.MergeFrom(original.Get())); err != nil && !kerrors.IsNotFound(err) {
|
||||
log.Error(err, "Failed to remove finalizer")
|
||||
@@ -114,19 +112,19 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
original := newOnce(autoscalingListener.DeepCopy)
|
||||
addFinalizer := !controllerutil.ContainsFinalizer(&autoscalingListener, autoscalingListenerFinalizerName)
|
||||
if addFinalizer {
|
||||
original.Do(autoscalingListener.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.AddFinalizer(&autoscalingListener, autoscalingListenerFinalizerName)
|
||||
}
|
||||
if addFinalizer {
|
||||
if original.Called() {
|
||||
if err := r.Patch(ctx, &autoscalingListener, client.MergeFrom(original.Get())); err != nil {
|
||||
log.Error(err, "Failed to add finalizer")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
log.Info("Successfully added finalizer")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// Check if the AutoscalingRunnerSet exists
|
||||
@@ -174,28 +172,40 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
desiredLabels := r.filterAndMergeLabels(serviceAccount.Labels, desiredServiceAccount.Labels)
|
||||
labelsModified := !maps.Equal(serviceAccount.Labels, desiredLabels)
|
||||
desiredAnnotations := r.mergeAnnotations(serviceAccount.Annotations, desiredServiceAccount.Annotations)
|
||||
annotationsModified := !maps.Equal(serviceAccount.Annotations, desiredAnnotations)
|
||||
var original once[*corev1.ServiceAccount]
|
||||
desiredLabels, labelsModified := r.mergeLabels(serviceAccount.Labels, desiredServiceAccount.Labels)
|
||||
original := newOnce(serviceAccount.DeepCopy)
|
||||
if labelsModified {
|
||||
original.Do(serviceAccount.DeepCopy)
|
||||
original.Do()
|
||||
serviceAccount.Labels = desiredLabels
|
||||
}
|
||||
desiredAnnotations, annotationsModified := r.mergeAnnotations(serviceAccount.Annotations, desiredServiceAccount.Annotations)
|
||||
if annotationsModified {
|
||||
original.Do(serviceAccount.DeepCopy)
|
||||
original.Do()
|
||||
serviceAccount.Annotations = desiredAnnotations
|
||||
}
|
||||
if labelsModified || annotationsModified {
|
||||
secretsModified := !cmp.Equal(serviceAccount.Secrets, desiredServiceAccount.Secrets)
|
||||
if secretsModified {
|
||||
original.Do()
|
||||
serviceAccount.Secrets = desiredServiceAccount.Secrets
|
||||
}
|
||||
imagePullSecretsModified := !cmp.Equal(serviceAccount.ImagePullSecrets, desiredServiceAccount.ImagePullSecrets)
|
||||
if imagePullSecretsModified {
|
||||
original.Do()
|
||||
serviceAccount.ImagePullSecrets = desiredServiceAccount.ImagePullSecrets
|
||||
}
|
||||
automountServiceAccountTokenModified := !cmp.Equal(serviceAccount.AutomountServiceAccountToken, desiredServiceAccount.AutomountServiceAccountToken)
|
||||
if automountServiceAccountTokenModified {
|
||||
original.Do()
|
||||
serviceAccount.AutomountServiceAccountToken = desiredServiceAccount.AutomountServiceAccountToken
|
||||
}
|
||||
|
||||
if original.Called() {
|
||||
log.Info("Updating listener service account")
|
||||
|
||||
if err := r.Patch(ctx, &serviceAccount, client.MergeFrom(original.Get())); err != nil {
|
||||
log.Error(err, "Failed to update listener service account")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
case kerrors.IsNotFound(err):
|
||||
// Create a service account for the listener pod in the controller namespace
|
||||
@@ -218,32 +228,29 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
)
|
||||
switch {
|
||||
case err == nil:
|
||||
original := newOnce(listenerRole.DeepCopy)
|
||||
desiredRole := r.newScaleSetListenerRole(&autoscalingListener)
|
||||
desiredLabels := r.filterAndMergeLabels(listenerRole.Labels, desiredRole.Labels)
|
||||
labelsModified := !maps.Equal(listenerRole.Labels, desiredLabels)
|
||||
desiredAnnotations := r.mergeAnnotations(listenerRole.Annotations, desiredRole.Annotations)
|
||||
annotationsModified := !maps.Equal(listenerRole.Annotations, desiredAnnotations)
|
||||
rulesModified := !reflect.DeepEqual(listenerRole.Rules, desiredRole.Rules)
|
||||
var original once[*rbacv1.Role]
|
||||
desiredLabels, labelsModified := r.mergeLabels(listenerRole.Labels, desiredRole.Labels)
|
||||
if labelsModified {
|
||||
original.Do(listenerRole.DeepCopy)
|
||||
original.Do()
|
||||
listenerRole.Labels = desiredLabels
|
||||
}
|
||||
desiredAnnotations, annotationsModified := r.mergeAnnotations(listenerRole.Annotations, desiredRole.Annotations)
|
||||
if annotationsModified {
|
||||
original.Do(listenerRole.DeepCopy)
|
||||
original.Do()
|
||||
listenerRole.Annotations = desiredAnnotations
|
||||
}
|
||||
rulesModified := !cmp.Equal(listenerRole.Rules, desiredRole.Rules)
|
||||
if rulesModified {
|
||||
original.Do(listenerRole.DeepCopy)
|
||||
original.Do()
|
||||
listenerRole.Rules = desiredRole.Rules
|
||||
}
|
||||
if labelsModified || annotationsModified || rulesModified {
|
||||
if original.Called() {
|
||||
log.Info("Updating listener role")
|
||||
if err := r.Patch(ctx, &listenerRole, client.MergeFrom(original.Get())); err != nil {
|
||||
log.Error(err, "Failed to update listener role")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
case kerrors.IsNotFound(err):
|
||||
// Create a role for the listener pod in the AutoScalingRunnerSet namespace
|
||||
@@ -259,35 +266,42 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
err = r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: autoscalingListener.Name}, &listenerRoleBinding)
|
||||
switch {
|
||||
case err == nil:
|
||||
original := newOnce(listenerRoleBinding.DeepCopy)
|
||||
desiredRoleBinding := r.newScaleSetListenerRoleBinding(
|
||||
&autoscalingListener,
|
||||
&listenerRole,
|
||||
&serviceAccount,
|
||||
)
|
||||
desiredLabels := r.filterAndMergeLabels(listenerRoleBinding.Labels, desiredRoleBinding.Labels)
|
||||
labelsModified := !maps.Equal(listenerRoleBinding.Labels, desiredLabels)
|
||||
desiredAnnotations := r.mergeAnnotations(listenerRoleBinding.Annotations, desiredRoleBinding.Annotations)
|
||||
annotationsModified := !maps.Equal(listenerRoleBinding.Annotations, desiredAnnotations)
|
||||
var original once[*rbacv1.RoleBinding]
|
||||
desiredLabels, labelsModified := r.mergeLabels(listenerRoleBinding.Labels, desiredRoleBinding.Labels)
|
||||
if labelsModified {
|
||||
original.Do(listenerRoleBinding.DeepCopy)
|
||||
original.Do()
|
||||
listenerRoleBinding.Labels = desiredLabels
|
||||
}
|
||||
|
||||
desiredAnnotations, annotationsModified := r.mergeAnnotations(listenerRoleBinding.Annotations, desiredRoleBinding.Annotations)
|
||||
if annotationsModified {
|
||||
original.Do(listenerRoleBinding.DeepCopy)
|
||||
original.Do()
|
||||
listenerRoleBinding.Annotations = desiredAnnotations
|
||||
}
|
||||
if labelsModified || annotationsModified {
|
||||
rulesModified := !cmp.Equal(listenerRoleBinding.RoleRef, desiredRoleBinding.RoleRef)
|
||||
if rulesModified {
|
||||
original.Do()
|
||||
listenerRoleBinding.RoleRef = desiredRoleBinding.RoleRef
|
||||
}
|
||||
|
||||
subjectsModified := !cmp.Equal(listenerRoleBinding.Subjects, desiredRoleBinding.Subjects)
|
||||
if subjectsModified {
|
||||
original.Do()
|
||||
listenerRoleBinding.Subjects = desiredRoleBinding.Subjects
|
||||
}
|
||||
|
||||
if original.Called() {
|
||||
log.Info("Updating listener role binding")
|
||||
if err := r.Patch(ctx, &listenerRoleBinding, client.MergeFrom(original.Get())); err != nil {
|
||||
log.Error(err, "Failed to update listener role binding")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
log.Info("Updated listener role binding")
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
|
||||
case kerrors.IsNotFound(err):
|
||||
// Create a role binding for the listener pod in the AutoScalingRunnerSet namespace
|
||||
log.Info("Creating a role binding for the service account and role")
|
||||
@@ -316,31 +330,47 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
)
|
||||
switch {
|
||||
case err == nil:
|
||||
original := newOnce(proxySecret.DeepCopy)
|
||||
desiredListenerProxy, err := r.newAutoscalingListenerProxySecret(&autoscalingListener, proxySecret.Data)
|
||||
if err != nil {
|
||||
log.Error(err, "Failed to build desired listener proxy secret")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
desiredLabels := r.filterAndMergeLabels(proxySecret.Labels, desiredListenerProxy.Labels)
|
||||
labelsModified := !maps.Equal(proxySecret.Labels, desiredLabels)
|
||||
desiredAnnotations := r.mergeAnnotations(proxySecret.Annotations, desiredListenerProxy.Annotations)
|
||||
annotationsModified := !maps.Equal(proxySecret.Annotations, desiredAnnotations)
|
||||
var original once[*corev1.Secret]
|
||||
desiredLabels, labelsModified := r.mergeLabels(proxySecret.Labels, desiredListenerProxy.Labels)
|
||||
if labelsModified {
|
||||
original.Do(proxySecret.DeepCopy)
|
||||
original.Do()
|
||||
proxySecret.Labels = desiredLabels
|
||||
}
|
||||
desiredAnnotations, annotationsModified := r.mergeAnnotations(proxySecret.Annotations, desiredListenerProxy.Annotations)
|
||||
if annotationsModified {
|
||||
original.Do(proxySecret.DeepCopy)
|
||||
original.Do()
|
||||
proxySecret.Annotations = desiredAnnotations
|
||||
}
|
||||
if labelsModified || annotationsModified {
|
||||
// we set the data so we just need to check other fields are nil
|
||||
if proxySecret.Immutable != nil {
|
||||
original.Do()
|
||||
proxySecret.Immutable = nil
|
||||
}
|
||||
if proxySecret.StringData != nil {
|
||||
original.Do()
|
||||
proxySecret.StringData = nil
|
||||
}
|
||||
if proxySecret.Type != desiredListenerProxy.Type {
|
||||
original.Do()
|
||||
proxySecret.Type = desiredListenerProxy.Type
|
||||
}
|
||||
dataModified := !cmp.Equal(proxySecret.Data, desiredListenerProxy.Data)
|
||||
if dataModified {
|
||||
original.Do()
|
||||
proxySecret.Data = desiredListenerProxy.Data
|
||||
}
|
||||
|
||||
if original.Called() {
|
||||
log.Info("Updating listener proxy secret")
|
||||
if err := r.Patch(ctx, &proxySecret, client.MergeFrom(original.Get())); err != nil {
|
||||
log.Error(err, "Failed to update listener proxy secret")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
case kerrors.IsNotFound(err):
|
||||
// Create a mirror secret for the listener pod in the Controller namespace for listener pod to use
|
||||
@@ -363,10 +393,8 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
log.Error(
|
||||
err,
|
||||
"Failed to get app config for AutoscalingRunnerSet.",
|
||||
"namespace",
|
||||
autoscalingRunnerSet.Namespace,
|
||||
"name",
|
||||
autoscalingRunnerSet.GitHubConfigSecret,
|
||||
"namespace", autoscalingRunnerSet.Namespace,
|
||||
"name", autoscalingRunnerSet.GitHubConfigSecret,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
@@ -394,6 +422,7 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
)
|
||||
switch {
|
||||
case err == nil:
|
||||
original := newOnce(listenerConfigSecret.DeepCopy)
|
||||
cfg, err := r.GetAppConfig(ctx, &autoscalingRunnerSet)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
@@ -409,21 +438,31 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("failed to build listener config secret: %w", err)
|
||||
}
|
||||
desiredLabels := r.filterAndMergeLabels(listenerConfigSecret.Labels, desiredSecret.Labels)
|
||||
labelsModified := !maps.Equal(listenerConfigSecret.Labels, desiredLabels)
|
||||
desiredAnnotations := r.mergeAnnotations(listenerConfigSecret.Annotations, desiredSecret.Annotations)
|
||||
annotationsModified := !maps.Equal(listenerConfigSecret.Annotations, desiredAnnotations)
|
||||
var original once[*corev1.Secret]
|
||||
desiredLabels, labelsModified := r.mergeLabels(listenerConfigSecret.Labels, desiredSecret.Labels)
|
||||
if labelsModified {
|
||||
original.Do(listenerConfigSecret.DeepCopy)
|
||||
original.Do()
|
||||
listenerConfigSecret.Labels = desiredLabels
|
||||
}
|
||||
desiredAnnotations, annotationsModified := r.mergeAnnotations(listenerConfigSecret.Annotations, desiredSecret.Annotations)
|
||||
if annotationsModified {
|
||||
original.Do(listenerConfigSecret.DeepCopy)
|
||||
original.Do()
|
||||
listenerConfigSecret.Annotations = desiredAnnotations
|
||||
}
|
||||
// we set the data so we just need to check other fields are nil
|
||||
if listenerConfigSecret.Immutable != nil {
|
||||
original.Do()
|
||||
listenerConfigSecret.Immutable = nil
|
||||
}
|
||||
if listenerConfigSecret.StringData != nil {
|
||||
original.Do()
|
||||
listenerConfigSecret.StringData = nil
|
||||
}
|
||||
if listenerConfigSecret.Type != desiredSecret.Type {
|
||||
original.Do()
|
||||
listenerConfigSecret.Type = desiredSecret.Type
|
||||
}
|
||||
|
||||
if labelsModified || annotationsModified {
|
||||
if original.Called() {
|
||||
log.Info("Updating listener config secret", "namespace", listenerConfigSecret.Namespace, "name", listenerConfigSecret.Name)
|
||||
if err := r.Patch(ctx, &listenerConfigSecret, client.MergeFrom(original.Get())); err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("failed to update listener config secret: %w", err)
|
||||
@@ -454,7 +493,7 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
}
|
||||
|
||||
// Requeue to create listener pod with the config secret
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
return ctrl.Result{RequeueAfter: 100 * time.Millisecond}, nil
|
||||
default:
|
||||
log.Error(err, "Unable to get listener config secret", "namespace", autoscalingListener.Namespace, "name", scaleSetListenerConfigName(&autoscalingListener))
|
||||
return ctrl.Result{}, err
|
||||
@@ -484,17 +523,15 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
desiredLabels := r.filterAndMergeLabels(listenerPod.Labels, desiredPod.Labels)
|
||||
labelsModified := !maps.Equal(listenerPod.Labels, desiredLabels)
|
||||
desiredAnnotations := r.mergeAnnotations(listenerPod.Annotations, desiredPod.Annotations)
|
||||
annotationsModified := !maps.Equal(listenerPod.Annotations, desiredAnnotations)
|
||||
var original once[*corev1.Pod]
|
||||
original := newOnce(listenerPod.DeepCopy)
|
||||
desiredLabels, labelsModified := r.mergeLabels(listenerPod.Labels, desiredPod.Labels)
|
||||
if labelsModified {
|
||||
original.Do(listenerPod.DeepCopy)
|
||||
original.Do()
|
||||
listenerPod.Labels = desiredLabels
|
||||
}
|
||||
desiredAnnotations, annotationsModified := r.mergeAnnotations(listenerPod.Annotations, desiredPod.Annotations)
|
||||
if annotationsModified {
|
||||
original.Do(listenerPod.DeepCopy)
|
||||
original.Do()
|
||||
listenerPod.Annotations = desiredAnnotations
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package actionsgithubcom
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -74,7 +73,7 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||
if err := r.Get(ctx, req.NamespacedName, &autoscalingRunnerSet); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
var original once[*v1alpha1.AutoscalingRunnerSet]
|
||||
original := newOnce(autoscalingRunnerSet.DeepCopy)
|
||||
|
||||
if !autoscalingRunnerSet.DeletionTimestamp.IsZero() {
|
||||
if !controllerutil.ContainsFinalizer(&autoscalingRunnerSet, autoscalingRunnerSetFinalizerName) {
|
||||
@@ -101,7 +100,7 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||
|
||||
removeFinalizer := controllerutil.ContainsFinalizer(&autoscalingRunnerSet, autoscalingRunnerSetFinalizerName)
|
||||
if removeFinalizer {
|
||||
original.Do(autoscalingRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.RemoveFinalizer(&autoscalingRunnerSet, autoscalingRunnerSetFinalizerName)
|
||||
}
|
||||
if removeFinalizer {
|
||||
@@ -137,7 +136,7 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||
|
||||
addFinalizer := !controllerutil.ContainsFinalizer(&autoscalingRunnerSet, autoscalingRunnerSetFinalizerName)
|
||||
if addFinalizer {
|
||||
original.Do(autoscalingRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.AddFinalizer(&autoscalingRunnerSet, autoscalingRunnerSetFinalizerName)
|
||||
}
|
||||
if addFinalizer {
|
||||
@@ -205,15 +204,15 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
var original once[*v1alpha1.EphemeralRunnerSet]
|
||||
original := newOnce(ephemeralRunnerSet.DeepCopy)
|
||||
ephemeralRunnerReplicasModified := ephemeralRunnerSet.Spec.Replicas != 0
|
||||
if ephemeralRunnerReplicasModified {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
ephemeralRunnerSet.Spec.Replicas = 0
|
||||
}
|
||||
ephemeralRunnerPatchIDModified := ephemeralRunnerSet.Spec.PatchID != 0
|
||||
if ephemeralRunnerPatchIDModified {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
ephemeralRunnerSet.Spec.PatchID = 0
|
||||
}
|
||||
if ephemeralRunnerReplicasModified || ephemeralRunnerPatchIDModified {
|
||||
@@ -302,29 +301,29 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
var original once[*v1alpha1.EphemeralRunnerSet]
|
||||
original := newOnce(ephemeralRunnerSet.DeepCopy)
|
||||
|
||||
ephemeralRunnerActionableSpecModified := !cmp.Equal(ephemeralRunnerSet.Spec.EphemeralRunnerSpec, desired.Spec.EphemeralRunnerSpec)
|
||||
if ephemeralRunnerActionableSpecModified {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
ephemeralRunnerSet.Spec.EphemeralRunnerSpec = desired.Spec.EphemeralRunnerSpec
|
||||
ephemeralRunnerSet.Spec.ActionableRevision = nextActionableRevision(&ephemeralRunnerSet)
|
||||
}
|
||||
|
||||
ephemeralRunnerMetadataModified := !cmp.Equal(ephemeralRunnerSet.Spec.EphemeralRunnerMetadata, desired.Spec.EphemeralRunnerMetadata)
|
||||
if ephemeralRunnerMetadataModified {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
ephemeralRunnerSet.Spec.EphemeralRunnerMetadata = desired.Spec.EphemeralRunnerMetadata
|
||||
}
|
||||
ephemeralRunnerLabelsModified := !maps.Equal(ephemeralRunnerSet.Labels, desired.Labels)
|
||||
desiredLabels, ephemeralRunnerLabelsModified := r.mergeLabels(ephemeralRunnerSet.Labels, desired.Labels)
|
||||
if ephemeralRunnerLabelsModified {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
ephemeralRunnerSet.Labels = r.filterAndMergeLabels(ephemeralRunnerSet.Labels, desired.Labels)
|
||||
original.Do()
|
||||
ephemeralRunnerSet.Labels = desiredLabels
|
||||
}
|
||||
ephemeralRunnerAnnotationsModified := !maps.Equal(ephemeralRunnerSet.Annotations, desired.Annotations)
|
||||
desiredAnnotations, ephemeralRunnerAnnotationsModified := r.mergeAnnotations(ephemeralRunnerSet.Annotations, desired.Annotations)
|
||||
if ephemeralRunnerAnnotationsModified {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
ephemeralRunnerSet.Annotations = r.mergeAnnotations(ephemeralRunnerSet.Annotations, desired.Annotations)
|
||||
original.Do()
|
||||
ephemeralRunnerSet.Annotations = desiredAnnotations
|
||||
}
|
||||
|
||||
if ephemeralRunnerActionableSpecModified || ephemeralRunnerLabelsModified || ephemeralRunnerAnnotationsModified || ephemeralRunnerMetadataModified {
|
||||
@@ -373,9 +372,20 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if !cmp.Equal(listener.Spec, desired.Spec) ||
|
||||
!cmp.Equal(listener.Labels, desired.Labels) ||
|
||||
!cmp.Equal(listener.Annotations, desired.Annotations) {
|
||||
original := newOnce(listener.DeepCopy)
|
||||
desiredLabels, listnerLabelsModified := r.mergeLabels(listener.Labels, desired.Labels)
|
||||
if listnerLabelsModified {
|
||||
original.Do()
|
||||
listener.Labels = desiredLabels
|
||||
}
|
||||
|
||||
desiredAnnotations, listenerAnnotationsModified := r.mergeAnnotations(listener.Annotations, desired.Annotations)
|
||||
if listenerAnnotationsModified {
|
||||
original.Do()
|
||||
listener.Annotations = desiredAnnotations
|
||||
}
|
||||
|
||||
if !cmp.Equal(listener.Spec, desired.Spec) {
|
||||
log.Info("Deleting AutoscalingListener to re-create with updated spec")
|
||||
if err := r.Delete(ctx, &listener); err != nil {
|
||||
log.Error(err, "Failed to delete AutoscalingListener for re-creation")
|
||||
@@ -384,6 +394,16 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||
log.Info("Deleted AutoscalingListener, will re-create on next reconcile")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if original.Called() {
|
||||
log.Info("Updating AutoscalingListener metadata to match desired labels and annotations")
|
||||
if err := r.Patch(ctx, &listener, client.MergeFrom(original.Get())); err != nil {
|
||||
log.Error(err, "Failed to patch AutoscalingListener metadata")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
log.Info("Successfully patched AutoscalingListener metadata")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Autoscaling runner set is up to date and ready")
|
||||
@@ -536,11 +556,11 @@ func (r *AutoscalingRunnerSetReconciler) removeFinalizersFromDependentResources(
|
||||
}
|
||||
|
||||
func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) (ctrl.Result, error) {
|
||||
var original once[*v1alpha1.AutoscalingRunnerSet]
|
||||
original := newOnce(autoscalingRunnerSet.DeepCopy)
|
||||
logger.Info("Creating a new runner scale set")
|
||||
actionsClient, err := r.GetActionsService(ctx, autoscalingRunnerSet)
|
||||
if len(autoscalingRunnerSet.Spec.RunnerScaleSetName) == 0 {
|
||||
original.Do(autoscalingRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
autoscalingRunnerSet.Spec.RunnerScaleSetName = autoscalingRunnerSet.Name
|
||||
}
|
||||
if err != nil {
|
||||
@@ -615,7 +635,7 @@ func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Contex
|
||||
actionsClient.SetSystemInfo(info)
|
||||
|
||||
logger.Info("Created/Reused a runner scale set", "id", runnerScaleSet.ID, "runnerGroupName", runnerScaleSet.RunnerGroupName)
|
||||
original.Do(autoscalingRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
if autoscalingRunnerSet.Annotations == nil {
|
||||
autoscalingRunnerSet.Annotations = map[string]string{}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
if err := r.Get(ctx, req.NamespacedName, &ephemeralRunner); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
var original once[*v1alpha1.EphemeralRunner]
|
||||
original := newOnce(ephemeralRunner.DeepCopy)
|
||||
|
||||
if !ephemeralRunner.DeletionTimestamp.IsZero() {
|
||||
r.publishEphemeralRunnerPhaseMetric(&ephemeralRunner, "", log)
|
||||
@@ -117,7 +117,7 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
}
|
||||
|
||||
log.Info("Runner is cleaned up from the service, removing finalizer")
|
||||
original.Do(ephemeralRunner.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.RemoveFinalizer(&ephemeralRunner, ephemeralRunnerActionsFinalizerName)
|
||||
}
|
||||
if removeActionsFinalizer {
|
||||
@@ -147,7 +147,7 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
|
||||
removeFinalizer := controllerutil.ContainsFinalizer(&ephemeralRunner, ephemeralRunnerFinalizerName)
|
||||
if removeFinalizer {
|
||||
original.Do(ephemeralRunner.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.RemoveFinalizer(&ephemeralRunner, ephemeralRunnerFinalizerName)
|
||||
}
|
||||
if removeFinalizer {
|
||||
@@ -181,12 +181,12 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
|
||||
ephemeralRunnerFinalizerModified := !controllerutil.ContainsFinalizer(&ephemeralRunner, ephemeralRunnerFinalizerName)
|
||||
if ephemeralRunnerFinalizerModified {
|
||||
original.Do(ephemeralRunner.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.AddFinalizer(&ephemeralRunner, ephemeralRunnerFinalizerName)
|
||||
}
|
||||
ephemeralRunnerActionsFinalizerModified := !controllerutil.ContainsFinalizer(&ephemeralRunner, ephemeralRunnerActionsFinalizerName)
|
||||
if ephemeralRunnerActionsFinalizerModified {
|
||||
original.Do(ephemeralRunner.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.AddFinalizer(&ephemeralRunner, ephemeralRunnerActionsFinalizerName)
|
||||
}
|
||||
if ephemeralRunnerFinalizerModified || ephemeralRunnerActionsFinalizerModified {
|
||||
|
||||
@@ -80,7 +80,7 @@ func (r *EphemeralRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
if err := r.Get(ctx, req.NamespacedName, &ephemeralRunnerSet); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
var original once[*v1alpha1.EphemeralRunnerSet]
|
||||
original := newOnce(ephemeralRunnerSet.DeepCopy)
|
||||
|
||||
// Requested deletion does not need reconciled.
|
||||
if !ephemeralRunnerSet.DeletionTimestamp.IsZero() {
|
||||
@@ -111,7 +111,7 @@ func (r *EphemeralRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
|
||||
removeFinalizer := controllerutil.ContainsFinalizer(&ephemeralRunnerSet, EphemeralRunnerSetFinalizerName)
|
||||
if removeFinalizer {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.RemoveFinalizer(&ephemeralRunnerSet, EphemeralRunnerSetFinalizerName)
|
||||
}
|
||||
if removeFinalizer {
|
||||
@@ -130,7 +130,7 @@ func (r *EphemeralRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
// Add finalizer if not present
|
||||
addFinalizer := !controllerutil.ContainsFinalizer(&ephemeralRunnerSet, EphemeralRunnerSetFinalizerName)
|
||||
if addFinalizer {
|
||||
original.Do(ephemeralRunnerSet.DeepCopy)
|
||||
original.Do()
|
||||
controllerutil.AddFinalizer(&ephemeralRunnerSet, EphemeralRunnerSetFinalizerName)
|
||||
}
|
||||
if addFinalizer {
|
||||
@@ -538,21 +538,19 @@ func (r *EphemeralRunnerSetReconciler) reconcileEphemeralRunnerSetProxySecret(ct
|
||||
}
|
||||
|
||||
dataModified := !maps.EqualFunc(proxySecret.Data, desiredRunnerSetProxy.Data, bytes.Equal)
|
||||
desiredLabels := r.filterAndMergeLabels(proxySecret.Labels, desiredRunnerSetProxy.Labels)
|
||||
labelsModified := !maps.Equal(proxySecret.Labels, desiredLabels)
|
||||
desiredAnnotations := r.mergeAnnotations(proxySecret.Annotations, desiredRunnerSetProxy.Annotations)
|
||||
annotationsModified := !maps.Equal(proxySecret.Annotations, desiredAnnotations)
|
||||
var original once[*corev1.Secret]
|
||||
desiredLabels, labelsModified := r.mergeLabels(proxySecret.Labels, desiredRunnerSetProxy.Labels)
|
||||
desiredAnnotations, annotationsModified := r.mergeAnnotations(proxySecret.Annotations, desiredRunnerSetProxy.Annotations)
|
||||
original := newOnce(proxySecret.DeepCopy)
|
||||
if dataModified {
|
||||
original.Do(proxySecret.DeepCopy)
|
||||
original.Do()
|
||||
proxySecret.Data = desiredRunnerSetProxy.Data
|
||||
}
|
||||
if labelsModified {
|
||||
original.Do(proxySecret.DeepCopy)
|
||||
original.Do()
|
||||
proxySecret.Labels = desiredLabels
|
||||
}
|
||||
if annotationsModified {
|
||||
original.Do(proxySecret.DeepCopy)
|
||||
original.Do()
|
||||
proxySecret.Annotations = desiredAnnotations
|
||||
}
|
||||
if dataModified || labelsModified || annotationsModified {
|
||||
|
||||
@@ -1670,6 +1670,28 @@ var _ = Describe("Test EphemeralRunnerSet actionable revision cleanup", func() {
|
||||
}
|
||||
}
|
||||
|
||||
waitForCachedActionableRevision := func(controller *EphemeralRunnerSetReconciler, key types.NamespacedName, specRevision, appliedRevision int64) {
|
||||
Eventually(func(g Gomega) {
|
||||
cached := new(v1alpha1.EphemeralRunnerSet)
|
||||
g.Expect(controller.Get(ctx, key, cached)).To(Succeed())
|
||||
g.Expect(cached.Spec.ActionableRevision).To(Equal(specRevision))
|
||||
g.Expect(cached.Status.AppliedActionableRevision).To(Equal(appliedRevision))
|
||||
g.Expect(cached.Finalizers).To(ContainElement(EphemeralRunnerSetFinalizerName))
|
||||
}, ephemeralRunnerSetTestTimeout, ephemeralRunnerSetTestInterval).Should(Succeed())
|
||||
}
|
||||
|
||||
waitForCachedRunningRunners := func(controller *EphemeralRunnerSetReconciler, namespace, owner string, expected int) {
|
||||
Eventually(func(g Gomega) {
|
||||
runners := new(v1alpha1.EphemeralRunnerList)
|
||||
g.Expect(controller.List(ctx, runners, client.InNamespace(namespace), client.MatchingFields{resourceOwnerKey: owner})).To(Succeed())
|
||||
state := newEphemeralRunnersByStates(runners)
|
||||
g.Expect(state.running).To(HaveLen(expected))
|
||||
for _, runner := range state.running {
|
||||
g.Expect(runner.Status.RunnerID).NotTo(BeZero())
|
||||
}
|
||||
}, ephemeralRunnerSetTestTimeout, ephemeralRunnerSetTestInterval).Should(Succeed())
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
ctx = context.Background()
|
||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||
@@ -1904,6 +1926,9 @@ var _ = Describe("Test EphemeralRunnerSet actionable revision cleanup", func() {
|
||||
err = k8sClient.Patch(ctx, specUpdated, client.MergeFrom(current))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
waitForCachedActionableRevision(controller, request.NamespacedName, 4, 3)
|
||||
waitForCachedRunningRunners(controller, autoscalingNS.Name, ephemeralRunnerSet.Name, 1)
|
||||
|
||||
_, err = controller.Reconcile(ctx, request)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("remove failed"))
|
||||
|
||||
@@ -163,7 +163,7 @@ func (b *ResourceBuilder) newAutoscalingListener(autoscalingRunnerSet *v1alpha1.
|
||||
ConfigSecretMetadata: autoscalingRunnerSet.Spec.ListenerConfigSecretMetadata,
|
||||
}
|
||||
|
||||
labels := b.filterAndMergeLabels(autoscalingRunnerSet.Labels, map[string]string{
|
||||
labels := b.propagateLabels(autoscalingRunnerSet.Labels, map[string]string{
|
||||
LabelKeyGitHubScaleSetNamespace: autoscalingRunnerSet.Namespace,
|
||||
LabelKeyGitHubScaleSetName: autoscalingRunnerSet.Name,
|
||||
LabelKeyKubernetesPartOf: labelValueKubernetesPartOf,
|
||||
@@ -178,8 +178,8 @@ func (b *ResourceBuilder) newAutoscalingListener(autoscalingRunnerSet *v1alpha1.
|
||||
var annotations map[string]string
|
||||
|
||||
if autoscalingRunnerSet.Spec.AutoscalingListenerMetadata != nil {
|
||||
labels = b.filterAndMergeLabels(autoscalingRunnerSet.Spec.AutoscalingListenerMetadata.Labels, labels)
|
||||
annotations = b.mergeAnnotations(autoscalingRunnerSet.Spec.AutoscalingListenerMetadata.Annotations, annotations)
|
||||
labels, _ = b.mergeLabels(autoscalingRunnerSet.Spec.AutoscalingListenerMetadata.Labels, labels)
|
||||
annotations, _ = b.mergeAnnotations(autoscalingRunnerSet.Spec.AutoscalingListenerMetadata.Annotations, annotations)
|
||||
}
|
||||
|
||||
autoscalingListener := &v1alpha1.AutoscalingListener{
|
||||
@@ -285,7 +285,7 @@ func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha
|
||||
|
||||
var labels map[string]string
|
||||
if autoscalingListener.Spec.ConfigSecretMetadata != nil && len(autoscalingListener.Spec.ConfigSecretMetadata.Labels) > 0 {
|
||||
labels = b.filterAndMergeLabels(autoscalingListener.Spec.ConfigSecretMetadata.Labels, nil)
|
||||
labels = autoscalingListener.Spec.ConfigSecretMetadata.Labels
|
||||
}
|
||||
|
||||
annotations := make(map[string]string)
|
||||
@@ -307,6 +307,7 @@ func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha
|
||||
Data: map[string][]byte{
|
||||
"config.json": buf.Bytes(),
|
||||
},
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
}
|
||||
|
||||
if err := b.setControllerReference(autoscalingListener, desiredSecret); err != nil {
|
||||
@@ -593,27 +594,29 @@ func (b *ResourceBuilder) newScaleSetListenerServiceAccount(autoscalingListener
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
labels := b.propagateLabels(autoscalingListener.Labels, map[string]string{
|
||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||
LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName,
|
||||
})
|
||||
annotations := make(map[string]string)
|
||||
|
||||
if autoscalingListener.Spec.ServiceAccountMetadata != nil {
|
||||
labels, _ = b.mergeLabels(autoscalingListener.Spec.ServiceAccountMetadata.Labels, labels)
|
||||
annotations, _ = b.mergeAnnotations(autoscalingListener.Spec.ServiceAccountMetadata.Annotations, annotations)
|
||||
}
|
||||
|
||||
base := &corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1.SchemeGroupVersion.String(),
|
||||
Kind: "ServiceAccount",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: autoscalingListener.Name,
|
||||
Namespace: autoscalingListener.Namespace,
|
||||
Labels: b.filterAndMergeLabels(autoscalingListener.Labels, map[string]string{
|
||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||
LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName,
|
||||
}),
|
||||
Annotations: make(map[string]string),
|
||||
Name: autoscalingListener.Name,
|
||||
Namespace: autoscalingListener.Namespace,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
},
|
||||
}
|
||||
|
||||
if autoscalingListener.Spec.ServiceAccountMetadata != nil {
|
||||
base.Labels = b.filterAndMergeLabels(autoscalingListener.Spec.ServiceAccountMetadata.Labels, base.Labels)
|
||||
base.Annotations = b.mergeAnnotations(autoscalingListener.Spec.ServiceAccountMetadata.Annotations, base.Annotations)
|
||||
}
|
||||
|
||||
if err := b.setControllerReference(autoscalingListener, base); err != nil {
|
||||
return nil, fmt.Errorf("failed to set controller reference for listener service account: %w", err)
|
||||
}
|
||||
@@ -633,7 +636,7 @@ func (b *ResourceBuilder) newScaleSetListenerRole(autoscalingListener *v1alpha1.
|
||||
return cached
|
||||
}
|
||||
|
||||
labels := b.filterAndMergeLabels(autoscalingListener.Labels, map[string]string{
|
||||
labels := b.propagateLabels(autoscalingListener.Labels, map[string]string{
|
||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||
LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName,
|
||||
labelKeyListenerNamespace: autoscalingListener.Namespace,
|
||||
@@ -642,8 +645,8 @@ func (b *ResourceBuilder) newScaleSetListenerRole(autoscalingListener *v1alpha1.
|
||||
|
||||
annotations := make(map[string]string)
|
||||
if autoscalingListener.Spec.RoleMetadata != nil {
|
||||
labels = b.filterAndMergeLabels(autoscalingListener.Spec.RoleMetadata.Labels, labels)
|
||||
annotations = b.mergeAnnotations(autoscalingListener.Spec.RoleMetadata.Annotations, nil)
|
||||
labels, _ = b.mergeLabels(autoscalingListener.Spec.RoleMetadata.Labels, labels)
|
||||
annotations = autoscalingListener.Spec.RoleMetadata.Annotations
|
||||
}
|
||||
|
||||
newRole := &rbacv1.Role{
|
||||
@@ -677,8 +680,9 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1
|
||||
}
|
||||
|
||||
roleRef := rbacv1.RoleRef{
|
||||
Kind: "Role",
|
||||
Name: listenerRole.Name,
|
||||
APIGroup: rbacv1.GroupName,
|
||||
Kind: "Role",
|
||||
Name: listenerRole.Name,
|
||||
}
|
||||
|
||||
subjects := []rbacv1.Subject{
|
||||
@@ -689,7 +693,7 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1
|
||||
},
|
||||
}
|
||||
|
||||
labels := b.filterAndMergeLabels(autoscalingListener.Labels, map[string]string{
|
||||
labels := b.propagateLabels(autoscalingListener.Labels, map[string]string{
|
||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||
LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName,
|
||||
labelKeyListenerNamespace: autoscalingListener.Namespace,
|
||||
@@ -698,7 +702,7 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1
|
||||
|
||||
annotations := make(map[string]string)
|
||||
if autoscalingListener.Spec.RoleBindingMetadata != nil {
|
||||
labels = b.filterAndMergeLabels(autoscalingListener.Spec.RoleBindingMetadata.Labels, labels)
|
||||
labels, _ = b.mergeLabels(autoscalingListener.Spec.RoleBindingMetadata.Labels, labels)
|
||||
annotations = autoscalingListener.Spec.RoleBindingMetadata.Annotations
|
||||
}
|
||||
|
||||
@@ -753,7 +757,7 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A
|
||||
EphemeralRunnerMetadata: autoscalingRunnerSet.Spec.EphemeralRunnerMetadata,
|
||||
}
|
||||
|
||||
labels := b.filterAndMergeLabels(autoscalingRunnerSet.Labels, map[string]string{
|
||||
labels := b.propagateLabels(autoscalingRunnerSet.Labels, map[string]string{
|
||||
LabelKeyKubernetesPartOf: labelValueKubernetesPartOf,
|
||||
LabelKeyKubernetesComponent: "runner-set",
|
||||
LabelKeyKubernetesVersion: autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion],
|
||||
@@ -771,8 +775,8 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A
|
||||
}
|
||||
|
||||
if autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata != nil {
|
||||
labels = b.filterAndMergeLabels(autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata.Labels, labels)
|
||||
annotations = b.mergeAnnotations(autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata.Annotations, annotations)
|
||||
labels, _ = b.mergeLabels(autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata.Labels, labels)
|
||||
annotations, _ = b.mergeAnnotations(autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata.Annotations, annotations)
|
||||
}
|
||||
|
||||
newEphemeralRunnerSet := &v1alpha1.EphemeralRunnerSet{
|
||||
@@ -809,6 +813,7 @@ func (b *ResourceBuilder) newAutoscalingListenerProxySecret(autoscalingListener
|
||||
Annotations: make(map[string]string, 1),
|
||||
},
|
||||
Data: data,
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
}
|
||||
|
||||
if err := b.setControllerReference(autoscalingListener, newProxySecret); err != nil {
|
||||
@@ -828,8 +833,8 @@ func (b *ResourceBuilder) newEphemeralRunner(ephemeralRunnerSet *v1alpha1.Epheme
|
||||
annotations[AnnotationKeyPatchID] = strconv.Itoa(ephemeralRunnerSet.Spec.PatchID)
|
||||
|
||||
if ephemeralRunnerSet.Spec.EphemeralRunnerMetadata != nil {
|
||||
labels = b.filterAndMergeLabels(ephemeralRunnerSet.Spec.EphemeralRunnerMetadata.Labels, labels)
|
||||
annotations = b.mergeAnnotations(ephemeralRunnerSet.Spec.EphemeralRunnerMetadata.Annotations, annotations)
|
||||
labels, _ = b.mergeLabels(ephemeralRunnerSet.Spec.EphemeralRunnerMetadata.Labels, labels)
|
||||
annotations, _ = b.mergeAnnotations(ephemeralRunnerSet.Spec.EphemeralRunnerMetadata.Annotations, annotations)
|
||||
}
|
||||
|
||||
ephemeralRunner := &v1alpha1.EphemeralRunner{
|
||||
@@ -925,7 +930,7 @@ func (b *ResourceBuilder) newEphemeralRunnerJitSecret(ephemeralRunner *v1alpha1.
|
||||
)
|
||||
|
||||
if ephemeralRunner.Spec.EphemeralRunnerConfigSecretMetadata != nil {
|
||||
labels = b.filterAndMergeLabels(ephemeralRunner.Spec.EphemeralRunnerConfigSecretMetadata.Labels, nil)
|
||||
labels = ephemeralRunner.Spec.EphemeralRunnerConfigSecretMetadata.Labels
|
||||
annotations = ephemeralRunner.Spec.EphemeralRunnerConfigSecretMetadata.Annotations
|
||||
}
|
||||
|
||||
@@ -1051,39 +1056,67 @@ func trimLabelValue(val string) string {
|
||||
return strings.Trim(val, "-_.")
|
||||
}
|
||||
|
||||
func (b *ResourceBuilder) filterAndMergeLabels(base, overwrite map[string]string) map[string]string {
|
||||
func (b *ResourceBuilder) shouldExcludePropagatedLabel(k, _ string) bool {
|
||||
for _, prefix := range b.ExcludeLabelPropagationPrefixes {
|
||||
if strings.HasPrefix(k, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// propagateLabels is responsible for filtering labels during propagation.
|
||||
// It only makes sense when we are creating the resource derived from some other resource.
|
||||
// Since the desired resource is cached, then we don't need to call this method every time.
|
||||
func (b *ResourceBuilder) propagateLabels(base, overwrite map[string]string) map[string]string {
|
||||
if base == nil && overwrite == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
mergedLabels := make(map[string]string, len(base))
|
||||
base:
|
||||
labels := make(map[string]string, len(base)+len(overwrite))
|
||||
for k, v := range base {
|
||||
for _, prefix := range b.ExcludeLabelPropagationPrefixes {
|
||||
if strings.HasPrefix(k, prefix) {
|
||||
continue base
|
||||
}
|
||||
if b.shouldExcludePropagatedLabel(k, v) {
|
||||
continue
|
||||
}
|
||||
mergedLabels[k] = v
|
||||
labels[k] = v
|
||||
}
|
||||
maps.Copy(labels, overwrite)
|
||||
|
||||
overwrite:
|
||||
for k, v := range overwrite {
|
||||
for _, prefix := range b.ExcludeLabelPropagationPrefixes {
|
||||
if strings.HasPrefix(k, prefix) {
|
||||
continue overwrite
|
||||
}
|
||||
}
|
||||
mergedLabels[k] = v
|
||||
}
|
||||
|
||||
return mergedLabels
|
||||
}
|
||||
|
||||
func (b *ResourceBuilder) mergeAnnotations(base, overwrite map[string]string) map[string]string {
|
||||
if base == nil && overwrite == nil {
|
||||
if len(labels) == 0 {
|
||||
return nil
|
||||
}
|
||||
maps.Copy(base, overwrite)
|
||||
return base
|
||||
return labels
|
||||
}
|
||||
|
||||
func (b *ResourceBuilder) mergeLabels(base, overwrite map[string]string) (map[string]string, bool) {
|
||||
return mergeMaps(base, overwrite)
|
||||
}
|
||||
|
||||
func (b *ResourceBuilder) mergeAnnotations(base, overwrite map[string]string) (map[string]string, bool) {
|
||||
return mergeMaps(base, overwrite)
|
||||
}
|
||||
|
||||
func mergeMaps[M ~map[K]V, K comparable, V comparable](base M, overwrite M) (M, bool) {
|
||||
if len(overwrite) == 0 {
|
||||
return base, false
|
||||
}
|
||||
|
||||
if containsMapEntries(base, overwrite) {
|
||||
return base, false
|
||||
}
|
||||
|
||||
merged := make(M, len(base)+len(overwrite))
|
||||
maps.Copy(merged, base)
|
||||
maps.Copy(merged, overwrite)
|
||||
return merged, true
|
||||
}
|
||||
|
||||
func containsMapEntries[M ~map[K]V, K comparable, V comparable](base M, entries M) bool {
|
||||
for k, v := range entries {
|
||||
current, ok := base[k]
|
||||
if !ok || current != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
@@ -157,6 +158,7 @@ func TestMetadataPropagation(t *testing.T) {
|
||||
assert.Equal(t, "listener-role-annotation", listenerRole.Annotations["test.com/listener-role-annotation"])
|
||||
|
||||
listenerRoleBinding := b.newScaleSetListenerRoleBinding(listener, listenerRole, listenerServiceAccount)
|
||||
assert.Equal(t, rbacv1.GroupName, listenerRoleBinding.RoleRef.APIGroup)
|
||||
assert.Equal(t, "listener-role-binding-label", listenerRoleBinding.Labels["test.com/listener-role-binding-label"])
|
||||
assert.Equal(t, "listener-role-binding-annotation", listenerRoleBinding.Annotations["test.com/listener-role-binding-annotation"])
|
||||
|
||||
@@ -231,6 +233,75 @@ func TestEphemeralRunnerSetProxySecretMetadata(t *testing.T) {
|
||||
assert.NotContains(t, proxySecret.Annotations, "actions.github.com/integrity-hash")
|
||||
}
|
||||
|
||||
func TestMergeMaps(t *testing.T) {
|
||||
t.Run("equal overwrite is not modified", func(t *testing.T) {
|
||||
base := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
overwrite := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
|
||||
merged, modified := mergeMaps(base, overwrite)
|
||||
|
||||
require.False(t, modified)
|
||||
merged["a"] = "changed"
|
||||
assert.Equal(t, "changed", base["a"])
|
||||
})
|
||||
|
||||
t.Run("base superset is not modified", func(t *testing.T) {
|
||||
base := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
"extra": "base-only",
|
||||
}
|
||||
overwrite := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
|
||||
merged, modified := mergeMaps(base, overwrite)
|
||||
|
||||
require.False(t, modified)
|
||||
merged["a"] = "changed"
|
||||
assert.Equal(t, "changed", base["a"])
|
||||
})
|
||||
|
||||
t.Run("missing overwrite key is modified", func(t *testing.T) {
|
||||
base := map[string]string{
|
||||
"a": "1",
|
||||
}
|
||||
overwrite := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
|
||||
merged, modified := mergeMaps(base, overwrite)
|
||||
|
||||
require.True(t, modified)
|
||||
assert.Equal(t, map[string]string{"a": "1", "b": "2"}, merged)
|
||||
assert.NotContains(t, base, "b")
|
||||
})
|
||||
|
||||
t.Run("different overwrite value is modified", func(t *testing.T) {
|
||||
base := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
overwrite := map[string]string{
|
||||
"a": "updated",
|
||||
}
|
||||
|
||||
merged, modified := mergeMaps(base, overwrite)
|
||||
|
||||
require.True(t, modified)
|
||||
assert.Equal(t, map[string]string{"a": "updated", "b": "2"}, merged)
|
||||
assert.Equal(t, "1", base["a"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGitHubURLTrimLabelValues(t *testing.T) {
|
||||
enterprise := strings.Repeat("a", 64)
|
||||
organization := strings.Repeat("b", 64)
|
||||
|
||||
@@ -16,21 +16,31 @@ func FilterLabels(labels map[string]string, filter string) map[string]string {
|
||||
|
||||
type once[T client.Object] struct {
|
||||
value T
|
||||
fn func(T) *T
|
||||
fn func() T
|
||||
done bool
|
||||
}
|
||||
|
||||
func (o *once[T]) Do(f func() T) T {
|
||||
func newOnce[T client.Object](fn func() T) *once[T] {
|
||||
return &once[T]{
|
||||
fn: fn,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *once[T]) Do() T {
|
||||
if !o.done {
|
||||
o.value = f()
|
||||
o.value = o.fn()
|
||||
o.done = true
|
||||
}
|
||||
return o.value
|
||||
}
|
||||
|
||||
func (o *once[T]) Get() T {
|
||||
if !o.done {
|
||||
if !o.Called() {
|
||||
panic("not done")
|
||||
}
|
||||
return o.value
|
||||
}
|
||||
|
||||
func (o *once[T]) Called() bool {
|
||||
return o.done
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user