From aa2b602050974315e2c1e8973ade6fdf8c83e476 Mon Sep 17 00:00:00 2001 From: Ondra Kupka Date: Mon, 17 Aug 2026 15:26:28 +0200 Subject: [PATCH 1/3] go mod vendor --- go.mod | 3 + go.sum | 4 +- .../pkg/apps/deployment/progressing.go | 65 ++++++ .../openshift/library-go/pkg/crypto/crypto.go | 51 +++++ .../apiserver/controller/workload/workload.go | 54 ++--- .../controllerset/apiservercontrollerset.go | 52 ++--- .../pkg/operator/encryption/controllers.go | 3 +- .../encryption/controllers/key_controller.go | 81 +++++--- .../controllers/kms_preflight_controller.go | 36 +++- .../kms/encryption_status_provider.go | 2 +- .../encryption/statemachine/transition.go | 6 +- .../test/library/encryption/errors.go | 2 +- .../test/library/encryption/helpers.go | 30 ++- .../test/library/encryption/kms/scenarios.go | 195 ++++++++++++++++++ .../test/library/encryption/perf_helpers.go | 4 + vendor/modules.txt | 3 +- 16 files changed, 478 insertions(+), 113 deletions(-) create mode 100644 vendor/github.com/openshift/library-go/pkg/apps/deployment/progressing.go create mode 100644 vendor/github.com/openshift/library-go/test/library/encryption/kms/scenarios.go diff --git a/go.mod b/go.mod index 4c7e799429..c0fc0a2c09 100644 --- a/go.mod +++ b/go.mod @@ -143,3 +143,6 @@ require ( ) replace github.com/onsi/ginkgo/v2 => github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20251001123353-fd5b1fb35db1 + +// branch: pr2-progressing-rework +replace github.com/openshift/library-go => github.com/tchap/library-go v0.0.0-20260817131047-edce4e0d0c2a diff --git a/go.sum b/go.sum index 94128dffe8..72be841a4e 100644 --- a/go.sum +++ b/go.sum @@ -175,8 +175,6 @@ github.com/openshift/build-machinery-go v0.0.0-20251023084048-5d77c1a5e5af h1:Ui github.com/openshift/build-machinery-go v0.0.0-20251023084048-5d77c1a5e5af/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= github.com/openshift/client-go v0.0.0-20260806041845-b74fb348f1e7 h1:Lphm0uMAyM26ibbOca0+dg7uLz7GmmrIdeWjzOh5R/U= github.com/openshift/client-go v0.0.0-20260806041845-b74fb348f1e7/go.mod h1:u08LcpI8Hq3IpelQLbciGRa/P158cE/O3uQe2Bt3Roo= -github.com/openshift/library-go v0.0.0-20260806124457-39539af5eb2c h1:giNfw2fwyJS7yJNlFEfKvAVcMHohRdBZJ8E9zJ8FsSo= -github.com/openshift/library-go v0.0.0-20260806124457-39539af5eb2c/go.mod h1:IrZbEK+wVUMEd+aXzYR2DCCh0p5IaQ7DvycYGP7qIYM= github.com/openshift/multi-operator-manager v0.0.0-20241205181422-20aa3906b99d h1:Rzx23P63JFNNz5D23ubhC0FCN5rK8CeJhKcq5QKcdyU= github.com/openshift/multi-operator-manager v0.0.0-20241205181422-20aa3906b99d/go.mod h1:iVi9Bopa5cLhjG5ie9DoZVVqkH8BGb1FQVTtecOLn4I= github.com/openshift/oauth-apiserver v0.0.0-20260520145010-97a820bd5412 h1:oDB0GmUXLp8y85fWz+LGRE0hM5JqbXTfNPi5GjEqiX0= @@ -231,6 +229,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tchap/library-go v0.0.0-20260817131047-edce4e0d0c2a h1:wqtJsxkJftFRPn0Uh3I3BEPPbKv7SvFWmkCzw8pPrAY= +github.com/tchap/library-go v0.0.0-20260817131047-edce4e0d0c2a/go.mod h1:IrZbEK+wVUMEd+aXzYR2DCCh0p5IaQ7DvycYGP7qIYM= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= diff --git a/vendor/github.com/openshift/library-go/pkg/apps/deployment/progressing.go b/vendor/github.com/openshift/library-go/pkg/apps/deployment/progressing.go new file mode 100644 index 0000000000..d8e8f0cedb --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/apps/deployment/progressing.go @@ -0,0 +1,65 @@ +package deployment + +import ( + "fmt" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + + operatorv1 "github.com/openshift/api/operator/v1" +) + +// DeploymentProgressingCondition computes an operator Progressing condition from +// the deployment's own status conditions and replica counts. +func DeploymentProgressingCondition(deployment *appsv1.Deployment) operatorv1.OperatorCondition { + desiredReplicas := ptr.Deref(deployment.Spec.Replicas, 1) + timedOutMessage, timedOut := HasDeploymentTimedOutProgressing(deployment.Status) + + switch { + case timedOut: + return operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeProgressing, + Status: operatorv1.ConditionFalse, + Reason: "ProgressDeadlineExceeded", + Message: fmt.Sprintf("deployment/%s.%s has timed out progressing: %s", deployment.Name, deployment.Namespace, timedOutMessage), + } + + case !HasDeploymentProgressed(deployment.Status): + return operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeProgressing, + Status: operatorv1.ConditionTrue, + Reason: "PodsUpdating", + Message: fmt.Sprintf("deployment/%s.%s: %d/%d pods have been updated to the latest revision and %d/%d pods are available", deployment.Name, deployment.Namespace, deployment.Status.UpdatedReplicas, desiredReplicas, deployment.Status.AvailableReplicas, desiredReplicas), + } + + default: + return operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeProgressing, + Status: operatorv1.ConditionFalse, + Reason: "AsExpected", + } + } +} + +// HasDeploymentProgressed returns true if the deployment reports NewReplicaSetAvailable +// via the DeploymentProgressing condition. +func HasDeploymentProgressed(status appsv1.DeploymentStatus) bool { + for _, cond := range status.Conditions { + if cond.Type == appsv1.DeploymentProgressing { + return cond.Status == corev1.ConditionTrue && cond.Reason == "NewReplicaSetAvailable" + } + } + return false +} + +// HasDeploymentTimedOutProgressing returns true if the deployment reports ProgressDeadlineExceeded. +// The function returns the Progressing condition message as the first return value. +func HasDeploymentTimedOutProgressing(status appsv1.DeploymentStatus) (string, bool) { + for _, cond := range status.Conditions { + if cond.Type == appsv1.DeploymentProgressing { + return cond.Message, cond.Status == corev1.ConditionFalse && cond.Reason == "ProgressDeadlineExceeded" + } + } + return "", false +} diff --git a/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go b/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go index c5ab62e6b7..58d08d28ba 100644 --- a/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go +++ b/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go @@ -20,8 +20,10 @@ import ( "os" "path/filepath" "reflect" + "slices" "sort" "strconv" + "strings" "sync" "time" @@ -211,6 +213,17 @@ var ciphersUnsupportedByGo = map[string]string{ "AES256-SHA256": "TLS_RSA_WITH_AES_256_CBC_SHA256", } +// tlsGroupToCurveID maps OpenShift API TLSGroup values to Go's tls.CurveID. +var tlsGroupToCurveID = map[configv1.TLSGroup]tls.CurveID{ + configv1.TLSGroupX25519: tls.X25519, + configv1.TLSGroupSecP256r1: tls.CurveP256, + configv1.TLSGroupSecP384r1: tls.CurveP384, + configv1.TLSGroupSecP521r1: tls.CurveP521, + configv1.TLSGroupX25519MLKEM768: tls.X25519MLKEM768, + configv1.TLSGroupSecP256r1MLKEM768: tls.SecP256r1MLKEM768, + configv1.TLSGroupSecP384r1MLKEM1024: tls.SecP384r1MLKEM1024, +} + // CipherSuitesToNamesOrDie given a list of cipher suites as ints, return their readable names func CipherSuitesToNamesOrDie(intVals []uint16) []string { ret := []string{} @@ -356,6 +369,44 @@ func OpenSSLToIANACipherSuites(ciphers []string) []string { return ianaCiphers } +// TLSGroupToCurveID returns the Go tls.CurveID for an OpenShift API TLSGroup +// constant, or (0, false) if the group is not recognized. +func TLSGroupToCurveID(group configv1.TLSGroup) (tls.CurveID, bool) { + id, ok := tlsGroupToCurveID[group] + return id, ok +} + +// TLSGroupsToCurveIDs converts a slice of TLSGroup values to their tls.CurveID +// codes. Returns the mapped curve IDs and a list of unrecognized groups. +// Unrecognized groups are silently filtered — callers should log warnings. +func TLSGroupsToCurveIDs(groups []configv1.TLSGroup) ([]tls.CurveID, []configv1.TLSGroup) { + var curves []tls.CurveID + var unrecognized []configv1.TLSGroup + + for _, group := range groups { + id, ok := TLSGroupToCurveID(group) + if !ok { + unrecognized = append(unrecognized, group) + continue + } + curves = append(curves, id) + } + + return curves, unrecognized +} + +// ValidTLSGroups returns the recognized TLS group names, sorted alphabetically. +func ValidTLSGroups() []configv1.TLSGroup { + groups := make([]configv1.TLSGroup, 0, len(tlsGroupToCurveID)) + for g := range tlsGroupToCurveID { + groups = append(groups, g) + } + slices.SortFunc(groups, func(a, b configv1.TLSGroup) int { + return strings.Compare(string(a), string(b)) + }) + return groups +} + type TLSCertificateConfig struct { Certs []*x509.Certificate Key crypto.PrivateKey diff --git a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go index 51f38dc97d..f83e6646d2 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go @@ -299,42 +299,22 @@ func (c *Controller) updateOperatorStatus(ctx context.Context, previousStatus *o WithReason("AsExpected") } - desiredReplicas := ptr.Deref(workload.Spec.Replicas, 1) - - // If the workload is up to date, then we are no longer progressing - workloadAtHighestGeneration := workload.ObjectMeta.Generation == workload.Status.ObservedGeneration - // Update is done when all pods have been updated to the latest revision - // and the deployment controller has reported NewReplicaSetAvailable - workloadIsBeingUpdated := !workloadAtHighestGeneration || !hasDeploymentProgressed(workload.Status) - workloadIsBeingUpdatedTooLong := v1helpers.IsUpdatingTooLong(previousStatus, *deploymentProgressingCondition.Type) - if !workloadAtHighestGeneration { - deploymentProgressingCondition = deploymentProgressingCondition. - WithStatus(operatorv1.ConditionTrue). - WithReason("NewGeneration"). - WithMessage(fmt.Sprintf("deployment/%s.%s: observed generation is %d, desired generation is %d.", workload.Name, c.targetNamespace, workload.Status.ObservedGeneration, workload.ObjectMeta.Generation)) - } else if workloadIsBeingUpdated { - deploymentProgressingCondition = deploymentProgressingCondition. - WithStatus(operatorv1.ConditionTrue). - WithReason("PodsUpdating"). - WithMessage(fmt.Sprintf("deployment/%s.%s: %d/%d pods have been updated to the latest generation and %d/%d pods are available", workload.Name, c.targetNamespace, workload.Status.UpdatedReplicas, desiredReplicas, workload.Status.AvailableReplicas, desiredReplicas)) - } else { - // Terminating pods don't account for any of the other status fields but - // still can exist in a state when they are accepting connections and would - // contribute to unexpected behavior when we report Progressing=False. - // The case of too many pods might occur for example if `TerminationGracePeriodSeconds` is set - // - // The workload should ensure this does not happen by using for example EnsureAtMostOnePodPerNode - // so that the old pods terminate before the new ones are started. - deploymentProgressingCondition = deploymentProgressingCondition. - WithStatus(operatorv1.ConditionFalse). - WithReason("AsExpected") - } + progressingCond := deployment.DeploymentProgressingCondition(workload) + deploymentProgressingCondition = deploymentProgressingCondition. + WithStatus(progressingCond.Status). + WithReason(progressingCond.Reason). + WithMessage(progressingCond.Message) // During a rollout the default maxSurge (25%) will allow the available // replicas to temporarily exceed the desired replica count. If this were // to occur, the operator should not report degraded. + _, workloadIsBeingUpdatedTooLong := deployment.HasDeploymentTimedOutProgressing(workload.Status) + workloadIsBeingUpdated := !deployment.HasDeploymentProgressed(workload.Status) && !workloadIsBeingUpdatedTooLong + + desiredReplicas := ptr.Deref(workload.Spec.Replicas, 1) workloadHasAllPodsAvailable := workload.Status.AvailableReplicas >= desiredReplicas - if !workloadHasAllPodsAvailable && (!workloadIsBeingUpdated || workloadIsBeingUpdatedTooLong) { + + if !workloadHasAllPodsAvailable && !workloadIsBeingUpdated { numNonAvailablePods := desiredReplicas - workload.Status.AvailableReplicas deploymentDegradedCondition = deploymentDegradedCondition. WithStatus(operatorv1.ConditionTrue). @@ -354,6 +334,7 @@ func (c *Controller) updateOperatorStatus(ctx context.Context, previousStatus *o // if the deployment is all available and at the expected generation, then update the version to the latest // when we update, the image pull spec should immediately be different, which should immediately cause a deployment rollout // which should immediately result in a deployment generation diff, which should cause this block to be skipped until it is ready. + workloadAtHighestGeneration := workload.ObjectMeta.Generation == workload.Status.ObservedGeneration workloadHasAllPodsUpdated := workload.Status.UpdatedReplicas == desiredReplicas if workloadAtHighestGeneration && workloadHasAllPodsAvailable && workloadHasAllPodsUpdated && operatorConfigAtHighestGeneration { c.versionRecorder.SetVersion(c.constructOperandNameFor(workload.Name), c.targetOperandVersion) @@ -373,17 +354,6 @@ func (c *Controller) constructOperandNameFor(name string) string { return name } -// hasDeploymentProgressed returns true if the deployment reports NewReplicaSetAvailable -// via the DeploymentProgressing condition -func hasDeploymentProgressed(status appsv1.DeploymentStatus) bool { - for _, cond := range status.Conditions { - if cond.Type == appsv1.DeploymentProgressing { - return cond.Status == corev1.ConditionTrue && cond.Reason == "NewReplicaSetAvailable" - } - } - return false -} - // EnsureAtMostOnePodPerNode updates the deployment spec to prevent more than // one pod of a given replicaset from landing on a node. It accomplishes this // by adding a label on the template and updates the pod anti-affinity term to include that label. diff --git a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controllerset/apiservercontrollerset.go b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controllerset/apiservercontrollerset.go index 323303e56e..fe55e45971 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controllerset/apiservercontrollerset.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controllerset/apiservercontrollerset.go @@ -372,24 +372,26 @@ func (cs *APIServerControllerSet) WithEncryptionControllers( resourceSyncer *resourcesynccontroller.ResourceSyncController, encryptionStatusProvider kms.EncryptionStatusProvider, preflightDeployer controllers.KMSPreflightDeployer, + encryptionConfigurationComputer controllers.EncryptionConfigurationComputer, ) *APIServerControllerSet { cs.encryptionControllers = encryptionControllerBuilder{ operatorClient: cs.operatorClient, eventRecorder: cs.eventRecorder, - component: component, - provider: provider, - deployer: deployer, - migrator: migrator, - apiServerClient: apiServerClient, - apiServerInformer: apiServerInformer, - kubeInformersForNamespaces: kubeInformersForNamespaces, - secretsClient: secretsClient, - configMapClient: configMapClient, - resourceSyncer: resourceSyncer, - encryptionStatusProvider: encryptionStatusProvider, - preflightDeployer: preflightDeployer, + component: component, + provider: provider, + deployer: deployer, + migrator: migrator, + apiServerClient: apiServerClient, + apiServerInformer: apiServerInformer, + kubeInformersForNamespaces: kubeInformersForNamespaces, + secretsClient: secretsClient, + configMapClient: configMapClient, + resourceSyncer: resourceSyncer, + encryptionStatusProvider: encryptionStatusProvider, + preflightDeployer: preflightDeployer, + encryptionConfigurationComputer: encryptionConfigurationComputer, } return cs @@ -487,18 +489,19 @@ type encryptionControllerBuilder struct { operatorClient v1helpers.OperatorClient eventRecorder events.Recorder - component string - provider controllers.Provider - deployer statemachine.Deployer - migrator migrators.Migrator - secretsClient corev1.SecretsGetter - configMapClient corev1.ConfigMapsGetter - apiServerClient configv1client.APIServerInterface - apiServerInformer configv1informers.APIServerInformer - kubeInformersForNamespaces v1helpers.KubeInformersForNamespaces - resourceSyncer *resourcesynccontroller.ResourceSyncController - encryptionStatusProvider kms.EncryptionStatusProvider - preflightDeployer controllers.KMSPreflightDeployer + component string + provider controllers.Provider + deployer statemachine.Deployer + migrator migrators.Migrator + secretsClient corev1.SecretsGetter + configMapClient corev1.ConfigMapsGetter + apiServerClient configv1client.APIServerInterface + apiServerInformer configv1informers.APIServerInformer + kubeInformersForNamespaces v1helpers.KubeInformersForNamespaces + resourceSyncer *resourcesynccontroller.ResourceSyncController + encryptionStatusProvider kms.EncryptionStatusProvider + preflightDeployer controllers.KMSPreflightDeployer + encryptionConfigurationComputer controllers.EncryptionConfigurationComputer unsupportedConfigPrefix []string } @@ -524,6 +527,7 @@ func (e *encryptionControllerBuilder) build() []controllerWrapper { e.resourceSyncer, e.encryptionStatusProvider, e.preflightDeployer, + e.encryptionConfigurationComputer, ) if err != nil { e.creationError = err diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers.go index 3b876b76d4..748ac21e0d 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers.go @@ -40,6 +40,7 @@ func NewControllers( resourceSyncer *resourcesynccontroller.ResourceSyncController, encryptionStatusProvider kms.EncryptionStatusProvider, preflightDeployer controllers.KMSPreflightDeployer, + encryptionConfigurationComputer controllers.EncryptionConfigurationComputer, ) (Controllers, error) { // avoid using the CachedSecretGetter as we need strong guarantees that our encryptionSecretSelector works // otherwise we could see secrets from a different component (which will break our keyID invariants) @@ -136,9 +137,9 @@ func NewControllers( provider, encryptionEnabledChecker.PreconditionFulfilled, preflightDeployer, + encryptionConfigurationComputer, operatorClient, apiServerClient, - apiServerInformer, secretsClient, configMapClient, encryptionStatusProvider, diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go index 6f75f6d075..f6365c0c2a 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go @@ -184,7 +184,7 @@ func (c *keyController) sync(ctx context.Context, syncCtx factory.SyncContext) ( } func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext factory.SyncContext, encryptedGRs []schema.GroupResource) error { - currentMode, externalReason, apiEncryptionConfiguration, err := c.getCurrentModeReasonAndEncryptionConfig(ctx) + currentMode, externalReason, apiEncryptionConfiguration, err := getCurrentModeReasonAndEncryptionConfig(ctx, c.apiServerClient, c.operatorClient, c.unsupportedConfigPrefix) if err != nil { return err } @@ -269,7 +269,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact return c.validateExistingSecret(ctx, keySecret, newKeyID) } if createErr != nil { - syncContext.Recorder().Warningf("EncryptionKeyCreateFailed", "Secret %q failed to create: %v", keySecret.Name, err) + syncContext.Recorder().Warningf("EncryptionKeyCreateFailed", "Secret %q failed to create: %v", keySecret.Name, createErr) return createErr } @@ -331,39 +331,28 @@ func (c *keyController) generateKeySecret(ctx context.Context, keyID uint64, cur // Fetch the referenced Secret and ConfigMap, copying their data into the // key state. The fetched objects are reused by prefetchedKMSConfigHasherResourceProvider // to compute the config hash without a second API round-trip. - var refSecret *corev1.Secret - if secretName, expectedKeys, err := desiredProviderCfg.referencedSecretName(); err != nil { + refSecret, refCM, err := fetchReferencedResources(ctx, desiredProviderCfg, c.secretClient, c.configMapClient, openshiftConfigNS) + if err != nil { return nil, false, err - } else if len(secretName) > 0 { - refSecret, err = c.secretClient.Secrets(openshiftConfigNS).Get(ctx, secretName, metav1.GetOptions{}) + } + if refSecret != nil { + secretName, expectedKeys, err := desiredProviderCfg.referencedSecretName() if err != nil { - return nil, false, fmt.Errorf("failed to get secret %s in %s: %w", secretName, openshiftConfigNS, err) + return nil, false, err } for _, key := range expectedKeys { - v, ok := refSecret.Data[key] - if !ok { - return nil, false, fmt.Errorf("secret %s in %s is missing required key %q", secretName, openshiftConfigNS, key) - } - if err := ks.KMS.PluginSecretData.Set(secretName, key, v); err != nil { + if err := ks.KMS.PluginSecretData.Set(secretName, key, refSecret.Data[key]); err != nil { return nil, false, err } } } - - var refCM *corev1.ConfigMap - if cmName, expectedKeys, err := desiredProviderCfg.referencedConfigMapName(); err != nil { - return nil, false, err - } else if len(cmName) > 0 { - refCM, err = c.configMapClient.ConfigMaps(openshiftConfigNS).Get(ctx, cmName, metav1.GetOptions{}) + if refCM != nil { + cmName, expectedKeys, err := desiredProviderCfg.referencedConfigMapName() if err != nil { - return nil, false, fmt.Errorf("failed to get configmap %s in %s: %w", cmName, openshiftConfigNS, err) + return nil, false, err } for _, key := range expectedKeys { - v, ok := refCM.Data[key] - if !ok { - return nil, false, fmt.Errorf("configmap %s in %s is missing required key %q", cmName, openshiftConfigNS, key) - } - if err := ks.KMS.PluginConfigMapData.Set(cmName, key, []byte(v)); err != nil { + if err := ks.KMS.PluginConfigMapData.Set(cmName, key, []byte(refCM.Data[key])); err != nil { return nil, false, err } } @@ -394,18 +383,54 @@ func (c *keyController) generateKeySecret(ctx context.Context, keyID uint64, cur return secret, true, nil } -func (c *keyController) getCurrentModeReasonAndEncryptionConfig(ctx context.Context) (state.Mode, string, configv1.APIServerEncryption, error) { - apiServer, err := c.apiServerClient.Get(ctx, "cluster", metav1.GetOptions{}) +// fetchReferencedResources loads the Secret and ConfigMap referenced by providerCfg from namespace, validating that every expected key is present. Either return value may be nil when the provider does not reference that resource type. +func fetchReferencedResources(ctx context.Context, providerCfg kmsProviderConfig, secretClient corev1client.SecretsGetter, configMapClient corev1client.ConfigMapsGetter, namespace string) (*corev1.Secret, *corev1.ConfigMap, error) { + var refSecret *corev1.Secret + if secretName, expectedKeys, err := providerCfg.referencedSecretName(); err != nil { + return nil, nil, err + } else if len(secretName) > 0 { + refSecret, err = secretClient.Secrets(namespace).Get(ctx, secretName, metav1.GetOptions{}) + if err != nil { + return nil, nil, fmt.Errorf("failed to get secret %s in %s: %w", secretName, namespace, err) + } + for _, key := range expectedKeys { + if _, ok := refSecret.Data[key]; !ok { + return nil, nil, fmt.Errorf("secret %s in %s is missing required key %q", secretName, namespace, key) + } + } + } + + var refCM *corev1.ConfigMap + if cmName, expectedKeys, err := providerCfg.referencedConfigMapName(); err != nil { + return nil, nil, err + } else if len(cmName) > 0 { + refCM, err = configMapClient.ConfigMaps(namespace).Get(ctx, cmName, metav1.GetOptions{}) + if err != nil { + return nil, nil, fmt.Errorf("failed to get configmap %s in %s: %w", cmName, namespace, err) + } + for _, key := range expectedKeys { + if _, ok := refCM.Data[key]; !ok { + return nil, nil, fmt.Errorf("configmap %s in %s is missing required key %q", cmName, namespace, key) + } + } + } + + return refSecret, refCM, nil +} + +// getCurrentModeReasonAndEncryptionConfig the active encryption mode, any external rotation reason from unsupported config overrides, and the full encryption spec. +func getCurrentModeReasonAndEncryptionConfig(ctx context.Context, apiServerClient configv1client.APIServerInterface, operatorClient operatorv1helpers.OperatorClient, unsupportedConfigPrefix []string) (state.Mode, string, configv1.APIServerEncryption, error) { + apiServer, err := apiServerClient.Get(ctx, "cluster", metav1.GetOptions{}) if err != nil { return "", "", configv1.APIServerEncryption{}, err } - operatorSpec, _, _, err := c.operatorClient.GetOperatorState() + operatorSpec, _, _, err := operatorClient.GetOperatorState() if err != nil { return "", "", configv1.APIServerEncryption{}, err } - encryptionConfig, err := structuredUnsupportedConfigFrom(operatorSpec.UnsupportedConfigOverrides.Raw, c.unsupportedConfigPrefix) + encryptionConfig, err := structuredUnsupportedConfigFrom(operatorSpec.UnsupportedConfigOverrides.Raw, unsupportedConfigPrefix) if err != nil { return "", "", configv1.APIServerEncryption{}, err } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/kms_preflight_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/kms_preflight_controller.go index 4d089bf81e..b7d48b6ceb 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/kms_preflight_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/kms_preflight_controller.go @@ -19,7 +19,6 @@ import ( configv1 "github.com/openshift/api/config/v1" operatorv1 "github.com/openshift/api/operator/v1" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" - configv1informers "github.com/openshift/client-go/config/informers/externalversions/config/v1" applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1" "github.com/openshift/library-go/pkg/controller/factory" @@ -28,6 +27,22 @@ import ( operatorv1helpers "github.com/openshift/library-go/pkg/operator/v1helpers" ) +// EncryptionConfigurationComputer computes the encryption configuration secret +// passed to the preflight deployer right before it creates a new deployment. +type EncryptionConfigurationComputer interface { + ComputeEncryptionConfiguration(ctx context.Context) (*corev1.Secret, error) +} + +// NoopEncryptionConfigurationComputer is a placeholder EncryptionConfigurationComputer +// that returns nil until a real implementation is available. +type NoopEncryptionConfigurationComputer struct{} + +var _ EncryptionConfigurationComputer = NoopEncryptionConfigurationComputer{} + +func (NoopEncryptionConfigurationComputer) ComputeEncryptionConfiguration(_ context.Context) (*corev1.Secret, error) { + return nil, nil +} + // kmsConfigHasherResourceProvider abstracts fetching the Secret and ConfigMap referenced // by a KMS provider config. type kmsConfigHasherResourceProvider interface { @@ -205,6 +220,9 @@ type kmsPreflightController struct { configMapsClient corev1client.ConfigMapsGetter deployer KMSPreflightDeployer + // encryptionConfigurationComputer is called right before Deploy to produce the + // encryption configuration secret passed to the deployer. + encryptionConfigurationComputer EncryptionConfigurationComputer // dirtyDeployer is true when preflight resources may exist in the cluster. // Set to true after each Deploy and cleared to false after a successful Cleanup, // so that repeated Cleanup calls in steady state issue no API requests. @@ -295,9 +313,9 @@ func NewKMSPreflightController( provider Provider, preconditionsFulfilledFn preconditionsFulfilled, deployer KMSPreflightDeployer, + encryptionConfigurationComputer EncryptionConfigurationComputer, operatorClient operatorv1helpers.OperatorClient, apiServerClient configv1client.APIServerInterface, - apiServerInformer configv1informers.APIServerInformer, // secretsClient and configMapsClient read referenced Secrets and ConfigMaps in // openshift-config for hash computation. No informer is needed: the key-controller // detects config changes and updates ObservedConfigHash, which triggers this @@ -315,7 +333,8 @@ func NewKMSPreflightController( secretsClient: secretsClient, configMapsClient: configMapsClient, - deployer: deployer, + deployer: deployer, + encryptionConfigurationComputer: encryptionConfigurationComputer, // assume resources may exist from a previous process run dirtyDeployer: true, provider: provider, @@ -501,9 +520,12 @@ func (c *kmsPreflightController) runPreflightChecks(ctx context.Context) (requeu message: fmt.Sprintf("preflight check failed for hash %s: pod was removed but failure is recorded in status", requiredHash), } } + encryptionConfig, err := c.encryptionConfigurationComputer.ComputeEncryptionConfiguration(ctx) + if err != nil { + return true, "", "", fmt.Errorf("failed to compute encryption configuration: %w", err) + } c.dirtyDeployer = true - // TODO: compute the encryption configuration and pass it to the deployer - if err := c.deployer.Deploy(ctx, requiredHash, nil); err != nil { + if err := c.deployer.Deploy(ctx, requiredHash, encryptionConfig); err != nil { return true, "", "", err } return true, "RunningPreflightCheck", fmt.Sprintf("Deploying preflight pod for hash %s", requiredHash), nil @@ -750,8 +772,8 @@ func (c *kmsPreflightController) preflightRequired(ctx context.Context) (string, } // No requeue needed: the key-controller will update ObservedConfigHash when it - // picks up the config change (via apiServerInformer), which triggers us through - // operatorClient.Informer(). The minute-based resync is a backstop. + // picks up the config change, which triggers us through operatorClient.Informer(). + // The minute-based resync is a backstop. if currentHash != requiredHash { klog.V(4).Infof("KMS config hash changed: required=%s, current=%s; waiting for the key-controller to update ObservedConfigHash", requiredHash, currentHash) return "", nil, nil diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/kms/encryption_status_provider.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/kms/encryption_status_provider.go index 6a6ea7b27a..a42cefd1c7 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/kms/encryption_status_provider.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/kms/encryption_status_provider.go @@ -17,7 +17,7 @@ type EncryptionStatusProvider interface { ApplyKMSEncryptionStatus(ctx context.Context, fieldManager string, status *applyoperatorv1.KMSEncryptionStatusApplyConfiguration) error // UpdateKMSEncryptionStatus reads the current status, applies the mutation, - // and writes it back. A conflict (409) is returned as-is. + // and writes it back. Implementations must retry on conflict (409). // // Note: use this instead of ApplyKMSEncryptionStatus when the controller is // the sole owner of a field. Apply requires re-sending every owned field on diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/statemachine/transition.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/statemachine/transition.go index 12eb5b8b90..b8f143938f 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/statemachine/transition.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/statemachine/transition.go @@ -56,12 +56,12 @@ func GetEncryptionConfigAndState( if err != nil { return nil, nil, nil, "", err } - desiredEncryptionState := getDesiredEncryptionState(secretData, encryptionSecrets, encryptedGRs) + desiredEncryptionState := GetDesiredEncryptionState(secretData, encryptionSecrets, encryptedGRs) return secretData, desiredEncryptionState, encryptionSecrets, "", nil } -// getDesiredEncryptionState returns the desired state of encryption for all resources. +// GetDesiredEncryptionState returns the desired state of encryption for all resources. // To do this it compares the current state against the available secrets and to-be-encrypted resources. // oldEncryptionConfig can be nil if there is no config yet. // If there are no secrets, the identity is set for all resources as write key. @@ -73,7 +73,7 @@ func GetEncryptionConfigAndState( // 2. every GR must have all the read-keys (existing as secrets) since last complete migration. // 3. if (2) is the case, the write-key must be the most recent key. // 4. if (2) and (3) are the case, all non-write keys should be removed. -func getDesiredEncryptionState(oldSecretData *encryptiondata.Config, encryptionSecrets []*corev1.Secret, toBeEncryptedGRs []schema.GroupResource) map[schema.GroupResource]state.GroupResourceState { +func GetDesiredEncryptionState(oldSecretData *encryptiondata.Config, encryptionSecrets []*corev1.Secret, toBeEncryptedGRs []schema.GroupResource) map[schema.GroupResource]state.GroupResourceState { // // STEP 0: start with old encryption config, and alter it towards the desired state in the following STEPs. // diff --git a/vendor/github.com/openshift/library-go/test/library/encryption/errors.go b/vendor/github.com/openshift/library-go/test/library/encryption/errors.go index 057481dafc..b08d9a16af 100644 --- a/vendor/github.com/openshift/library-go/test/library/encryption/errors.go +++ b/vendor/github.com/openshift/library-go/test/library/encryption/errors.go @@ -46,7 +46,7 @@ func transientAPIError(err error) bool { switch { case err == nil: return false - case errors.IsServerTimeout(err), errors.IsTooManyRequests(err), net.IsProbableEOF(err), net.IsConnectionReset(err), net.IsNoRoutesError(err), isConnectionRefusedError(err), isGolangNetTimeout(err): + case errors.IsServiceUnavailable(err), errors.IsServerTimeout(err), errors.IsTooManyRequests(err), net.IsProbableEOF(err), net.IsConnectionReset(err), net.IsNoRoutesError(err), isConnectionRefusedError(err), isGolangNetTimeout(err): return true default: return false diff --git a/vendor/github.com/openshift/library-go/test/library/encryption/helpers.go b/vendor/github.com/openshift/library-go/test/library/encryption/helpers.go index d342b4e98d..bd558b664b 100644 --- a/vendor/github.com/openshift/library-go/test/library/encryption/helpers.go +++ b/vendor/github.com/openshift/library-go/test/library/encryption/helpers.go @@ -126,9 +126,24 @@ func SetAndWaitForEncryptionType(ctx context.Context, t testing.TB, provider Enc // KMS-to-KMS migration: when both old and new are KMS but the config differs, // the key controller creates a new key. We must wait for the next migrated key // rather than asserting no new key is created. - if needsUpdate && provider.Type == configv1.EncryptionTypeKMS && previousEncryption.Type == configv1.EncryptionTypeKMS { - WaitForNextMigratedKey(t, clientSet.Kube, lastMigratedKeyMeta, defaultTargetGRs, namespace, labelSelector) - return clientSet + // Multi-operator parallel KMS-to-KMS: another goroutine already applied the + // KMS config change (needsUpdate=false), but the operator will still create a + // new key because the KMS provider config changed. Use targetGRs to determine + // if we captured the old key or the new key. + if provider.Type == configv1.EncryptionTypeKMS { + if needsUpdate { + if previousEncryption.Type == configv1.EncryptionTypeKMS { + WaitForNextMigratedKey(t, clientSet.Kube, lastMigratedKeyMeta, defaultTargetGRs, namespace, labelSelector) + return clientSet + } + } else if lastMigratedKeyMeta.Mode == string(configv1.EncryptionTypeKMS) { + if len(lastMigratedKeyMeta.Name) > 0 && !allTargetGRsMigrated(lastMigratedKeyMeta, defaultTargetGRs) { + WaitForCurrentKeyMigrated(t, clientSet.Kube, lastMigratedKeyMeta, defaultTargetGRs, namespace, labelSelector) + } else { + WaitForNextMigratedKey(t, clientSet.Kube, lastMigratedKeyMeta, defaultTargetGRs, namespace, labelSelector) + } + return clientSet + } } WaitForEncryptionKeyBasedOn(t, clientSet.Kube, lastMigratedKeyMeta, provider.Type, defaultTargetGRs, namespace, labelSelector) @@ -700,3 +715,12 @@ func GetRawWellKnownTokenOfLife(t testing.TB, clientSet ClientSet) string { return string(resp.Kvs[0].Value) } + +func allTargetGRsMigrated(keyMeta EncryptionKeyMeta, targetGRs []schema.GroupResource) bool { + for _, gr := range targetGRs { + if !hasResource(gr, keyMeta.Migrated) { + return false + } + } + return true +} diff --git a/vendor/github.com/openshift/library-go/test/library/encryption/kms/scenarios.go b/vendor/github.com/openshift/library-go/test/library/encryption/kms/scenarios.go new file mode 100644 index 0000000000..19c2308ff9 --- /dev/null +++ b/vendor/github.com/openshift/library-go/test/library/encryption/kms/scenarios.go @@ -0,0 +1,195 @@ +package kms + +import ( + "context" + "fmt" + "math/rand/v2" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + + library "github.com/openshift/library-go/test/library/encryption" +) + +const ( + globalMachineSpecifiedConfigNamespace = "openshift-config-managed" + kubeAPIServerComponent = "openshift-kube-apiserver" + kubeAPIServerOperatorNamespace = "openshift-kube-apiserver-operator" + oauthAPIServerComponent = "openshift-oauth-apiserver" + authenticationOperatorNamespace = "openshift-authentication-operator" + openshiftAPIServerComponent = "openshift-apiserver" + openshiftAPIServerOperatorNamespace = "openshift-apiserver-operator" +) + +func encryptionComponentLabelSelector(component string) string { + return "encryption.apiserver.operator.openshift.io/component=" + component +} + +// EncryptionTurnOnAndOffScenarios returns ready-to-use KAS/Auth/OAS on/off scenarios. +// +// Provider handling: on/off tests toggle a single encryption mode (KMS on, identity off), +// so only the KAS scenario sets EncryptionProvider. Auth and OAS omit it because +// APIServer.spec.encryption is cluster-wide — TestEncryptionTurnOnAndOff reads the one +// non-empty provider and applies it for every operator in parallel. +// +// The provider is built here (not passed in) because Vault KMS setup requires ctx and t. +func EncryptionTurnOnAndOffScenarios(ctx context.Context, t testing.TB) []library.OnOffScenario { + provider := DefaultVaultEncryptionProvider(ctx, t) + return []library.OnOffScenario{ + kasOnOffScenario(provider), + authOnOffScenario(ctx), + oasOnOffScenario(ctx), + } +} + +// EncryptionProvidersMigrationScenarios returns ready-to-use KAS/Auth/OAS migration scenarios. +// +// Provider handling: migration tests step through multiple encryption modes, so only +// the KAS scenario sets EncryptionProviders (a shuffled KMS + AES sequence). Auth and +// OAS omit it for the same cluster-wide reason as on/off — TestEncryptionProvidersMigration +// reads the one non-empty list and drives every operator through the same steps. +// +// The provider list is built here (not passed in): Vault KMS needs ctx/t, and the list +// is shuffled with a random AES provider (AESGCM or AESCBC) so callers get a complete +// ready-to-run scenario. +func EncryptionProvidersMigrationScenarios(ctx context.Context, t testing.TB) []library.ProvidersMigrationScenario { + providers := library.ShuffleEncryptionProviders([]library.EncryptionProvider{ + DefaultVaultEncryptionProvider(ctx, t), + library.SupportedStaticEncryptionProviders[rand.IntN(len(library.SupportedStaticEncryptionProviders))], + }) + return []library.ProvidersMigrationScenario{ + kasProvidersMigrationScenario(providers), + authProvidersMigrationScenario(ctx), + oasProvidersMigrationScenario(ctx), + } +} + +func kasOnOffScenario(provider library.EncryptionProvider) library.OnOffScenario { + return library.OnOffScenario{ + BasicScenario: library.BasicScenario{ + Namespace: globalMachineSpecifiedConfigNamespace, + LabelSelector: encryptionComponentLabelSelector(kubeAPIServerComponent), + EncryptionConfigSecretName: fmt.Sprintf("encryption-config-%s", kubeAPIServerComponent), + EncryptionConfigSecretNamespace: globalMachineSpecifiedConfigNamespace, + OperatorNamespace: kubeAPIServerOperatorNamespace, + TargetGRs: library.WellKnownKASTargetGRs, + AssertFunc: library.AssertWellKnownSecretsAndConfigMaps, + }, + CreateResourceFunc: library.CreateAndStoreWellKnownSecretOfLife, + AssertResourceEncryptedFunc: library.AssertWellKnownSecretOfLifeEncrypted, + AssertResourceNotEncryptedFunc: library.AssertWellKnownSecretOfLifeNotEncrypted, + ResourceFunc: library.WellKnownSecretOfLife, + ResourceName: "SecretOfLife", + // Cluster-wide APIServer config — only KAS sets this; Auth/OAS omit it. + // EncryptionProvider sets cluster-wide APIServer encryption for on/off tests. + // When multiple operators run together, set it on exactly one scenario. + EncryptionProvider: provider, + } +} + +func authOnOffScenario(ctx context.Context) library.OnOffScenario { + return library.OnOffScenario{ + BasicScenario: library.BasicScenario{ + Namespace: globalMachineSpecifiedConfigNamespace, + LabelSelector: encryptionComponentLabelSelector(oauthAPIServerComponent), + EncryptionConfigSecretName: fmt.Sprintf("encryption-config-%s", oauthAPIServerComponent), + EncryptionConfigSecretNamespace: globalMachineSpecifiedConfigNamespace, + OperatorNamespace: authenticationOperatorNamespace, + TargetGRs: library.WellKnownAuthTargetGRs, + AssertFunc: library.AssertWellKnownTokens, + }, + CreateResourceFunc: func(t testing.TB, clientSet library.ClientSet, _ string) runtime.Object { + return library.CreateAndStoreWellKnownTokenOfLife(ctx, t, clientSet) + }, + AssertResourceEncryptedFunc: library.AssertWellKnownTokenOfLifeEncrypted, + AssertResourceNotEncryptedFunc: library.AssertWellKnownTokenOfLifeNotEncrypted, + ResourceFunc: library.WellKnownTokenOfLife, + ResourceName: "TokenOfLife", + } +} + +func oasOnOffScenario(ctx context.Context) library.OnOffScenario { + return library.OnOffScenario{ + BasicScenario: library.BasicScenario{ + Namespace: globalMachineSpecifiedConfigNamespace, + LabelSelector: encryptionComponentLabelSelector(openshiftAPIServerComponent), + EncryptionConfigSecretName: fmt.Sprintf("encryption-config-%s", openshiftAPIServerComponent), + EncryptionConfigSecretNamespace: globalMachineSpecifiedConfigNamespace, + OperatorNamespace: openshiftAPIServerOperatorNamespace, + TargetGRs: library.WellKnownOASTargetGRs, + AssertFunc: library.AssertWellKnownRoutes, + }, + CreateResourceFunc: func(t testing.TB, clientSet library.ClientSet, ns string) runtime.Object { + return library.CreateAndStoreWellKnownRouteOfLife(ctx, t, clientSet, ns) + }, + AssertResourceEncryptedFunc: library.AssertWellKnownRouteOfLifeEncrypted, + AssertResourceNotEncryptedFunc: library.AssertWellKnownRouteOfLifeNotEncrypted, + ResourceFunc: library.WellKnownRouteOfLife, + ResourceName: "RouteOfLife", + } +} + +func kasProvidersMigrationScenario(providers []library.EncryptionProvider) library.ProvidersMigrationScenario { + return library.ProvidersMigrationScenario{ + BasicScenario: library.BasicScenario{ + Namespace: globalMachineSpecifiedConfigNamespace, + LabelSelector: encryptionComponentLabelSelector(kubeAPIServerComponent), + EncryptionConfigSecretName: fmt.Sprintf("encryption-config-%s", kubeAPIServerComponent), + EncryptionConfigSecretNamespace: globalMachineSpecifiedConfigNamespace, + OperatorNamespace: kubeAPIServerOperatorNamespace, + TargetGRs: library.WellKnownKASTargetGRs, + AssertFunc: library.AssertWellKnownSecretsAndConfigMaps, + }, + CreateResourceFunc: library.CreateAndStoreWellKnownSecretOfLife, + AssertResourceEncryptedFunc: library.AssertWellKnownSecretOfLifeEncrypted, + AssertResourceNotEncryptedFunc: library.AssertWellKnownSecretOfLifeNotEncrypted, + ResourceFunc: library.WellKnownSecretOfLife, + ResourceName: "SecretOfLife", + // Cluster-wide APIServer config — only KAS sets this; Auth/OAS omit it. + // EncryptionProvider sets cluster-wide APIServer encryption for provider migration tests. + // When multiple operators run together, set it on exactly one scenario. + EncryptionProviders: providers, + } +} + +func authProvidersMigrationScenario(ctx context.Context) library.ProvidersMigrationScenario { + return library.ProvidersMigrationScenario{ + BasicScenario: library.BasicScenario{ + Namespace: globalMachineSpecifiedConfigNamespace, + LabelSelector: encryptionComponentLabelSelector(oauthAPIServerComponent), + EncryptionConfigSecretName: fmt.Sprintf("encryption-config-%s", oauthAPIServerComponent), + EncryptionConfigSecretNamespace: globalMachineSpecifiedConfigNamespace, + OperatorNamespace: authenticationOperatorNamespace, + TargetGRs: library.WellKnownAuthTargetGRs, + AssertFunc: library.AssertWellKnownTokens, + }, + CreateResourceFunc: func(t testing.TB, clientSet library.ClientSet, _ string) runtime.Object { + return library.CreateAndStoreWellKnownTokenOfLife(ctx, t, clientSet) + }, + AssertResourceEncryptedFunc: library.AssertWellKnownTokenOfLifeEncrypted, + AssertResourceNotEncryptedFunc: library.AssertWellKnownTokenOfLifeNotEncrypted, + ResourceFunc: library.WellKnownTokenOfLife, + ResourceName: "TokenOfLife", + } +} + +func oasProvidersMigrationScenario(ctx context.Context) library.ProvidersMigrationScenario { + return library.ProvidersMigrationScenario{ + BasicScenario: library.BasicScenario{ + Namespace: globalMachineSpecifiedConfigNamespace, + LabelSelector: encryptionComponentLabelSelector(openshiftAPIServerComponent), + EncryptionConfigSecretName: fmt.Sprintf("encryption-config-%s", openshiftAPIServerComponent), + EncryptionConfigSecretNamespace: globalMachineSpecifiedConfigNamespace, + OperatorNamespace: openshiftAPIServerOperatorNamespace, + TargetGRs: library.WellKnownOASTargetGRs, + AssertFunc: library.AssertWellKnownRoutes, + }, + CreateResourceFunc: func(t testing.TB, clientSet library.ClientSet, ns string) runtime.Object { + return library.CreateAndStoreWellKnownRouteOfLife(ctx, t, clientSet, ns) + }, + AssertResourceEncryptedFunc: library.AssertWellKnownRouteOfLifeEncrypted, + AssertResourceNotEncryptedFunc: library.AssertWellKnownRouteOfLifeNotEncrypted, + ResourceFunc: library.WellKnownRouteOfLife, + ResourceName: "RouteOfLife", + } +} diff --git a/vendor/github.com/openshift/library-go/test/library/encryption/perf_helpers.go b/vendor/github.com/openshift/library-go/test/library/encryption/perf_helpers.go index 7f0ad05054..92f060e3b1 100644 --- a/vendor/github.com/openshift/library-go/test/library/encryption/perf_helpers.go +++ b/vendor/github.com/openshift/library-go/test/library/encryption/perf_helpers.go @@ -26,6 +26,10 @@ func watchForMigrationControllerProgressingCondition(t testing.TB, getOperatorCo err := wait.Poll(waitPollInterval, waitPollTimeout, func() (bool, error) { conditions, err := getOperatorConditionsFn(t) if err != nil { + if transientAPIError(err) { + t.Logf("failed to get operator conditions, will retry: %v", err) + return false, nil + } return false, err } for _, cond := range conditions { diff --git a/vendor/modules.txt b/vendor/modules.txt index 37e513ea1c..44cc41f577 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -415,7 +415,7 @@ github.com/openshift/client-go/user/applyconfigurations/internal github.com/openshift/client-go/user/applyconfigurations/user/v1 github.com/openshift/client-go/user/clientset/versioned/scheme github.com/openshift/client-go/user/clientset/versioned/typed/user/v1 -# github.com/openshift/library-go v0.0.0-20260806124457-39539af5eb2c +# github.com/openshift/library-go v0.0.0-20260806124457-39539af5eb2c => github.com/tchap/library-go v0.0.0-20260817131047-edce4e0d0c2a ## explicit; go 1.26.0 github.com/openshift/library-go/pkg/apiserver/jsonpatch github.com/openshift/library-go/pkg/apps/deployment @@ -1714,3 +1714,4 @@ sigs.k8s.io/structured-merge-diff/v6/value ## explicit; go 1.22 sigs.k8s.io/yaml # github.com/onsi/ginkgo/v2 => github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20251001123353-fd5b1fb35db1 +# github.com/openshift/library-go => github.com/tchap/library-go v0.0.0-20260817131047-edce4e0d0c2a From 746cb564f04efc71a44abf96bb6473a74e0655ca Mon Sep 17 00:00:00 2001 From: Ondra Kupka Date: Mon, 17 Aug 2026 15:32:41 +0200 Subject: [PATCH 2/3] Fix build errors after dep update --- pkg/operator/starter.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/operator/starter.go b/pkg/operator/starter.go index 02a1b4660f..e88c647df9 100644 --- a/pkg/operator/starter.go +++ b/pkg/operator/starter.go @@ -45,6 +45,7 @@ import ( "github.com/openshift/library-go/pkg/operator/configobserver/featuregates" "github.com/openshift/library-go/pkg/operator/csr" "github.com/openshift/library-go/pkg/operator/encryption" + encryptioncontrollers "github.com/openshift/library-go/pkg/operator/encryption/controllers" "github.com/openshift/library-go/pkg/operator/encryption/controllers/migrators" encryptiondeployer "github.com/openshift/library-go/pkg/operator/encryption/deployer" kmspreflight "github.com/openshift/library-go/pkg/operator/encryption/kms/preflight" @@ -718,6 +719,7 @@ func prepareOauthAPIServerOperator( resourceSyncController, authEncryptionStatusProvider, kmspreflight.NewAlwaysSucceedKMSPreflightDeployer(), + encryptioncontrollers.NoopEncryptionConfigurationComputer{}, ).WithUnsupportedConfigPrefixForEncryptionControllers( oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix, ).WithFinalizerController( From 62db21cd0361a44c5ea724783a3334c9b7846ee9 Mon Sep 17 00:00:00 2001 From: Ondra Kupka Date: Mon, 17 Aug 2026 15:36:44 +0200 Subject: [PATCH 3/3] Regenerate test-data --- ...-system-COLON-openshift-COLON-openshift-authenticator-.yaml} | 2 +- ...-system-COLON-openshift-COLON-openshift-authenticator-.yaml} | 0 .../{c5b3-body-cluster.yaml => 28de-body-cluster.yaml} | 2 +- .../{c5b3-metadata-cluster.yaml => 28de-metadata-cluster.yaml} | 0 .../{c5b3-options-cluster.yaml => 28de-options-cluster.yaml} | 0 .../{5749-body-cluster.yaml => 1ead-body-cluster.yaml} | 2 +- .../{5749-metadata-cluster.yaml => 1ead-metadata-cluster.yaml} | 0 .../{5749-options-cluster.yaml => 1ead-options-cluster.yaml} | 0 8 files changed, 3 insertions(+), 3 deletions(-) rename test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/{ad23-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml => d8b3-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml} (56%) rename test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/{ad23-metadata-system-COLON-openshift-COLON-openshift-authenticator-.yaml => d8b3-metadata-system-COLON-openshift-COLON-openshift-authenticator-.yaml} (100%) rename test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/{c5b3-body-cluster.yaml => 28de-body-cluster.yaml} (93%) rename test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/{c5b3-metadata-cluster.yaml => 28de-metadata-cluster.yaml} (100%) rename test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/{c5b3-options-cluster.yaml => 28de-options-cluster.yaml} (100%) rename test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/{5749-body-cluster.yaml => 1ead-body-cluster.yaml} (93%) rename test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/{5749-metadata-cluster.yaml => 1ead-metadata-cluster.yaml} (100%) rename test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/{5749-options-cluster.yaml => 1ead-options-cluster.yaml} (100%) diff --git a/test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/ad23-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml b/test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/d8b3-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml similarity index 56% rename from test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/ad23-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml rename to test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/d8b3-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml index a9b1a0a0aa..70b4b1a513 100644 --- a/test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/ad23-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml +++ b/test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/d8b3-body-system-COLON-openshift-COLON-openshift-authenticator-.yaml @@ -5,7 +5,7 @@ metadata: labels: authentication.openshift.io/csr: openshift-authenticator spec: - request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQkRqQ0J0QUlCQURCU01WQXdUZ1lEVlFRREUwZHplWE4wWlcwNmMyVnlkbWxqWldGalkyOTFiblE2YjNCbApibk5vYVdaMExXOWhkWFJvTFdGd2FYTmxjblpsY2pwdmNHVnVjMmhwWm5RdFlYVjBhR1Z1ZEdsallYUnZjakJaCk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkh0a0lWek9qTnI4OEVSeUxUbGpYZ1lLeURIeCtGbWQKRUJKSldqZ3NoNFpmY3BjWUJKd2YwWmxlVFNBMjFEZnQvNzdSbDhmNWJ0QXJzV1ZNbFNGbjl1Q2dBREFLQmdncQpoa2pPUFFRREFnTkpBREJHQWlFQWgyenZud3I2VTBmSHluQXI4Q3RjWWFRN3FxQ3ZISDdVZXF3eGdKVHJwT2NDCklRQ2E4Z3RrS3A3cXBZdmdXOTZDYitMb05ZU0xYY2YvZXdodWR6b05uemlETXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K + request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQkREQ0J0QUlCQURCU01WQXdUZ1lEVlFRREUwZHplWE4wWlcwNmMyVnlkbWxqWldGalkyOTFiblE2YjNCbApibk5vYVdaMExXOWhkWFJvTFdGd2FYTmxjblpsY2pwdmNHVnVjMmhwWm5RdFlYVjBhR1Z1ZEdsallYUnZjakJaCk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkluYWFRaFZFZXdCMjFFODVSZVlpakl6OG0rMDZ3VlMKRG1vUWJPT3F1NFV2UVdFU25rQkYwbW1SSkJwdzk2dEszU1FXRkJUY1Q1WUxNbjU0T2FHN1FqYWdBREFLQmdncQpoa2pPUFFRREFnTkhBREJFQWlBaEwwVEFHSFR2T2pWdllmVnkxS3N3V2xRVDQzY3gzMGIxOSsrbis1WkJTQUlnClFCVDNxL2lqbEdMc1d4M1lBMWdMRXFqQU5xMUJRY1dUSmNESmhta1Y0bUU9Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo= signerName: kubernetes.io/kube-apiserver-client usages: - digital signature diff --git a/test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/ad23-metadata-system-COLON-openshift-COLON-openshift-authenticator-.yaml b/test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/d8b3-metadata-system-COLON-openshift-COLON-openshift-authenticator-.yaml similarity index 100% rename from test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/ad23-metadata-system-COLON-openshift-COLON-openshift-authenticator-.yaml rename to test-data/apply-configuration/overall/minimal-cluster/expected-output/UserWorkload/Create/cluster-scoped-resources/certificates.k8s.io/certificatesigningrequests/d8b3-metadata-system-COLON-openshift-COLON-openshift-authenticator-.yaml diff --git a/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/c5b3-body-cluster.yaml b/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/28de-body-cluster.yaml similarity index 93% rename from test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/c5b3-body-cluster.yaml rename to test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/28de-body-cluster.yaml index 92d3803206..8863d06d41 100644 --- a/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/c5b3-body-cluster.yaml +++ b/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/28de-body-cluster.yaml @@ -15,7 +15,7 @@ status: type: APIServerDeploymentDegraded - lastTransitionTime: "2024-10-14T22:38:20Z" message: 'deployment/apiserver.openshift-oauth-apiserver: 0/1 pods have been updated - to the latest generation and 0/1 pods are available' + to the latest revision and 0/1 pods are available' reason: PodsUpdating status: "True" type: APIServerDeploymentProgressing diff --git a/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/c5b3-metadata-cluster.yaml b/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/28de-metadata-cluster.yaml similarity index 100% rename from test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/c5b3-metadata-cluster.yaml rename to test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/28de-metadata-cluster.yaml diff --git a/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/c5b3-options-cluster.yaml b/test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/28de-options-cluster.yaml similarity index 100% rename from test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/c5b3-options-cluster.yaml rename to test-data/apply-configuration/overall/oauth-apiserver-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/28de-options-cluster.yaml diff --git a/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/5749-body-cluster.yaml b/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/1ead-body-cluster.yaml similarity index 93% rename from test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/5749-body-cluster.yaml rename to test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/1ead-body-cluster.yaml index a03cc75105..a0471546f1 100644 --- a/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/5749-body-cluster.yaml +++ b/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/1ead-body-cluster.yaml @@ -15,7 +15,7 @@ status: type: OAuthServerDeploymentDegraded - lastTransitionTime: "2025-08-07T22:38:20Z" message: 'deployment/oauth-openshift.openshift-authentication: 0/1 pods have been - updated to the latest generation and 0/1 pods are available' + updated to the latest revision and 0/1 pods are available' reason: PodsUpdating status: "True" type: OAuthServerDeploymentProgressing diff --git a/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/5749-metadata-cluster.yaml b/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/1ead-metadata-cluster.yaml similarity index 100% rename from test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/5749-metadata-cluster.yaml rename to test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/1ead-metadata-cluster.yaml diff --git a/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/5749-options-cluster.yaml b/test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/1ead-options-cluster.yaml similarity index 100% rename from test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/5749-options-cluster.yaml rename to test-data/apply-configuration/overall/oauth-server-creation-minimal/expected-output/Management/ApplyStatus/cluster-scoped-resources/operator.openshift.io/authentications/1ead-options-cluster.yaml