From 3ddb65998397d7716fc3ba41b2ef841a4182a003 Mon Sep 17 00:00:00 2001 From: Gang Wang Date: Wed, 15 Apr 2026 18:40:52 +0800 Subject: [PATCH 01/19] kubeadm: skip promote call when etcd member is already a voting member Move isLearner and isStarted variables to the outer var block of MemberPromote so their values are accessible after the poll loop. After the poll, if isLearner is false the member was already promoted, so return nil early without issuing a redundant promote call. --- cmd/kubeadm/app/util/etcd/etcd.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cmd/kubeadm/app/util/etcd/etcd.go b/cmd/kubeadm/app/util/etcd/etcd.go index 2d8183b6eea08..fc9bad351b50a 100644 --- a/cmd/kubeadm/app/util/etcd/etcd.go +++ b/cmd/kubeadm/app/util/etcd/etcd.go @@ -575,6 +575,8 @@ func (c *Client) getMemberStatus(memberID uint64) (isLearner bool, started bool, func (c *Client) MemberPromote(learnerID uint64) error { var ( lastError error + isLearner bool + isStarted bool learnerIDUint = strconv.FormatUint(learnerID, 16) ) @@ -582,7 +584,8 @@ func (c *Client) MemberPromote(learnerID uint64) error { err := wait.PollUntilContextTimeout(context.Background(), constants.EtcdAPICallRetryInterval, kubeadmapi.GetActiveTimeouts().EtcdAPICall.Duration, true, func(_ context.Context) (bool, error) { - isLearner, started, err := c.getMemberStatus(learnerID) + var err error + isLearner, isStarted, err = c.getMemberStatus(learnerID) if err != nil { lastError = errors.WithMessagef(err, "failed to get member %s status", learnerIDUint) return false, nil @@ -591,7 +594,7 @@ func (c *Client) MemberPromote(learnerID uint64) error { klog.V(1).Infof("[etcd] Member %s was already promoted.", learnerIDUint) return true, nil } - if !started { + if !isStarted { klog.V(1).Infof("[etcd] Member %s is not started yet. Waiting for it to be started.", learnerIDUint) lastError = errors.Errorf("the etcd member %s is not started", learnerIDUint) return false, nil @@ -602,6 +605,10 @@ func (c *Client) MemberPromote(learnerID uint64) error { return lastError } + if !isLearner { + return nil + } + klog.V(1).Infof("[etcd] Promoting a learner as a voting member: %s", learnerIDUint) cli, err := c.newEtcdClient(c.Endpoints) From 720f13b8eac49f2e6086f05de95b00d601691e65 Mon Sep 17 00:00:00 2001 From: Siyuan Zhang Date: Fri, 24 Apr 2026 14:50:50 -0500 Subject: [PATCH 02/19] test/compatibility_lifecycle: resolve feature names from variables Signed-off-by: Siyuan Zhang --- .../cmd/feature_gates.go | 20 +++++++++++++--- .../cmd/feature_gates_test.go | 23 +++++++++++++++---- .../reference/versioned_feature_list.yaml | 22 +++++++++--------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/test/compatibility_lifecycle/cmd/feature_gates.go b/test/compatibility_lifecycle/cmd/feature_gates.go index 8800f0d8aca97..93d93771ae156 100644 --- a/test/compatibility_lifecycle/cmd/feature_gates.go +++ b/test/compatibility_lifecycle/cmd/feature_gates.go @@ -60,7 +60,10 @@ type featureSpec struct { } type featureInfo struct { - Name string `yaml:"name" json:"name"` + Name string `yaml:"name" json:"name"` + // FullName is the full name of the feature, including the package name, + // used for ensuring that features are grouped by their package prefix first, + // and then sorted alphabetically within that group. FullName string `yaml:"-" json:"-"` VersionedSpecs []featureSpec `yaml:"versionedSpecs" json:"versionedSpecs"` } @@ -435,9 +438,20 @@ func isFeatureSpecType(v ast.Expr, aliasMap map[string]string) bool { } func parseFeatureInfo(variables map[string]ast.Expr, kv *ast.KeyValueExpr) (featureInfo, error) { + name := identifierName(kv.Key, true) + fullName := identifierName(kv.Key, false) + + if id, ok := kv.Key.(*ast.Ident); ok { + if varVal, ok := variables[id.Name]; ok { + if strVal, err := basicStringLiteral(varVal); err == nil { + name = strVal + } + } + } + info := featureInfo{ - Name: identifierName(kv.Key, true), - FullName: identifierName(kv.Key, false), + Name: name, + FullName: fullName, VersionedSpecs: []featureSpec{}, } specExps := []ast.Expr{} diff --git a/test/compatibility_lifecycle/cmd/feature_gates_test.go b/test/compatibility_lifecycle/cmd/feature_gates_test.go index a0652852b2aa5..9631d82d86389 100644 --- a/test/compatibility_lifecycle/cmd/feature_gates_test.go +++ b/test/compatibility_lifecycle/cmd/feature_gates_test.go @@ -108,7 +108,7 @@ func TestVerifyOrUpdateFeatureListVersioned(t *testing.T) { lockToDefault: false preRelease: Beta version: "1.30" -- name: CPUCFSQuotaPeriod +- name: CustomCPUCFSQuotaPeriod versionedSpecs: - default: false lockToDefault: false @@ -136,6 +136,9 @@ import ( "k8s.io/apimachinery/pkg/util/version" "k8s.io/component-base/featuregate" ) + +const CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod" + var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate.VersionedSpecs{ AppArmorFields: { {Version: version.MajorMinor(1, 30), Default: true, PreRelease: featuregate.Beta}, @@ -166,6 +169,9 @@ import ( "k8s.io/apimachinery/pkg/util/version" "k8s.io/component-base/featuregate" ) + +const CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod" + var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate.VersionedSpecs{ AppArmorFields: { {Version: version.MajorMinor(1, 30), Default: true, PreRelease: featuregate.Beta}, @@ -196,7 +202,7 @@ var otherFeatureGates = map[featuregate.Feature]featuregate.VersionedSpecs{ lockToDefault: false preRelease: Beta version: "1.30" -- name: CPUCFSQuotaPeriod +- name: CustomCPUCFSQuotaPeriod versionedSpecs: - default: false lockToDefault: false @@ -276,6 +282,9 @@ import ( "k8s.io/apimachinery/pkg/util/version" "k8s.io/component-base/featuregate" ) + +const CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod" + var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate.VersionedSpecs{ AppArmorFields: { {Version: version.MajorMinor(1, 30), Default: true, PreRelease: featuregate.Beta}, @@ -312,7 +321,7 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate lockToDefault: false preRelease: Beta version: "1.30" -- name: CPUCFSQuotaPeriod +- name: CustomCPUCFSQuotaPeriod versionedSpecs: - default: false lockToDefault: false @@ -333,6 +342,9 @@ import ( "k8s.io/apimachinery/pkg/util/version" "k8s.io/component-base/featuregate" ) + +const CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod" + var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate.VersionedSpecs{ CPUCFSQuotaPeriod: { {Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha}, @@ -373,6 +385,9 @@ import ( "k8s.io/apimachinery/pkg/util/version" "k8s.io/component-base/featuregate" ) + +const CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod" + var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate.VersionedSpecs{ AppArmorFields: { {Version: version.MajorMinor(1, 30), Default: true, PreRelease: featuregate.Beta}, @@ -401,7 +416,7 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate lockToDefault: false preRelease: Beta version: "1.30" -- name: CPUCFSQuotaPeriod +- name: CustomCPUCFSQuotaPeriod versionedSpecs: - default: false lockToDefault: false diff --git a/test/compatibility_lifecycle/reference/versioned_feature_list.yaml b/test/compatibility_lifecycle/reference/versioned_feature_list.yaml index 1567f421beeb4..1fbb8f0ddf64e 100644 --- a/test/compatibility_lifecycle/reference/versioned_feature_list.yaml +++ b/test/compatibility_lifecycle/reference/versioned_feature_list.yaml @@ -339,16 +339,6 @@ lockToDefault: false preRelease: Beta version: "1.33" -- name: CPUCFSQuotaPeriod - versionedSpecs: - - default: false - lockToDefault: false - preRelease: Alpha - version: "1.12" - - default: true - lockToDefault: false - preRelease: GA - version: "1.36" - name: CPUManagerPolicyAlphaOptions versionedSpecs: - default: false @@ -427,6 +417,16 @@ lockToDefault: false preRelease: Alpha version: "1.21" +- name: CustomCPUCFSQuotaPeriod + versionedSpecs: + - default: false + lockToDefault: false + preRelease: Alpha + version: "1.12" + - default: true + lockToDefault: false + preRelease: GA + version: "1.36" - name: CustomResourceFieldSelectors versionedSpecs: - default: false @@ -1739,7 +1739,7 @@ lockToDefault: false preRelease: Beta version: "1.12" -- name: RuntimeClassInImageCriAPI +- name: RuntimeClassInImageCriApi versionedSpecs: - default: false lockToDefault: false From 746956bbd8de14bc96197b6d0e1dc3cd73590a45 Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Fri, 1 May 2026 23:08:29 +0000 Subject: [PATCH 03/19] flowcontrol: emit Required when spec.type or limitResponse.type is empty Handwritten validation previously fell through to NotSupported when PriorityLevelConfigurationSpec.Type or LimitResponse.Type was empty. The declarative validator emits FieldValueRequired for these fields, so the two paths disagreed for the empty case. Branch on len(Type)==0 to emit Required (matching declarative); keep NotSupported for unknown values. --- pkg/apis/flowcontrol/validation/validation.go | 12 +++++-- .../flowcontrol/validation/validation_test.go | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pkg/apis/flowcontrol/validation/validation.go b/pkg/apis/flowcontrol/validation/validation.go index 510b5e4a17114..d801f0e1382b2 100644 --- a/pkg/apis/flowcontrol/validation/validation.go +++ b/pkg/apis/flowcontrol/validation/validation.go @@ -416,7 +416,11 @@ func ValidatePriorityLevelConfigurationSpec(spec *flowcontrol.PriorityLevelConfi allErrs = append(allErrs, ValidateLimitedPriorityLevelConfiguration(spec.Limited, requestGV, fldPath.Child("limited"), opts)...) } default: - allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), spec.Type, supportedPriorityLevelEnablement.List())) + if len(spec.Type) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("type"), "").MarkCoveredByDeclarative()) + } else { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), spec.Type, supportedPriorityLevelEnablement.List())) + } } return allErrs } @@ -475,7 +479,11 @@ func ValidateLimitResponse(lr flowcontrol.LimitResponse, fldPath *field.Path) fi allErrs = append(allErrs, ValidatePriorityLevelQueuingConfiguration(lr.Queuing, fldPath.Child("queuing"))...) } default: - allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), lr.Type, supportedLimitResponseType.List())) + if len(lr.Type) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("type"), "").MarkCoveredByDeclarative()) + } else { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), lr.Type, supportedLimitResponseType.List())) + } } return allErrs } diff --git a/pkg/apis/flowcontrol/validation/validation_test.go b/pkg/apis/flowcontrol/validation/validation_test.go index 01a21ec01c00a..9c3b2d305e72f 100644 --- a/pkg/apis/flowcontrol/validation/validation_test.go +++ b/pkg/apis/flowcontrol/validation/validation_test.go @@ -1127,6 +1127,38 @@ func TestPriorityLevelConfigurationValidation(t *testing.T) { expectedErrors: field.ErrorList{ field.Forbidden(field.NewPath("metadata").Child("annotations"), fmt.Sprintf("annotation '%s' is forbidden", flowcontrolv1beta3.PriorityLevelPreserveZeroConcurrencySharesKey)), }, + }, { + name: "spec.type empty should fail with required", + priorityLevelConfiguration: &flowcontrol.PriorityLevelConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-empty-type", + }, + Spec: flowcontrol.PriorityLevelConfigurationSpec{ + Type: "", + }, + }, + expectedErrors: field.ErrorList{ + field.Required(field.NewPath("spec").Child("type"), "").MarkCoveredByDeclarative(), + }, + }, { + name: "spec.limited.limitResponse.type empty should fail with required", + priorityLevelConfiguration: &flowcontrol.PriorityLevelConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-empty-lr-type", + }, + Spec: flowcontrol.PriorityLevelConfigurationSpec{ + Type: flowcontrol.PriorityLevelEnablementLimited, + Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ + NominalConcurrencyShares: 42, + LimitResponse: flowcontrol.LimitResponse{ + Type: "", + }, + }, + }, + }, + expectedErrors: field.ErrorList{ + field.Required(field.NewPath("spec").Child("limited").Child("limitResponse").Child("type"), "").MarkCoveredByDeclarative(), + }, }} for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { From bed40bd59730ac9b9cc1fa032a806c09f4623e4f Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Fri, 1 May 2026 23:29:40 +0000 Subject: [PATCH 04/19] flowcontrol: cover Required rule for spec.type and limitResponse.type Add declarative-validation test cases for empty Spec.Type and empty LimitResponse.Type, closing the FieldValueRequired coverage gap reported for PriorityLevelConfiguration across v1, v1beta1, v1beta2, v1beta3. --- .../declarative_validation_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go b/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go index 4a36e699811be..f592972c95524 100644 --- a/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go +++ b/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go @@ -103,6 +103,18 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { field.Forbidden(specPath.Child("limited", "limitResponse", "queuing"), "").MarkCoveredByDeclarative().MarkAlpha(), }, }, + "spec.type: empty": { + input: mkPLC(tweakSpecType(""), tweakLimited(nil)), + expectedErrs: field.ErrorList{ + field.Required(specPath.Child("type"), "").MarkCoveredByDeclarative().MarkAlpha(), + }, + }, + "limitResponse.type: empty": { + input: mkPLC(tweakLimitResponseType("")), + expectedErrs: field.ErrorList{ + field.Required(specPath.Child("limited", "limitResponse", "type"), "").MarkCoveredByDeclarative().MarkAlpha(), + }, + }, } for name, tc := range testCases { @@ -226,6 +238,13 @@ func tweakLimited(limited *flowcontrol.LimitedPriorityLevelConfiguration) func(* } } +// tweakSpecType sets the Spec.Type field directly. +func tweakSpecType(t flowcontrol.PriorityLevelEnablement) func(*flowcontrol.PriorityLevelConfiguration) { + return func(obj *flowcontrol.PriorityLevelConfiguration) { + obj.Spec.Type = t + } +} + // tweakExemptConfig sets the Exempt configuration field. func tweakExemptConfig(exempt *flowcontrol.ExemptPriorityLevelConfiguration) func(*flowcontrol.PriorityLevelConfiguration) { return func(obj *flowcontrol.PriorityLevelConfiguration) { From ff173bd506f5bbd9ebe114ed7ca7407d3ca23c2a Mon Sep 17 00:00:00 2001 From: Akhil Singh Date: Wed, 3 Jun 2026 11:31:43 +0530 Subject: [PATCH 05/19] Fix job controller reporting active=0 during pod creation backoff When manageJob() needs to create replacement pods but defers creation because a pod-failure backoff is still active, it returned a hardcoded active=0 to the caller. Because no pods were actually created or deleted, this left Status.Active=0 while Status.Ready still reflected the running pods. The apiserver correctly rejects such updates ("cannot set more ready pods than active") with a 422, which blocks flushing uncounted terminated pods, removing finalizers, and updating job status, leaving pods stuck Terminating with stale status. Return the real active count from both backoff early-returns instead, since the deferral does not change the number of active pods. Issue: https://github.com/kubernetes/kubernetes/issues/139428 (cherry picked from commit 2fe49b0cd06a367b2eedc535fc51f0d8a8b1ecd6) --- pkg/controller/job/job_controller.go | 11 +++- pkg/controller/job/job_controller_test.go | 76 +++++++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/pkg/controller/job/job_controller.go b/pkg/controller/job/job_controller.go index ccf9b222c7cae..b7884a0800515 100644 --- a/pkg/controller/job/job_controller.go +++ b/pkg/controller/job/job_controller.go @@ -1855,7 +1855,12 @@ func (jm *Controller) manageJob(ctx context.Context, job *batch.Job, jobCtx *syn } if remainingTime > 0 { jm.enqueueSyncJobWithDelay(logger, job, remainingTime) - return 0, metrics.JobSyncActionPodsCreated, nil + // No pods were created or deleted, so return the current active + // count rather than 0. Returning 0 here would cause the status + // update to set Active=0 while Ready still reflects the running + // pods, which the API server rejects ("cannot set more ready pods + // than active"), blocking finalizer removal and status flushing. + return active, metrics.JobSyncActionPodsCreated, nil } if diff > int32(MaxPodCreateDeletePerSync) { diff = int32(MaxPodCreateDeletePerSync) @@ -1868,7 +1873,9 @@ func (jm *Controller) manageJob(ctx context.Context, job *batch.Job, jobCtx *syn indexesToAdd, remainingTime = jm.getPodCreationInfoForIndependentIndexes(logger, indexesToAdd, jobCtx.podsWithDelayedDeletionPerIndex) if remainingTime > 0 { jm.enqueueSyncJobWithDelay(logger, job, remainingTime) - return 0, metrics.JobSyncActionPodsCreated, nil + // No pods were created or deleted, so return the current + // active count rather than 0 (see comment above). + return active, metrics.JobSyncActionPodsCreated, nil } } diff = int32(len(indexesToAdd)) diff --git a/pkg/controller/job/job_controller_test.go b/pkg/controller/job/job_controller_test.go index 5c8797ea17611..1c9597e9a2e8e 100644 --- a/pkg/controller/job/job_controller_test.go +++ b/pkg/controller/job/job_controller_test.go @@ -453,6 +453,36 @@ func TestControllerSyncJob(t *testing.T) { expectedReady: ptr.To[int32](0), controllerTime: &referenceTime, }, + // Regression test for https://github.com/kubernetes/kubernetes/issues/139428. + // When replacement pods are needed but pod creation is deferred due to an + // active backoff, manageJob must report the actual active count rather than + // 0. Reporting 0 while Ready still reflects the running pods makes the status + // update fail apiserver validation ("cannot set more ready pods than active"), + // blocking finalizer removal and status flushing. + "too few active pods and active back-off with running pods": { + parallelism: 2, + completions: 2, + backoffLimit: 6, + backoffRecord: &backoffRecord{ + failuresAfterLastSuccess: 1, + lastFailureTime: &referenceTime, + }, + initialStatus: &jobInitialStatus{ + startTime: func() *time.Time { + now := time.Now() + return &now + }(), + }, + activePods: 1, + readyPods: 1, + succeededPods: 0, + expectedCreations: 0, + expectedActive: 1, + expectedSucceeded: 0, + expectedPodPatches: 0, + expectedReady: ptr.To[int32](1), + controllerTime: &referenceTime, + }, "too few active pods and no back-offs": { parallelism: 1, completions: 1, @@ -5377,6 +5407,52 @@ func TestSyncJobWithJobBackoffLimitPerIndex(t *testing.T) { FailedIndexes: ptr.To(""), }, }, + // Regression test for https://github.com/kubernetes/kubernetes/issues/139428. + // One index has a running pod while another index's replacement pod + // creation is deferred because its per-index backoff is still active. + // manageJob must report the actual active count (1) rather than 0; a + // status with active=0 while pods are still running is rejected by the + // apiserver ("cannot set more ready pods than active"), blocking + // finalizer removal and status flushing. + "replacement pod creation delayed by per-index backoff while another index runs": { + enableJobBackoffLimitPerIndex: true, + enableJobPodReplacementPolicy: true, + job: batch.Job{ + TypeMeta: metav1.TypeMeta{Kind: "Job"}, + ObjectMeta: validObjectMeta, + Spec: batch.JobSpec{ + Selector: validSelector, + Template: validTemplate, + Parallelism: ptr.To[int32](2), + Completions: ptr.To[int32](2), + BackoffLimit: ptr.To[int32](math.MaxInt32), + CompletionMode: ptr.To(batch.IndexedCompletion), + BackoffLimitPerIndex: ptr.To[int32](1), + }, + }, + pods: []v1.Pod{ + *buildPod().uid("a").index("0").phase(v1.PodRunning).indexFailureCount("0").trackingFinalizer().Pod, + *buildPod().uid("b").index("1").status(v1.PodStatus{ + Phase: v1.PodFailed, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "x", + State: v1.ContainerState{ + Terminated: &v1.ContainerStateTerminated{ + FinishedAt: metav1.NewTime(now), + }, + }, + }, + }, + }).indexFailureCount("0").trackingFinalizer().Pod, + }, + wantStatus: batch.JobStatus{ + Active: 1, + Terminating: ptr.To[int32](0), + UncountedTerminatedPods: &batch.UncountedTerminatedPods{}, + FailedIndexes: new(string), + }, + }, "single failed index due to exceeding the backoff limit per index, the job continues": { enableJobBackoffLimitPerIndex: true, enableJobPodReplacementPolicy: true, From 903e7fc93bf47151cf6d978fe0b422be44acb6e0 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Thu, 11 Jun 2026 18:21:48 +0000 Subject: [PATCH 06/19] Update CHANGELOG/CHANGELOG-1.36.md for v1.36.2 --- CHANGELOG/CHANGELOG-1.36.md | 231 +++++++++++++++++++++++++++--------- 1 file changed, 176 insertions(+), 55 deletions(-) diff --git a/CHANGELOG/CHANGELOG-1.36.md b/CHANGELOG/CHANGELOG-1.36.md index dd1dc99b77eef..032ae4e00585d 100644 --- a/CHANGELOG/CHANGELOG-1.36.md +++ b/CHANGELOG/CHANGELOG-1.36.md @@ -1,139 +1,260 @@ -- [v1.36.1](#v1361) - - [Downloads for v1.36.1](#downloads-for-v1361) +- [v1.36.2](#v1362) + - [Downloads for v1.36.2](#downloads-for-v1362) - [Source Code](#source-code) - [Client Binaries](#client-binaries) - [Server Binaries](#server-binaries) - [Node Binaries](#node-binaries) - [Container Images](#container-images) - - [Changelog since v1.36.0](#changelog-since-v1360) + - [Changelog since v1.36.1](#changelog-since-v1361) - [Changes by Kind](#changes-by-kind) + - [Feature](#feature) - [Bug or Regression](#bug-or-regression) - [Dependencies](#dependencies) - [Added](#added) - [Changed](#changed) - [Removed](#removed) -- [v1.36.0](#v1360) - - [Downloads for v1.36.0](#downloads-for-v1360) +- [v1.36.1](#v1361) + - [Downloads for v1.36.1](#downloads-for-v1361) - [Source Code](#source-code-1) - [Client Binaries](#client-binaries-1) - [Server Binaries](#server-binaries-1) - [Node Binaries](#node-binaries-1) - [Container Images](#container-images-1) - - [Changelog since v1.35.0](#changelog-since-v1350) - - [Urgent Upgrade Notes](#urgent-upgrade-notes) - - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade) + - [Changelog since v1.36.0](#changelog-since-v1360) - [Changes by Kind](#changes-by-kind-1) - - [Dependency](#dependency) - - [Deprecation](#deprecation) - - [API Change](#api-change) - - [Feature](#feature) - - [Documentation](#documentation) - - [Failing Test](#failing-test) - [Bug or Regression](#bug-or-regression-1) - - [Other (Cleanup or Flake)](#other-cleanup-or-flake) - [Dependencies](#dependencies-1) - [Added](#added-1) - [Changed](#changed-1) - [Removed](#removed-1) -- [v1.36.0-rc.1](#v1360-rc1) - - [Downloads for v1.36.0-rc.1](#downloads-for-v1360-rc1) +- [v1.36.0](#v1360) + - [Downloads for v1.36.0](#downloads-for-v1360) - [Source Code](#source-code-2) - [Client Binaries](#client-binaries-2) - [Server Binaries](#server-binaries-2) - [Node Binaries](#node-binaries-2) - [Container Images](#container-images-2) - - [Changelog since v1.36.0-rc.0](#changelog-since-v1360-rc0) + - [Changelog since v1.35.0](#changelog-since-v1350) + - [Urgent Upgrade Notes](#urgent-upgrade-notes) + - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade) + - [Changes by Kind](#changes-by-kind-2) + - [Dependency](#dependency) + - [Deprecation](#deprecation) + - [API Change](#api-change) + - [Feature](#feature-1) + - [Documentation](#documentation) + - [Failing Test](#failing-test) + - [Bug or Regression](#bug-or-regression-2) + - [Other (Cleanup or Flake)](#other-cleanup-or-flake) - [Dependencies](#dependencies-2) - [Added](#added-2) - [Changed](#changed-2) - [Removed](#removed-2) -- [v1.36.0-rc.0](#v1360-rc0) - - [Downloads for v1.36.0-rc.0](#downloads-for-v1360-rc0) +- [v1.36.0-rc.1](#v1360-rc1) + - [Downloads for v1.36.0-rc.1](#downloads-for-v1360-rc1) - [Source Code](#source-code-3) - [Client Binaries](#client-binaries-3) - [Server Binaries](#server-binaries-3) - [Node Binaries](#node-binaries-3) - [Container Images](#container-images-3) - - [Changelog since v1.36.0-beta.0](#changelog-since-v1360-beta0) - - [Changes by Kind](#changes-by-kind-2) - - [API Change](#api-change-1) - - [Feature](#feature-1) - - [Bug or Regression](#bug-or-regression-2) - - [Other (Cleanup or Flake)](#other-cleanup-or-flake-1) + - [Changelog since v1.36.0-rc.0](#changelog-since-v1360-rc0) - [Dependencies](#dependencies-3) - [Added](#added-3) - [Changed](#changed-3) - [Removed](#removed-3) -- [v1.36.0-beta.0](#v1360-beta0) - - [Downloads for v1.36.0-beta.0](#downloads-for-v1360-beta0) +- [v1.36.0-rc.0](#v1360-rc0) + - [Downloads for v1.36.0-rc.0](#downloads-for-v1360-rc0) - [Source Code](#source-code-4) - [Client Binaries](#client-binaries-4) - [Server Binaries](#server-binaries-4) - [Node Binaries](#node-binaries-4) - [Container Images](#container-images-4) - - [Changelog since v1.36.0-alpha.2](#changelog-since-v1360-alpha2) - - [Urgent Upgrade Notes](#urgent-upgrade-notes-1) - - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade-1) + - [Changelog since v1.36.0-beta.0](#changelog-since-v1360-beta0) - [Changes by Kind](#changes-by-kind-3) - - [Deprecation](#deprecation-1) - - [API Change](#api-change-2) + - [API Change](#api-change-1) - [Feature](#feature-2) - - [Documentation](#documentation-1) - - [Failing Test](#failing-test-1) - [Bug or Regression](#bug-or-regression-3) - - [Other (Cleanup or Flake)](#other-cleanup-or-flake-2) + - [Other (Cleanup or Flake)](#other-cleanup-or-flake-1) - [Dependencies](#dependencies-4) - [Added](#added-4) - [Changed](#changed-4) - [Removed](#removed-4) -- [v1.36.0-alpha.2](#v1360-alpha2) - - [Downloads for v1.36.0-alpha.2](#downloads-for-v1360-alpha2) +- [v1.36.0-beta.0](#v1360-beta0) + - [Downloads for v1.36.0-beta.0](#downloads-for-v1360-beta0) - [Source Code](#source-code-5) - [Client Binaries](#client-binaries-5) - [Server Binaries](#server-binaries-5) - [Node Binaries](#node-binaries-5) - [Container Images](#container-images-5) - - [Changelog since v1.36.0-alpha.1](#changelog-since-v1360-alpha1) - - [Urgent Upgrade Notes](#urgent-upgrade-notes-2) - - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade-2) + - [Changelog since v1.36.0-alpha.2](#changelog-since-v1360-alpha2) + - [Urgent Upgrade Notes](#urgent-upgrade-notes-1) + - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade-1) - [Changes by Kind](#changes-by-kind-4) - - [Dependency](#dependency-1) - - [Deprecation](#deprecation-2) - - [API Change](#api-change-3) + - [Deprecation](#deprecation-1) + - [API Change](#api-change-2) - [Feature](#feature-3) - - [Failing Test](#failing-test-2) + - [Documentation](#documentation-1) + - [Failing Test](#failing-test-1) - [Bug or Regression](#bug-or-regression-4) - - [Other (Cleanup or Flake)](#other-cleanup-or-flake-3) + - [Other (Cleanup or Flake)](#other-cleanup-or-flake-2) - [Dependencies](#dependencies-5) - [Added](#added-5) - [Changed](#changed-5) - [Removed](#removed-5) -- [v1.36.0-alpha.1](#v1360-alpha1) - - [Downloads for v1.36.0-alpha.1](#downloads-for-v1360-alpha1) +- [v1.36.0-alpha.2](#v1360-alpha2) + - [Downloads for v1.36.0-alpha.2](#downloads-for-v1360-alpha2) - [Source Code](#source-code-6) - [Client Binaries](#client-binaries-6) - [Server Binaries](#server-binaries-6) - [Node Binaries](#node-binaries-6) - [Container Images](#container-images-6) - - [Changelog since v1.35.0](#changelog-since-v1350-1) - - [Urgent Upgrade Notes](#urgent-upgrade-notes-3) - - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade-3) + - [Changelog since v1.36.0-alpha.1](#changelog-since-v1360-alpha1) + - [Urgent Upgrade Notes](#urgent-upgrade-notes-2) + - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade-2) - [Changes by Kind](#changes-by-kind-5) - - [Dependency](#dependency-2) - - [API Change](#api-change-4) + - [Dependency](#dependency-1) + - [Deprecation](#deprecation-2) + - [API Change](#api-change-3) - [Feature](#feature-4) - - [Failing Test](#failing-test-3) + - [Failing Test](#failing-test-2) - [Bug or Regression](#bug-or-regression-5) - - [Other (Cleanup or Flake)](#other-cleanup-or-flake-4) + - [Other (Cleanup or Flake)](#other-cleanup-or-flake-3) - [Dependencies](#dependencies-6) - [Added](#added-6) - [Changed](#changed-6) - [Removed](#removed-6) +- [v1.36.0-alpha.1](#v1360-alpha1) + - [Downloads for v1.36.0-alpha.1](#downloads-for-v1360-alpha1) + - [Source Code](#source-code-7) + - [Client Binaries](#client-binaries-7) + - [Server Binaries](#server-binaries-7) + - [Node Binaries](#node-binaries-7) + - [Container Images](#container-images-7) + - [Changelog since v1.35.0](#changelog-since-v1350-1) + - [Urgent Upgrade Notes](#urgent-upgrade-notes-3) + - [(No, really, you MUST read this before you upgrade)](#no-really-you-must-read-this-before-you-upgrade-3) + - [Changes by Kind](#changes-by-kind-6) + - [Dependency](#dependency-2) + - [API Change](#api-change-4) + - [Feature](#feature-5) + - [Failing Test](#failing-test-3) + - [Bug or Regression](#bug-or-regression-6) + - [Other (Cleanup or Flake)](#other-cleanup-or-flake-4) + - [Dependencies](#dependencies-7) + - [Added](#added-7) + - [Changed](#changed-7) + - [Removed](#removed-7) +# v1.36.2 + + +## Downloads for v1.36.2 + + + +### Source Code + +filename | sha512 hash +-------- | ----------- +[kubernetes.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes.tar.gz) | aef47a1cdd9a8aad387ee3aaeb3d681affe6af1231b72c67d73264d177bb63a5bbcf050fc0562a8310e6ed64be5fb0672e638e104dc630e6b6a82e15acc5ff66 +[kubernetes-src.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-src.tar.gz) | fad7f78605f87a93199316f7fb3f586e4531c41476c53fedee92fdd5bd641a9128c5cde45b6859e07eb2ab254873f1845236c0a33934cba918ff5b97d0cf571d + +### Client Binaries + +filename | sha512 hash +-------- | ----------- +[kubernetes-client-darwin-amd64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-darwin-amd64.tar.gz) | 71ad2179e6cfbfc85b162da58b3ad7143ed94eba62185b23f4b02445b664b155db590aae4c56c5be04d9b9a1d460db2b5779536d9a1f0ff00b00b285fe141259 +[kubernetes-client-darwin-arm64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-darwin-arm64.tar.gz) | 9cdf5cb41032a632ec9434f5b1ce11be71c4648860d658dc78e55837956f7df080f8d47b81f5c901eb4599722c2f5f967ef04922aad51e3a027a76731604b5d5 +[kubernetes-client-linux-386.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-linux-386.tar.gz) | 7b18df02a37ab4ae8a5fbc363baa1032204c3d532cc8f0be1f762f0e9f950ba2b7be99f1ec197b1ce28a89c09c5e77f088107b588d25eed61ad33ad1a24b0198 +[kubernetes-client-linux-amd64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-linux-amd64.tar.gz) | bf3fa2fe065af663b944acdef42ab61a0062e01d325d60d756aaab22bb412addc2ffa77fdcb39de47560c5613a9bcd68e67ea83417626aefbe52db9cc76fde7d +[kubernetes-client-linux-arm.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-linux-arm.tar.gz) | c4fe54b27ab0cb342967d0911e0f695cc1226ed3f4f0fc84080d547fa8c92b343d75054cbc1e51e9af5c066f475b5b4463f029a7e883c83d986e5142cc2464df +[kubernetes-client-linux-arm64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-linux-arm64.tar.gz) | ef798cdab3538164ecd6b3c1987c69e4094c14d3e88a31811964cd0b57536a4b488b0b9f37a4ad7139d25f1b73c019d2791f9e58017cce929bc0e8262484496d +[kubernetes-client-linux-ppc64le.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-linux-ppc64le.tar.gz) | 9f0474cbce05b41674a1e49fe5dc7c4f88cfe7db18c6c60d6b93a1ccff4ec1ee6c23633b45ea1b1715f2c00191eee0a2dbec6fbba3297e80279b1b648c8b7fd7 +[kubernetes-client-linux-s390x.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-linux-s390x.tar.gz) | 4e39e5c5160cd2a1379749f055a0555ba682fec6a924a271a5b45a185995a95093ca6e76bc1ad9ba2863b7ae0ea38368e9b15aa1282775263d0ccecf735052f5 +[kubernetes-client-windows-386.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-windows-386.tar.gz) | 23218ac82fcb2ec98e3af1e1a11cee6b20eb7bc610366dfb7aafbb82e9ab2c890a71256f7f52d3c68f8d4e8abf21672ef142735a3463fc89498ecdd6973b1a4d +[kubernetes-client-windows-amd64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-windows-amd64.tar.gz) | 853ee9d8783f16236285fc4b37bbf972719c8061ff99a4b61c2a7c680441ac98886885723b31a9b418b3236ee0d5876268efb42de1e4b5355facd5305bfd7802 +[kubernetes-client-windows-arm64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-client-windows-arm64.tar.gz) | a036865e990eb797dd2eef91983fb518712c76c640c66d3c5b80a41a89c283feb61a16b0869209229be0d38392b9d0c316c45836790f4934ba3dcaf065e6910f + +### Server Binaries + +filename | sha512 hash +-------- | ----------- +[kubernetes-server-linux-amd64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-server-linux-amd64.tar.gz) | 0c617cb74f6a8ddc142afd453b3ece4b39268d78febdbe9df91faf3a01031d364e9347bf8dfdc336e9ed0fe64ad82ce0209ef9fc0340e7d2f784d37bfa7e0d18 +[kubernetes-server-linux-arm64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-server-linux-arm64.tar.gz) | 7226d91204980892f593307f06acefd5579337ec5758c8615a0e46541a990083c6be9809b01fb9e06da7e9b6d7208a673fd5129b7145436c3fe6e726d1fa469d +[kubernetes-server-linux-ppc64le.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-server-linux-ppc64le.tar.gz) | 791c496395c6834554d05a0bbba11e5ab99dc8a2639f1adb53ccbc91919b6760339378a02d05bbc9543e3d018440f258426ed5c2625ddc56cc613e5c952c2c2f +[kubernetes-server-linux-s390x.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-server-linux-s390x.tar.gz) | b2f24c710a4e1124a0b352c85f2d3316cac9d711e879cd081ad3ea1d646c034ceecc7f892364646516fafec61efe20621bfb0eb3f5c94052cf2d6c92da091c1d + +### Node Binaries + +filename | sha512 hash +-------- | ----------- +[kubernetes-node-linux-amd64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-node-linux-amd64.tar.gz) | 24b95198259d96990d1aa4a625c15017348affe2ef7964225968e58b30d622c6dabfaf1c7abe12d1103b3879f0e887bf956259ee160eab3bcb24d7d3f5a72dab +[kubernetes-node-linux-arm64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-node-linux-arm64.tar.gz) | 2dc8926b5f5d08e7f3133e7ca9a50365e6f424f40a6c6931c57b64e0f93440430bf628ac31579d3b9a9d8dbf519e5b7d76e044b7198011e519eeb96e8545e6c2 +[kubernetes-node-linux-ppc64le.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-node-linux-ppc64le.tar.gz) | f69d6b1e29bd978085376f014023a792e2571865950794bf6cbde9dc65440ce3a3c0a47f1ffc2a8a8bfa0bc546d32980954d4b7adb71589fbeaeec8081cbe284 +[kubernetes-node-linux-s390x.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-node-linux-s390x.tar.gz) | cc0d4198955e55cca46de24548ccbd398f96e9e6b3dcc381d3b68706847b1e39e6992757a8927a4fce968399d9459cd26465e02d9be0f3e707507459c1e5aad9 +[kubernetes-node-windows-amd64.tar.gz](https://dl.k8s.io/v1.36.2/kubernetes-node-windows-amd64.tar.gz) | aaa965f855ef9eede65b3101b6885555661d355a1805ebf351cfb66c6e9219489f982f63d40c1aa241df827d5646fb8f06bab398deadac9724a85b791f7ecedb + +### Container Images + +All container images are available as manifest lists and support the described +architectures. It is also possible to pull a specific architecture directly by +adding the "-$ARCH" suffix to the container image name. + +name | architectures +---- | ------------- +[registry.k8s.io/conformance:v1.36.2](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/conformance) | [amd64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/conformance-amd64), [arm64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/conformance-arm64), [ppc64le](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/conformance-ppc64le), [s390x](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/conformance-s390x) +[registry.k8s.io/kube-apiserver:v1.36.2](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-apiserver) | [amd64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-apiserver-amd64), [arm64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-apiserver-arm64), [ppc64le](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-apiserver-ppc64le), [s390x](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-apiserver-s390x) +[registry.k8s.io/kube-controller-manager:v1.36.2](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-controller-manager) | [amd64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-controller-manager-amd64), [arm64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-controller-manager-arm64), [ppc64le](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-controller-manager-ppc64le), [s390x](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-controller-manager-s390x) +[registry.k8s.io/kube-proxy:v1.36.2](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-proxy) | [amd64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-proxy-amd64), [arm64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-proxy-arm64), [ppc64le](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-proxy-ppc64le), [s390x](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-proxy-s390x) +[registry.k8s.io/kube-scheduler:v1.36.2](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-scheduler) | [amd64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-scheduler-amd64), [arm64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-scheduler-arm64), [ppc64le](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-scheduler-ppc64le), [s390x](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kube-scheduler-s390x) +[registry.k8s.io/kubectl:v1.36.2](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kubectl) | [amd64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kubectl-amd64), [arm64](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kubectl-arm64), [ppc64le](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kubectl-ppc64le), [s390x](https://console.cloud.google.com/artifacts/docker/k8s-artifacts-prod/southamerica-east1/images/kubectl-s390x) + +## Changelog since v1.36.1 + +## Changes by Kind + +### Feature + +- Kubernetes is now built using Go 1.26.4 ([#139585](https://github.com/kubernetes/kubernetes/pull/139585), [@cpanato](https://github.com/cpanato)) [SIG Release and Testing] +- Kubernetes is now built with Go 1.26.4 ([#138871](https://github.com/kubernetes/kubernetes/pull/138871), [@BenTheElder](https://github.com/BenTheElder)) [SIG Release] + +### Bug or Regression + +- Avoid costly comparisons during selinux metric emission. ([#139136](https://github.com/kubernetes/kubernetes/pull/139136), [@gnufied](https://github.com/gnufied)) [SIG Apps and Storage] +- Fixed a Dynamic Resource Allocation scheduler bug that could assign mutually exclusive + device partitions to multiple Pods. This affected DRA drivers using `SharedCounters` + (`DRAPartitionableDevices`) together with multi-allocatable devices (`DRAConsumableCapacity`). + Depending on the device and driver, the incorrect double-allocation could cause workload failures, + device conflicts, crashes, or data loss. ([#139211](https://github.com/kubernetes/kubernetes/pull/139211), [@ashvindeodhar](https://github.com/ashvindeodhar)) [SIG Node] +- Fixed a bug where Pods that share multi-node claims and also have per-node claims can get stuck in Pending. ([#139363](https://github.com/kubernetes/kubernetes/pull/139363), [@nojnhuh](https://github.com/nojnhuh)) [SIG Node and Scheduling] +- Fixed a kube-scheduler panic when a DRA ResourceClaim using `allocationMode: All` selects a device that consumes shared counters. ([#138988](https://github.com/kubernetes/kubernetes/pull/138988), [@pohly](https://github.com/pohly)) [SIG Node] +- Fixed a panic in the endpoint controller when processing services with empty IPFamilies field (pre-dual-stack services that were never spec-updated). ([#139233](https://github.com/kubernetes/kubernetes/pull/139233), [@rahulbabu95](https://github.com/rahulbabu95)) [SIG Apps and Network] +- Fixed a regression in 1.36 where modifications to scheduling directives (nodeSelector, tolerations, node affinity) on suspended Jobs were rejected if the JobSuspended condition had not yet been set by the job controller. ([#139329](https://github.com/kubernetes/kubernetes/pull/139329), [@kannon92](https://github.com/kannon92)) [SIG Apps and Testing] +- Fixed an issue where kubelet would delete the CSI mount directory when + a periodic NodePublishVolume call (triggered by + CSIDriver.spec.requiresRepublish=true) returned an error, leaving the + pod with stale volume contents that subsequent successful republishes + could not repair. ([#139228](https://github.com/kubernetes/kubernetes/pull/139228), [@aramase](https://github.com/aramase)) [SIG Storage] +- Fixes a 1.34+ regression handling containers with environment values set from Secret API objects containing binary non-utf8 data. ([#139192](https://github.com/kubernetes/kubernetes/pull/139192), [@liggitt](https://github.com/liggitt)) [SIG Node] +- Kubeadm: fixed kubeadm init phase certs --dry-run to correctly copy existing CA files. ([#139445](https://github.com/kubernetes/kubernetes/pull/139445), [@HirazawaUi](https://github.com/HirazawaUi)) [SIG Cluster Lifecycle] + +## Dependencies + +### Added +_Nothing has changed._ + +### Changed +_Nothing has changed._ + +### Removed +_Nothing has changed._ + + + # v1.36.1 From d20c60aa5537f5bc7cb0661ac939c34638b714af Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Thu, 11 Jun 2026 12:11:16 -0500 Subject: [PATCH 07/19] Align DeviceTaintRule informer API version with handlers --- .../resourceslice/tracker/tracker.go | 20 ++-- .../resourceslice/tracker/tracker_test.go | 92 +++++++++---------- test/integration/dra/device_taints.go | 92 +++++++++++++++++++ test/integration/dra/dra.go | 4 + 4 files changed, 152 insertions(+), 56 deletions(-) diff --git a/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker.go b/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker.go index 9941a38c3f010..e86ac3ddcaa86 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker.go +++ b/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker.go @@ -25,7 +25,7 @@ import ( v1 "k8s.io/api/core/v1" resourceapi "k8s.io/api/resource/v1" - resourcealphaapi "k8s.io/api/resource/v1alpha3" + resourcebetaapi "k8s.io/api/resource/v1beta2" labels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/diff" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -395,15 +395,15 @@ func sliceDriverPoolDeviceIndexFunc(obj any) ([]string, error) { return indexValues, nil } -func driverPoolDeviceIndexPatchKey(patch *resourcealphaapi.DeviceTaintRule) string { - deviceSelector := ptr.Deref(patch.Spec.DeviceSelector, resourcealphaapi.DeviceTaintSelector{}) +func driverPoolDeviceIndexPatchKey(patch *resourcebetaapi.DeviceTaintRule) string { + deviceSelector := ptr.Deref(patch.Spec.DeviceSelector, resourcebetaapi.DeviceTaintSelector{}) driverKey := ptr.Deref(deviceSelector.Driver, anyDriver) poolKey := ptr.Deref(deviceSelector.Pool, anyPool) deviceKey := ptr.Deref(deviceSelector.Device, anyDevice) return deviceID(driverKey, poolKey, deviceKey) } -func (t *Tracker) sliceNamesForPatch(ctx context.Context, patch *resourcealphaapi.DeviceTaintRule) []string { +func (t *Tracker) sliceNamesForPatch(ctx context.Context, patch *resourcebetaapi.DeviceTaintRule) []string { patchKey := driverPoolDeviceIndexPatchKey(patch) sliceNames, err := t.resourceSlices.GetIndexer().IndexKeys(driverPoolDeviceIndexName, patchKey) if err != nil { @@ -469,7 +469,7 @@ func (t *Tracker) resourceSliceDelete(ctx context.Context) func(obj any) { func (t *Tracker) deviceTaintAdd(ctx context.Context) func(obj any) { logger := klog.FromContext(ctx) return func(obj any) { - rule, ok := obj.(*resourcealphaapi.DeviceTaintRule) + rule, ok := obj.(*resourcebetaapi.DeviceTaintRule) if !ok { return } @@ -487,11 +487,11 @@ func (t *Tracker) deviceTaintAdd(ctx context.Context) func(obj any) { func (t *Tracker) deviceTaintUpdate(ctx context.Context) func(oldObj, newObj any) { logger := klog.FromContext(ctx) return func(oldObj, newObj any) { - oldRule, ok := oldObj.(*resourcealphaapi.DeviceTaintRule) + oldRule, ok := oldObj.(*resourcebetaapi.DeviceTaintRule) if !ok { return } - newRule, ok := newObj.(*resourcealphaapi.DeviceTaintRule) + newRule, ok := newObj.(*resourcebetaapi.DeviceTaintRule) if !ok { return } @@ -519,7 +519,7 @@ func (t *Tracker) deviceTaintDelete(ctx context.Context) func(obj any) { if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok { obj = tombstone.Obj } - patch, ok := obj.(*resourcealphaapi.DeviceTaintRule) + patch, ok := obj.(*resourcebetaapi.DeviceTaintRule) if !ok { return } @@ -631,7 +631,7 @@ func (t *Tracker) syncSlice(ctx context.Context, name string, sendEvent bool) { return } - patches := typedSlice[*resourcealphaapi.DeviceTaintRule](t.deviceTaints.GetIndexer().List()) + patches := typedSlice[*resourcebetaapi.DeviceTaintRule](t.deviceTaints.GetIndexer().List()) patchedSlice, err := t.applyPatches(ctx, slice, patches) if err != nil { t.handleError(ctx, err, "failed to apply patches to ResourceSlice", "resourceslice", klog.KObj(slice)) @@ -666,7 +666,7 @@ func (t *Tracker) syncSlice(ctx context.Context, name string, sendEvent bool) { } } -func (t *Tracker) applyPatches(ctx context.Context, slice *resourceapi.ResourceSlice, taintRules []*resourcealphaapi.DeviceTaintRule) (*resourceapi.ResourceSlice, error) { +func (t *Tracker) applyPatches(ctx context.Context, slice *resourceapi.ResourceSlice, taintRules []*resourcebetaapi.DeviceTaintRule) (*resourceapi.ResourceSlice, error) { logger := klog.FromContext(ctx) // slice will be DeepCopied just-in-time, only when necessary. diff --git a/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker_test.go b/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker_test.go index 8a5221eacbea8..572c7a251c617 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker_test.go +++ b/staging/src/k8s.io/dynamic-resource-allocation/resourceslice/tracker/tracker_test.go @@ -30,7 +30,7 @@ import ( "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" resourceapi "k8s.io/api/resource/v1" - resourcealphaapi "k8s.io/api/resource/v1alpha3" + resourcebetaapi "k8s.io/api/resource/v1beta2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" @@ -116,7 +116,7 @@ func applyEventPair(tCtx *testContext, event any) { require.NoError(tCtx, err) tCtx.resourceSliceAdd(tCtx.Context)(pair[1]) } - case [2]*resourcealphaapi.DeviceTaintRule: + case [2]*resourcebetaapi.DeviceTaintRule: store := tCtx.deviceTaints.GetStore() switch { case pair[0] != nil && pair[1] != nil: @@ -279,39 +279,39 @@ var ( slice2 = sliceWithDevices(slice2NoDevices, devices2) slice2Tainted = sliceWithDevices(slice2, taintedDevices2) - alphaDeviceTaint = func(taint resourceapi.DeviceTaint) resourcealphaapi.DeviceTaint { - return resourcealphaapi.DeviceTaint{ + alphaDeviceTaint = func(taint resourceapi.DeviceTaint) resourcebetaapi.DeviceTaint { + return resourcebetaapi.DeviceTaint{ Key: taint.Key, Value: taint.Value, - Effect: resourcealphaapi.DeviceTaintEffect(taint.Effect), + Effect: resourcebetaapi.DeviceTaintEffect(taint.Effect), TimeAdded: taint.TimeAdded, } } - taintAllDevicesRule = &resourcealphaapi.DeviceTaintRule{ + taintAllDevicesRule = &resourcebetaapi.DeviceTaintRule{ ObjectMeta: metav1.ObjectMeta{ Name: "rule", }, - Spec: resourcealphaapi.DeviceTaintRuleSpec{ + Spec: resourcebetaapi.DeviceTaintRuleSpec{ Taint: alphaDeviceTaint(deviceTaint1), }, } - taintPoolDevicesRule = func(rule *resourcealphaapi.DeviceTaintRule, pool string) *resourcealphaapi.DeviceTaintRule { + taintPoolDevicesRule = func(rule *resourcebetaapi.DeviceTaintRule, pool string) *resourcebetaapi.DeviceTaintRule { rule = rule.DeepCopy() - rule.Spec.DeviceSelector = &resourcealphaapi.DeviceTaintSelector{ + rule.Spec.DeviceSelector = &resourcebetaapi.DeviceTaintSelector{ Pool: &pool, } return rule } - taintDriverDevicesRule = func(rule *resourcealphaapi.DeviceTaintRule, driver string) *resourcealphaapi.DeviceTaintRule { + taintDriverDevicesRule = func(rule *resourcebetaapi.DeviceTaintRule, driver string) *resourcebetaapi.DeviceTaintRule { rule = rule.DeepCopy() - rule.Spec.DeviceSelector = &resourcealphaapi.DeviceTaintSelector{ + rule.Spec.DeviceSelector = &resourcebetaapi.DeviceTaintSelector{ Driver: &driver, } return rule } - taintNamedDevicesRule = func(rule *resourcealphaapi.DeviceTaintRule, name string) *resourcealphaapi.DeviceTaintRule { + taintNamedDevicesRule = func(rule *resourcebetaapi.DeviceTaintRule, name string) *resourcebetaapi.DeviceTaintRule { rule = rule.DeepCopy() - rule.Spec.DeviceSelector = &resourcealphaapi.DeviceTaintSelector{ + rule.Spec.DeviceSelector = &resourcebetaapi.DeviceTaintSelector{ Device: &name, } return rule @@ -720,8 +720,8 @@ func BenchmarkEventHandlers(b *testing.B) { now := time.Now() benchmarks := map[string]struct { resourceSlices []*resourceapi.ResourceSlice - taintRules []*resourcealphaapi.DeviceTaintRule - loop func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcealphaapi.DeviceTaintRule, i int) + taintRules []*resourcebetaapi.DeviceTaintRule + loop func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcebetaapi.DeviceTaintRule, i int) }{ "resource-slice-add-no-taint-rules": { resourceSlices: func() []*resourceapi.ResourceSlice { @@ -738,7 +738,7 @@ func BenchmarkEventHandlers(b *testing.B) { } return resourceSlices }(), - loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, _ []*resourcealphaapi.DeviceTaintRule, i int) { + loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, _ []*resourcebetaapi.DeviceTaintRule, i int) { tracker.resourceSliceAdd(ctx)(resourceSlices[i%len(resourceSlices)]) }, }, @@ -757,23 +757,23 @@ func BenchmarkEventHandlers(b *testing.B) { } return resourceSlices }(), - taintRules: []*resourcealphaapi.DeviceTaintRule{ + taintRules: []*resourcebetaapi.DeviceTaintRule{ { ObjectMeta: metav1.ObjectMeta{ Name: "taintRule", }, - Spec: resourcealphaapi.DeviceTaintRuleSpec{ + Spec: resourcebetaapi.DeviceTaintRuleSpec{ DeviceSelector: nil, // all slices - Taint: resourcealphaapi.DeviceTaint{ + Taint: resourcebetaapi.DeviceTaint{ Key: "example.com/taint", Value: "tainted", - Effect: resourcealphaapi.DeviceTaintEffectNoExecute, + Effect: resourcebetaapi.DeviceTaintEffectNoExecute, TimeAdded: &metav1.Time{Time: now}, }, }, }, }, - loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcealphaapi.DeviceTaintRule, i int) { + loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcebetaapi.DeviceTaintRule, i int) { tracker.deviceTaintAdd(ctx)(taintRules[i%len(taintRules)]) }, }, @@ -792,23 +792,23 @@ func BenchmarkEventHandlers(b *testing.B) { } return resourceSlices }(), - taintRules: []*resourcealphaapi.DeviceTaintRule{ + taintRules: []*resourcebetaapi.DeviceTaintRule{ { ObjectMeta: metav1.ObjectMeta{ Name: "taintRule", }, - Spec: resourcealphaapi.DeviceTaintRuleSpec{ + Spec: resourcebetaapi.DeviceTaintRuleSpec{ DeviceSelector: nil, // all slices - Taint: resourcealphaapi.DeviceTaint{ + Taint: resourcebetaapi.DeviceTaint{ Key: "example.com/taint", Value: "tainted", - Effect: resourcealphaapi.DeviceTaintEffectNoExecute, + Effect: resourcebetaapi.DeviceTaintEffectNoExecute, TimeAdded: &metav1.Time{Time: now}, }, }, }, }, - loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, _ []*resourcealphaapi.DeviceTaintRule, i int) { + loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, _ []*resourcebetaapi.DeviceTaintRule, i int) { tracker.resourceSliceAdd(ctx)(resourceSlices[i%len(resourceSlices)]) }, }, @@ -841,25 +841,25 @@ func BenchmarkEventHandlers(b *testing.B) { resourceSlices[nSlices/2].Spec.Devices[nDevices/2].Name = "patchme" return resourceSlices }(), - taintRules: []*resourcealphaapi.DeviceTaintRule{ + taintRules: []*resourcebetaapi.DeviceTaintRule{ { ObjectMeta: metav1.ObjectMeta{ Name: "taintRule", }, - Spec: resourcealphaapi.DeviceTaintRuleSpec{ - DeviceSelector: &resourcealphaapi.DeviceTaintSelector{ + Spec: resourcebetaapi.DeviceTaintRuleSpec{ + DeviceSelector: &resourcebetaapi.DeviceTaintSelector{ Device: ptr.To("patchme"), }, - Taint: resourcealphaapi.DeviceTaint{ + Taint: resourcebetaapi.DeviceTaint{ Key: "example.com/taint", Value: "tainted", - Effect: resourcealphaapi.DeviceTaintEffectNoExecute, + Effect: resourcebetaapi.DeviceTaintEffectNoExecute, TimeAdded: &metav1.Time{Time: now}, }, }, }, }, - loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcealphaapi.DeviceTaintRule, i int) { + loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcebetaapi.DeviceTaintRule, i int) { tracker.deviceTaintAdd(ctx)(taintRules[i%len(taintRules)]) }, }, @@ -886,26 +886,26 @@ func BenchmarkEventHandlers(b *testing.B) { } return resourceSlices }(), - taintRules: []*resourcealphaapi.DeviceTaintRule{ + taintRules: []*resourcebetaapi.DeviceTaintRule{ { ObjectMeta: metav1.ObjectMeta{ Name: "patch", }, - Spec: resourcealphaapi.DeviceTaintRuleSpec{ - DeviceSelector: &resourcealphaapi.DeviceTaintSelector{ + Spec: resourcebetaapi.DeviceTaintRuleSpec{ + DeviceSelector: &resourcebetaapi.DeviceTaintSelector{ Pool: ptr.To("pool-250"), Device: ptr.To("patchme"), }, - Taint: resourcealphaapi.DeviceTaint{ + Taint: resourcebetaapi.DeviceTaint{ Key: "example.com/taint", Value: "tainted", - Effect: resourcealphaapi.DeviceTaintEffectNoExecute, + Effect: resourcebetaapi.DeviceTaintEffectNoExecute, TimeAdded: &metav1.Time{Time: now}, }, }, }, }, - loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, patches []*resourcealphaapi.DeviceTaintRule, i int) { + loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, patches []*resourcebetaapi.DeviceTaintRule, i int) { tracker.resourceSliceAdd(ctx)(resourceSlices[250]) // the slice affected by the patch }, }, @@ -927,21 +927,21 @@ func BenchmarkEventHandlers(b *testing.B) { } return resourceSlices }(), - taintRules: func() []*resourcealphaapi.DeviceTaintRule { - patches := make([]*resourcealphaapi.DeviceTaintRule, 500) + taintRules: func() []*resourcebetaapi.DeviceTaintRule { + patches := make([]*resourcebetaapi.DeviceTaintRule, 500) for i := range patches { - patches[i] = &resourcealphaapi.DeviceTaintRule{ + patches[i] = &resourcebetaapi.DeviceTaintRule{ ObjectMeta: metav1.ObjectMeta{ Name: "taint-rule-" + strconv.Itoa(i), }, - Spec: resourcealphaapi.DeviceTaintRuleSpec{ - DeviceSelector: &resourcealphaapi.DeviceTaintSelector{ + Spec: resourcebetaapi.DeviceTaintRuleSpec{ + DeviceSelector: &resourcebetaapi.DeviceTaintSelector{ Pool: ptr.To("pool-" + strconv.Itoa(i)), }, - Taint: resourcealphaapi.DeviceTaint{ + Taint: resourcebetaapi.DeviceTaint{ Key: "example.com/taint", Value: "tainted", - Effect: resourcealphaapi.DeviceTaintEffectNoExecute, + Effect: resourcebetaapi.DeviceTaintEffectNoExecute, TimeAdded: &metav1.Time{Time: now}, }, }, @@ -949,7 +949,7 @@ func BenchmarkEventHandlers(b *testing.B) { } return patches }(), - loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcealphaapi.DeviceTaintRule, i int) { + loop: func(ctx context.Context, b *testing.B, tracker *Tracker, resourceSlices []*resourceapi.ResourceSlice, taintRules []*resourcebetaapi.DeviceTaintRule, i int) { tracker.deviceTaintAdd(ctx)(taintRules[i%len(taintRules)]) }, }, diff --git a/test/integration/dra/device_taints.go b/test/integration/dra/device_taints.go index 958d029b8a6f7..ef52b044f8f2e 100644 --- a/test/integration/dra/device_taints.go +++ b/test/integration/dra/device_taints.go @@ -37,6 +37,7 @@ import ( "k8s.io/client-go/tools/cache" "k8s.io/kubernetes/pkg/controller/devicetainteviction" "k8s.io/kubernetes/pkg/features" + st "k8s.io/kubernetes/pkg/scheduler/testing" "k8s.io/kubernetes/test/utils/ktesting" "k8s.io/utils/ptr" ) @@ -403,3 +404,94 @@ func testEvictCluster(tCtx ktesting.TContext, useRule useRuleMode) { })))) } } + +func testNoScheduleRule(tCtx ktesting.TContext, useRule useRuleMode) { + tCtx.Parallel() + + startScheduler(tCtx) + + namespace := createTestNamespace(tCtx, nil) + class, driverName := createTestClass(tCtx, namespace) + slice := st.MakeResourceSlice("worker-0", driverName).Devices(device1) + + taintKey := "testing" + ruleName := "rule-" + namespace + switch useRule { + case useV1alpha3Rule: + rule := &resourcealpha.DeviceTaintRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: ruleName, + }, + Spec: resourcealpha.DeviceTaintRuleSpec{ + DeviceSelector: &resourcealpha.DeviceTaintSelector{ + Driver: &driverName, + }, + Taint: resourcealpha.DeviceTaint{ + Key: taintKey, + Effect: resourcealpha.DeviceTaintEffectNoSchedule, + }, + }, + } + _ = must(tCtx, tCtx.Client().ResourceV1alpha3().DeviceTaintRules().Create, rule, metav1.CreateOptions{}) + tCtx.CleanupCtx(func(tCtx ktesting.TContext) { + err := tCtx.Client().ResourceV1alpha3().DeviceTaintRules().Delete(tCtx, ruleName, metav1.DeleteOptions{}) + if apierrors.IsNotFound(err) { + return + } + tCtx.ExpectNoError(err) + }) + case useV1beta2Rule: + rule := &resourcebeta.DeviceTaintRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: ruleName, + }, + Spec: resourcebeta.DeviceTaintRuleSpec{ + DeviceSelector: &resourcebeta.DeviceTaintSelector{ + Driver: &driverName, + }, + Taint: resourcebeta.DeviceTaint{ + Key: taintKey, + Effect: resourcebeta.DeviceTaintEffectNoSchedule, + }, + }, + } + _ = must(tCtx, tCtx.Client().ResourceV1beta2().DeviceTaintRules().Create, rule, metav1.CreateOptions{}) + tCtx.CleanupCtx(func(tCtx ktesting.TContext) { + err := tCtx.Client().ResourceV1beta2().DeviceTaintRules().Delete(tCtx, ruleName, metav1.DeleteOptions{}) + if apierrors.IsNotFound(err) { + return + } + tCtx.ExpectNoError(err) + }) + case useNoRule: + slice.Spec.Devices[0].Taints = []resourceapi.DeviceTaint{ + { + Key: taintKey, + Effect: resourceapi.DeviceTaintEffectNoSchedule, + }, + } + } + + // Creating the ResourceSlice after the DeviceTaintRule exercises additional + // code paths in the ResourceSlice tracker. + _ = createSlice(tCtx, slice.Obj()) + + pod := st.MakePod().Name(podName).Namespace(namespace). + Container("my-container"). + Obj() + + untoleratingClaim := createClaim(tCtx, namespace, "-untolerating", class, claim) + untoleratingPod := createPod(tCtx, namespace, "-untolerating", pod, untoleratingClaim) + expectPodUnschedulable(tCtx, untoleratingPod, "cannot allocate all claims") + + toleratingClaim := claim.DeepCopy() + toleratingClaim.Spec.Devices.Requests[0].Exactly.Tolerations = []resourceapi.DeviceToleration{ + { + Key: taintKey, + Effect: resourceapi.DeviceTaintEffectNoSchedule, + }, + } + _ = createClaim(tCtx, namespace, "-tolerating", class, toleratingClaim) + toleratingPod := createPod(tCtx, namespace, "-tolerating", pod) + waitForPodScheduled(tCtx, namespace, toleratingPod.Name) +} diff --git a/test/integration/dra/dra.go b/test/integration/dra/dra.go index e8c7d76cf7c43..fc3e4fd1c2123 100644 --- a/test/integration/dra/dra.go +++ b/test/integration/dra/dra.go @@ -134,6 +134,7 @@ func run(tCtx ktesting.TContext, whatRE string) { f: func(tCtx ktesting.TContext) { runSubTest(tCtx, "Pod", func(tCtx ktesting.TContext) { testPod(tCtx, true) }) runSubTest(tCtx, "EvictClusterWithSlices", func(tCtx ktesting.TContext) { testEvictCluster(tCtx, useNoRule) }) + runSubTest(tCtx, "NoScheduleWithSlices", func(tCtx ktesting.TContext) { testNoScheduleRule(tCtx, useNoRule) }) // Number of devices per slice is chosen so that Filter takes a few seconds: // without a timeout, the test doesn't run too long, but long enough that a short timeout triggers. runSubTest(tCtx, "FilterTimeout", func(tCtx ktesting.TContext) { testFilterTimeout(tCtx, 21) }) @@ -249,6 +250,9 @@ func run(tCtx ktesting.TContext, whatRE string) { runSubTest(tCtx, "EvictClusterWithV1alpha3Rule", func(tCtx ktesting.TContext) { testEvictCluster(tCtx, useV1alpha3Rule) }) runSubTest(tCtx, "EvictClusterWithV1beta2Rule", func(tCtx ktesting.TContext) { testEvictCluster(tCtx, useV1beta2Rule) }) runSubTest(tCtx, "EvictClusterWithSlices", func(tCtx ktesting.TContext) { testEvictCluster(tCtx, useNoRule) }) + runSubTest(tCtx, "NoScheduleWithV1alpha3Rule", func(tCtx ktesting.TContext) { testNoScheduleRule(tCtx, useV1alpha3Rule) }) + runSubTest(tCtx, "NoScheduleWithV1beta2Rule", func(tCtx ktesting.TContext) { testNoScheduleRule(tCtx, useV1beta2Rule) }) + runSubTest(tCtx, "NoScheduleWithSlices", func(tCtx ktesting.TContext) { testNoScheduleRule(tCtx, useNoRule) }) runSubTest(tCtx, "InvalidResourceSlices", testInvalidResourceSlices) // Number of devices per slice is chosen so that Filter takes a few seconds: The allocator // in the experimental channel has an improvement that requires a higher number here than From 24b3a259f0a1bcd3858d0e0d63c3a80444000706 Mon Sep 17 00:00:00 2001 From: Damiano Donati Date: Wed, 17 Jun 2026 11:31:41 +0200 Subject: [PATCH 08/19] kubeadm: use KubernetesAPICallTimeout for mandatory kubeadm-config fetch During kubeadm join, the mandatory kubeadm-config ConfigMap fetch uses GetConfigMapWithShortRetry, which has a 350ms polling budget. When the API server is slow to respond, the single GET attempt blocks for up to 10 seconds (the client timeout), exhausting the polling budget with no retry. Since this call site has no fallback, the join fails. Add a shortConfigMapGet parameter to getInitConfigurationFromCluster and FetchInitConfigurationFromCluster. When false, the kubeadm-config ConfigMap is fetched using KubernetesAPICallTimeout (default 1 minute, user-configurable) with retries, matching the pattern used by getAPIEndpointFromPodAnnotation. When true, the existing GetConfigMapWithShortRetry is used for callers like kubeadm reset that don't need a long retry. Signed-off-by: Damiano Donati --- cmd/kubeadm/app/cmd/certs.go | 2 +- cmd/kubeadm/app/cmd/join.go | 2 +- cmd/kubeadm/app/cmd/reset.go | 2 +- cmd/kubeadm/app/cmd/upgrade/apply.go | 2 +- cmd/kubeadm/app/cmd/upgrade/common.go | 2 +- cmd/kubeadm/app/cmd/upgrade/diff.go | 4 +-- cmd/kubeadm/app/cmd/upgrade/diff_test.go | 2 +- cmd/kubeadm/app/cmd/upgrade/node.go | 2 +- cmd/kubeadm/app/util/config/cluster.go | 35 ++++++++++++++++++--- cmd/kubeadm/app/util/config/cluster_test.go | 2 +- 10 files changed, 40 insertions(+), 15 deletions(-) diff --git a/cmd/kubeadm/app/cmd/certs.go b/cmd/kubeadm/app/cmd/certs.go index 1e5115a558dcd..0579d021073b2 100644 --- a/cmd/kubeadm/app/cmd/certs.go +++ b/cmd/kubeadm/app/cmd/certs.go @@ -350,7 +350,7 @@ func getInternalCfg(cfgPath string, client kubernetes.Interface, cfg kubeadmapiv getNodeRegistration := true getAPIEndpoint := staticpodutil.IsControlPlaneNode() getComponentConfigs := true - internalcfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, getNodeRegistration, getAPIEndpoint, getComponentConfigs) + internalcfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, getNodeRegistration, getAPIEndpoint, getComponentConfigs, true) if err == nil { printer.Println() // add empty line to separate the FetchInitConfigurationFromCluster output from the command output // certificate renewal or expiration checking doesn't depend on a running cluster, which means the CertificatesDir diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 20920abe6e12d..a64b45a045767 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -715,7 +715,7 @@ func fetchInitConfiguration(client clientset.Interface) (*kubeadmapi.InitConfigu getNodeRegistration := false getAPIEndpoint := false getComponentConfigs := true - initConfiguration, err := configutil.FetchInitConfigurationFromCluster(client, nil, "preflight", getNodeRegistration, getAPIEndpoint, getComponentConfigs) + initConfiguration, err := configutil.FetchInitConfigurationFromCluster(client, nil, "preflight", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false) if err != nil { return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap") } diff --git a/cmd/kubeadm/app/cmd/reset.go b/cmd/kubeadm/app/cmd/reset.go index 66a64e2cdf830..1aeff6fbccca3 100644 --- a/cmd/kubeadm/app/cmd/reset.go +++ b/cmd/kubeadm/app/cmd/reset.go @@ -136,7 +136,7 @@ func newResetData(cmd *cobra.Command, opts *resetOptions, in io.Reader, out io.W getNodeRegistration := true getAPIEndpoint := staticpodutil.IsControlPlaneNode() getComponentConfigs := true - initCfg, err = configutil.FetchInitConfigurationFromCluster(client, nil, "reset", getNodeRegistration, getAPIEndpoint, getComponentConfigs) + initCfg, err = configutil.FetchInitConfigurationFromCluster(client, nil, "reset", getNodeRegistration, getAPIEndpoint, getComponentConfigs, true) if err != nil { klog.Warningf("[reset] Unable to fetch the kubeadm-config ConfigMap from cluster: %v", err) } diff --git a/cmd/kubeadm/app/cmd/upgrade/apply.go b/cmd/kubeadm/app/cmd/upgrade/apply.go index f940639844902..90b6fefd86aa8 100644 --- a/cmd/kubeadm/app/cmd/upgrade/apply.go +++ b/cmd/kubeadm/app/cmd/upgrade/apply.go @@ -241,7 +241,7 @@ func newApplyData(cmd *cobra.Command, args []string, applyFlags *applyFlags) (*a getNodeRegistration := true isControlPlaneNode := true getComponentConfigs := true - initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, isControlPlaneNode, getComponentConfigs) + initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, isControlPlaneNode, getComponentConfigs, false) if err != nil { if apierrors.IsNotFound(err) { _, _ = printer.Printf("[upgrade] In order to upgrade, a ConfigMap called %q in the %q namespace must exist.\n", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem) diff --git a/cmd/kubeadm/app/cmd/upgrade/common.go b/cmd/kubeadm/app/cmd/upgrade/common.go index 0fee21e2ecbd7..d853e4454cf02 100644 --- a/cmd/kubeadm/app/cmd/upgrade/common.go +++ b/cmd/kubeadm/app/cmd/upgrade/common.go @@ -96,7 +96,7 @@ func enforceRequirements(flagSet *pflag.FlagSet, flags *applyPlanFlags, args []s getNodeRegistration := true getAPIEndpoint := staticpodutil.IsControlPlaneNode() getComponentConfigs := true - initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", getNodeRegistration, getAPIEndpoint, getComponentConfigs) + initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false) if err != nil { return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/init config] FATAL") } diff --git a/cmd/kubeadm/app/cmd/upgrade/diff.go b/cmd/kubeadm/app/cmd/upgrade/diff.go index 3d5bf468e9b8c..6fc12b222eb50 100644 --- a/cmd/kubeadm/app/cmd/upgrade/diff.go +++ b/cmd/kubeadm/app/cmd/upgrade/diff.go @@ -107,7 +107,7 @@ func validateManifestsPath(manifests ...string) (err error) { } // FetchInitConfigurationFunc defines the signature of the function which will fetch InitConfiguration from cluster. -type FetchInitConfigurationFunc func(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) +type FetchInitConfigurationFunc func(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error) func runDiff(fs *pflag.FlagSet, flags *diffFlags, args []string, fetchInitConfigurationFromCluster FetchInitConfigurationFunc) error { externalCfg := &v1beta4.UpgradeConfiguration{} @@ -123,7 +123,7 @@ func runDiff(fs *pflag.FlagSet, flags *diffFlags, args []string, fetchInitConfig getNodeRegistration := true getAPIEndpoint := staticpodutil.IsControlPlaneNode() getComponentConfigs := false - initCfg, err := fetchInitConfigurationFromCluster(client, &output.TextPrinter{}, "upgrade/diff", getNodeRegistration, getAPIEndpoint, getComponentConfigs) + initCfg, err := fetchInitConfigurationFromCluster(client, &output.TextPrinter{}, "upgrade/diff", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false) if err != nil { return err } diff --git a/cmd/kubeadm/app/cmd/upgrade/diff_test.go b/cmd/kubeadm/app/cmd/upgrade/diff_test.go index 7e65ee1a18bf2..4cf16c612ce4d 100644 --- a/cmd/kubeadm/app/cmd/upgrade/diff_test.go +++ b/cmd/kubeadm/app/cmd/upgrade/diff_test.go @@ -44,7 +44,7 @@ func createTestRunDiffFile(contents []byte) (string, error) { return file.Name(), nil } -func fakeFetchInitConfig(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { +func fakeFetchInitConfig(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error) { return &kubeadmapi.InitConfiguration{ ClusterConfiguration: kubeadmapi.ClusterConfiguration{ KubernetesVersion: "v1.0.1", diff --git a/cmd/kubeadm/app/cmd/upgrade/node.go b/cmd/kubeadm/app/cmd/upgrade/node.go index 1c8ad80049e11..36b5bc03b23d8 100644 --- a/cmd/kubeadm/app/cmd/upgrade/node.go +++ b/cmd/kubeadm/app/cmd/upgrade/node.go @@ -205,7 +205,7 @@ func newNodeData(cmd *cobra.Command, nodeOptions *nodeOptions, out io.Writer) (* getNodeRegistration := true getAPIEndpoint := isControlPlaneNode getComponentConfigs := true - initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, getAPIEndpoint, getComponentConfigs) + initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false) if err != nil { return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap") } diff --git a/cmd/kubeadm/app/util/config/cluster.go b/cmd/kubeadm/app/util/config/cluster.go index ebdb51c2abb1f..7c02a40d27525 100644 --- a/cmd/kubeadm/app/util/config/cluster.go +++ b/cmd/kubeadm/app/util/config/cluster.go @@ -27,6 +27,7 @@ import ( "time" authv1 "k8s.io/api/authentication/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" @@ -51,8 +52,10 @@ import ( kubeadmruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime" ) -// FetchInitConfigurationFromCluster fetches configuration from a ConfigMap in the cluster -func FetchInitConfigurationFromCluster(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { +// FetchInitConfigurationFromCluster fetches configuration from a ConfigMap in the cluster. +// If shortConfigMapGet is true, a short retry is used when fetching the kubeadm-config ConfigMap, +// which is suitable for callers like "kubeadm reset" that don't need a long retry. +func FetchInitConfigurationFromCluster(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error) { if printer == nil { printer = &output.TextPrinter{} } @@ -61,7 +64,7 @@ func FetchInitConfigurationFromCluster(client clientset.Interface, printer outpu _, _ = printer.Printf("[%s] Use 'kubeadm init phase upload-config kubeadm --config your-config-file' to re-upload it.\n", logPrefix) // Fetch the actual config from cluster - cfg, err := getInitConfigurationFromCluster(constants.KubernetesDir, client, getNodeRegistration, getAPIEndpoint, getComponentConfigs) + cfg, err := getInitConfigurationFromCluster(constants.KubernetesDir, client, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet) if err != nil { return nil, err } @@ -78,9 +81,31 @@ func FetchInitConfigurationFromCluster(client clientset.Interface, printer outpu } // getInitConfigurationFromCluster is separate only for testing purposes, don't call it directly, use FetchInitConfigurationFromCluster instead -func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Interface, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { +func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Interface, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error) { // Also, the config map really should be KubeadmConfigConfigMap... - configMap, err := apiclient.GetConfigMapWithShortRetry(client, metav1.NamespaceSystem, constants.KubeadmConfigConfigMap) + var configMap *v1.ConfigMap + var err error + if shortConfigMapGet { + configMap, err = apiclient.GetConfigMapWithShortRetry(client, metav1.NamespaceSystem, constants.KubeadmConfigConfigMap) + } else { + var lastErr error + err = wait.PollUntilContextTimeout(context.Background(), + constants.KubernetesAPICallRetryInterval, + kubeadmapi.GetActiveTimeouts().KubernetesAPICall.Duration, + true, func(_ context.Context) (bool, error) { + var err error + configMap, err = client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get( + context.Background(), constants.KubeadmConfigConfigMap, metav1.GetOptions{}) + if err == nil { + return true, nil + } + lastErr = err + return false, nil + }) + if err != nil { + err = lastErr + } + } if err != nil { return nil, errors.Wrap(err, "failed to get config map") } diff --git a/cmd/kubeadm/app/util/config/cluster_test.go b/cmd/kubeadm/app/util/config/cluster_test.go index adaf85dbb2616..728e5c877b1c6 100644 --- a/cmd/kubeadm/app/util/config/cluster_test.go +++ b/cmd/kubeadm/app/util/config/cluster_test.go @@ -540,7 +540,7 @@ func TestGetInitConfigurationFromCluster(t *testing.T) { } getComponentConfigs := true - cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.getNodeRegistration, rt.getAPIEndpoint, getComponentConfigs) + cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.getNodeRegistration, rt.getAPIEndpoint, getComponentConfigs, true) if rt.expectedError != (err != nil) { t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err) return From 5acf40ff78581a337f190339241f843c233bd513 Mon Sep 17 00:00:00 2001 From: jihyun-huh Date: Thu, 18 Jun 2026 12:18:47 +0100 Subject: [PATCH 09/19] kubeadm: treat already promoted learner as successful --- cmd/kubeadm/app/util/etcd/etcd.go | 31 +++- cmd/kubeadm/app/util/etcd/etcd_test.go | 209 ++++++++++++++++++++++++- 2 files changed, 235 insertions(+), 5 deletions(-) diff --git a/cmd/kubeadm/app/util/etcd/etcd.go b/cmd/kubeadm/app/util/etcd/etcd.go index e3da49c0c6d65..f2f91ea8e226c 100644 --- a/cmd/kubeadm/app/util/etcd/etcd.go +++ b/cmd/kubeadm/app/util/etcd/etcd.go @@ -626,14 +626,39 @@ func (c *Client) MemberPromote(learnerID uint64) error { // 2. context deadline exceeded // 3. peer URLs already exists // Once the client provides a way to check if the etcd learner is ready to promote, the retry logic can be revisited. - var promoteResp *clientv3.MemberPromoteResponse + var memberList []*etcdserverpb.Member err = wait.PollUntilContextTimeout(context.Background(), constants.EtcdAPICallRetryInterval, kubeadmapi.GetActiveTimeouts().EtcdAPICall.Duration, true, func(_ context.Context) (bool, error) { + // MemberPromote can return a transient client-side error even if the + // promotion already succeeded on the etcd side. Check the current + // member state before attempting another promotion so that retries + // remain idempotent. + resp, statusErr := c.listMembersOnce() + if statusErr != nil { + klog.V(5).Infof("[etcd] Failed to list members before promoting learner %s: %v", learnerIDUint, statusErr) + lastError = statusErr + return false, nil + } + + for _, m := range resp.Members { + if m.ID != learnerID { + continue + } + + if !m.IsLearner { + klog.V(1).Infof("[etcd] Member %s is already a voting member, treating promotion as successful", learnerIDUint) + memberList = resp.Members + return true, nil + } + break + } + ctx, cancel := context.WithTimeout(context.Background(), etcdTimeout) defer cancel() - promoteResp, err = cli.MemberPromote(ctx, learnerID) + promoteResp, err := cli.MemberPromote(ctx, learnerID) if err == nil { klog.V(1).Infof("[etcd] The learner was promoted as a voting member: %s", learnerIDUint) + memberList = promoteResp.Members return true, nil } klog.V(5).Infof("[etcd] Promoting the learner %s failed: %v", learnerIDUint, err) @@ -644,7 +669,7 @@ func (c *Client) MemberPromote(learnerID uint64) error { return lastError } - for _, m := range promoteResp.Members { + for _, m := range memberList { if m.ID == learnerID { parsedPeerAddrs, err := url.Parse(m.PeerURLs[0]) if err != nil { diff --git a/cmd/kubeadm/app/util/etcd/etcd_test.go b/cmd/kubeadm/app/util/etcd/etcd_test.go index cbf1a97463a5f..af4f99e0f0f53 100644 --- a/cmd/kubeadm/app/util/etcd/etcd_test.go +++ b/cmd/kubeadm/app/util/etcd/etcd_test.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "reflect" + "slices" "strconv" "testing" "time" @@ -44,6 +45,9 @@ var errNotImplemented = errors.New("not implemented") type fakeEtcdClient struct { members []*pb.Member endpoints []string + + memberListFunc func(context.Context, ...clientv3.OpOption) (*clientv3.MemberListResponse, error) + memberPromoteFunc func(context.Context, uint64) (*clientv3.MemberPromoteResponse, error) } // Close shuts down the client's etcd connections. @@ -58,7 +62,10 @@ func (f *fakeEtcdClient) Endpoints() []string { } // MemberList lists the current cluster membership. -func (f *fakeEtcdClient) MemberList(_ context.Context, _ ...clientv3.OpOption) (*clientv3.MemberListResponse, error) { +func (f *fakeEtcdClient) MemberList(ctx context.Context, opts ...clientv3.OpOption) (*clientv3.MemberListResponse, error) { + if f.memberListFunc != nil { + return f.memberListFunc(ctx, opts...) + } return &clientv3.MemberListResponse{ Members: f.members, }, nil @@ -80,7 +87,10 @@ func (f *fakeEtcdClient) MemberRemove(_ context.Context, id uint64) (*clientv3.M } // MemberPromote promotes a member from raft learner (non-voting) to raft voting member. -func (f *fakeEtcdClient) MemberPromote(_ context.Context, id uint64) (*clientv3.MemberPromoteResponse, error) { +func (f *fakeEtcdClient) MemberPromote(ctx context.Context, id uint64) (*clientv3.MemberPromoteResponse, error) { + if f.memberPromoteFunc != nil { + return f.memberPromoteFunc(ctx, id) + } return nil, errNotImplemented } @@ -965,3 +975,198 @@ func TestEvaluateClusterStatus(t *testing.T) { }) } } + +func TestMemberPromote(t *testing.T) { + learnerID := uint64(12345) + + const ( + initialEndpoint = "https://192.168.10.100:2379" + promotedEndpoint = "https://192.168.10.200:2379" + ) + + member := func(isLearner bool) *pb.Member { + return &pb.Member{ + ID: learnerID, + Name: "cp-1", + PeerURLs: []string{"https://192.168.10.200:2380"}, + ClientURLs: []string{promotedEndpoint}, + IsLearner: isLearner, + } + } + + type memberListResult struct { + members []*pb.Member + err error + } + + type memberPromoteResult struct { + resp *clientv3.MemberPromoteResponse + err error + } + + tests := []struct { + name string + memberListResults []memberListResult + memberPromoteResults []memberPromoteResult + wantErr bool + wantEndpoint string + wantPromoteCalls int + minMemberListCalls int + }{ + { + name: "successful promotion adds endpoint", + memberListResults: []memberListResult{ + {members: []*pb.Member{member(true)}}, + {members: []*pb.Member{member(true)}}, + }, + memberPromoteResults: []memberPromoteResult{ + { + resp: &clientv3.MemberPromoteResponse{ + Members: []*pb.Member{member(false)}, + }, + }, + }, + wantEndpoint: promotedEndpoint, + wantPromoteCalls: 1, + minMemberListCalls: 2, + }, + { + name: "already promoted after transient promote failure adds endpoint", + memberListResults: []memberListResult{ + {members: []*pb.Member{member(true)}}, + {members: []*pb.Member{member(true)}}, + {members: []*pb.Member{member(false)}}, + }, + memberPromoteResults: []memberPromoteResult{ + { + err: context.DeadlineExceeded, + }, + }, + wantEndpoint: promotedEndpoint, + wantPromoteCalls: 1, + minMemberListCalls: 3, + }, + { + name: "already promoted before promote attempt adds endpoint", + memberListResults: []memberListResult{ + {members: []*pb.Member{member(true)}}, + {members: []*pb.Member{member(false)}}, + }, + wantEndpoint: promotedEndpoint, + wantPromoteCalls: 0, + minMemberListCalls: 2, + }, + { + name: "member list error before promote is retried", + memberListResults: []memberListResult{ + {members: []*pb.Member{member(true)}}, + {err: errNotImplemented}, + {members: []*pb.Member{member(true)}}, + }, + memberPromoteResults: []memberPromoteResult{ + { + resp: &clientv3.MemberPromoteResponse{ + Members: []*pb.Member{member(false)}, + }, + }, + }, + wantEndpoint: promotedEndpoint, + wantPromoteCalls: 1, + minMemberListCalls: 3, + }, + { + name: "promotion keeps failing", + memberListResults: []memberListResult{ + {members: []*pb.Member{member(true)}}, + {members: []*pb.Member{member(true)}}, + }, + memberPromoteResults: []memberPromoteResult{ + { + err: context.DeadlineExceeded, + }, + }, + wantErr: true, + wantPromoteCalls: -1, + minMemberListCalls: 1, + }, + } + + oldActiveTimeout := kubeadmapi.GetActiveTimeouts() + newActiveTimeout := oldActiveTimeout.DeepCopy() + newActiveTimeout.EtcdAPICall = &metav1.Duration{ + Duration: 3 * constants.EtcdAPICallRetryInterval, + } + kubeadmapi.SetActiveTimeouts(newActiveTimeout) + defer kubeadmapi.SetActiveTimeouts(oldActiveTimeout) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + memberListCalls := 0 + memberPromoteCalls := 0 + + fakeClient := &fakeEtcdClient{} + + fakeClient.memberListFunc = func(_ context.Context, _ ...clientv3.OpOption) (*clientv3.MemberListResponse, error) { + if len(tt.memberListResults) == 0 { + t.Fatal("MemberList called without configured results") + } + + resultIndex := memberListCalls + if resultIndex >= len(tt.memberListResults) { + resultIndex = len(tt.memberListResults) - 1 + } + result := tt.memberListResults[resultIndex] + memberListCalls++ + + if result.err != nil { + return nil, result.err + } + return &clientv3.MemberListResponse{ + Members: result.members, + }, nil + } + + fakeClient.memberPromoteFunc = func(_ context.Context, _ uint64) (*clientv3.MemberPromoteResponse, error) { + if len(tt.memberPromoteResults) == 0 { + t.Fatalf("unexpected MemberPromote call") + } + + resultIndex := memberPromoteCalls + if resultIndex >= len(tt.memberPromoteResults) { + resultIndex = len(tt.memberPromoteResults) - 1 + } + result := tt.memberPromoteResults[resultIndex] + memberPromoteCalls++ + + return result.resp, result.err + } + + c := &Client{ + Endpoints: []string{initialEndpoint}, + } + c.newEtcdClient = func(_ []string) (etcdClient, error) { + return fakeClient, nil + } + c.listMembersFunc = func(_ time.Duration) (*clientv3.MemberListResponse, error) { + return fakeClient.MemberList(context.Background()) + } + + err := c.MemberPromote(learnerID) + if (err != nil) != tt.wantErr { + t.Fatalf("MemberPromote() error = %v, wantErr %v", err, tt.wantErr) + } + + if tt.wantPromoteCalls >= 0 && memberPromoteCalls != tt.wantPromoteCalls { + t.Fatalf("MemberPromote calls = %d, want %d", memberPromoteCalls, tt.wantPromoteCalls) + } + + if memberListCalls < tt.minMemberListCalls { + t.Fatalf("MemberList calls = %d, want at least %d", memberListCalls, tt.minMemberListCalls) + } + + if tt.wantEndpoint != "" && !slices.Contains(c.Endpoints, tt.wantEndpoint) { + t.Fatalf("expected endpoint %q to be added, got %v", tt.wantEndpoint, c.Endpoints) + } + }) + } +} From b86d94a7cce8113b1e406efacfd3ae70dc7ebf88 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Tue, 23 Jun 2026 13:37:53 -0400 Subject: [PATCH 10/19] Restore string JSON encoding of cri-api KeyValue --- .../cri-api/pkg/apis/runtime/v1/api_json.go | 47 +++++++ .../pkg/apis/runtime/v1/api_json_test.go | 115 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json.go create mode 100644 staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json.go b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json.go new file mode 100644 index 0000000000000..2e0b6dc2fd861 --- /dev/null +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json.go @@ -0,0 +1,47 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import "encoding/json" + +// MarshalJSON() preserves pre-1.34 JSON encoding of value as a string (not base64), +// stomping non-utf-8 data with the utf8 replacement character. +func (k *KeyValue) MarshalJSON() ([]byte, error) { + return json.Marshal(stringKeyValue{ + Key: k.GetKey(), + Value: string(k.GetValue()), + }) +} + +// UnmarshalJSON preserves pre-1.34 JSON decoding of value as a string (not base64), +// stomping non-utf-8 data with the utf8 replacement character. +func (k *KeyValue) UnmarshalJSON(data []byte) error { + v := stringKeyValue{} + if err := json.Unmarshal(data, &v); err != nil { + return err + } + k.Key = v.Key + k.Value = []byte(v.Value) + return nil +} + +// stringKeyValue matches the structure used to json-encode pre-1.34. +// Non-UTF-8 characters in Value are coerced to the replacement character on encode/decode. +type stringKeyValue struct { + Key string `json:"key,omitempty"` + Value string `json:"value,omitempty"` +} diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go new file mode 100644 index 0000000000000..bfa4494afe7be --- /dev/null +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go @@ -0,0 +1,115 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "bytes" + "encoding/json" + "testing" +) + +func TestKeyValueCompat(t *testing.T) { + testcases := []struct { + name string + envs []*KeyValue + variantJSON string + expectedJSON string + expectedRoundTripped []*KeyValue + }{ + { + name: "null", + envs: nil, + expectedJSON: `null`, + expectedRoundTripped: nil, + }, + { + name: "zero-length list", + envs: []*KeyValue{}, + expectedJSON: `[]`, + expectedRoundTripped: []*KeyValue{}, + }, + { + name: "zero-value env", + envs: []*KeyValue{{}}, + expectedJSON: `[{}]`, + expectedRoundTripped: []*KeyValue{{}}, + }, + { + name: "ascii env", + envs: []*KeyValue{{Key: "key", Value: []byte("value")}}, + expectedJSON: `[{"key":"key","value":"value"}]`, + expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("value")}}, + }, + { + name: "utf8 env", + envs: []*KeyValue{{Key: "key", Value: []byte("Iñtërnâtiônàlizætiøn🐹")}}, + expectedJSON: `[{"key":"key","value":"Iñtërnâtiônàlizætiøn🐹"}]`, + expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("Iñtërnâtiônàlizætiøn🐹")}}, + }, + { + name: "non-utf8 env", + envs: []*KeyValue{{Key: "key", Value: []byte{'A', 0x80, 'Z'}}}, // invalid utf8 continuation byte (0x80) + variantJSON: `[{"key":"key","value":"A` + "\x80" + `Z"}]`, // an alternate JSON input containing the invalid utf8 byte that should coerce to the same result + expectedJSON: `[{"key":"key","value":"A\ufffdZ"}]`, // coerced to utf8 replacement character (\ufffd) on marshal + expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("A\ufffdZ")}}, // round-trips to replacement character (\ufffd) on unmarshal + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + data, err := json.Marshal(tc.envs) + if err != nil { + t.Fatal(err) + } + + if string(data) != tc.expectedJSON { + t.Fatalf("json differed:\nwant: %s\ngot: %s", tc.expectedJSON, string(data)) + } + + verifyJSON(t, data, tc.expectedRoundTripped) + if len(tc.variantJSON) > 0 { + verifyJSON(t, []byte(tc.variantJSON), tc.expectedRoundTripped) + } + }) + } +} + +func verifyJSON(t *testing.T, data []byte, expectedRoundTripped []*KeyValue) { + t.Helper() + + var rt []*KeyValue + if err := json.Unmarshal(data, &rt); err != nil { + t.Fatal(err) + } + if (rt == nil) != (expectedRoundTripped == nil) { + t.Fatalf("expected value (%#v) does not match actual round-tripped value (%#v) for nil", expectedRoundTripped, rt) + } + if rt == nil { + return + } + if len(rt) != len(expectedRoundTripped) { + t.Fatalf("length of expected value (%#v) does not match length of actual round-tripped value (%#v)", expectedRoundTripped, rt) + } + for i := range expectedRoundTripped { + if want, got := expectedRoundTripped[i].Key, rt[i].Key; want != got { + t.Fatalf("item[%d].key does not match: %s vs %s", i, want, got) + } + if want, got := expectedRoundTripped[i].Value, rt[i].Value; !bytes.Equal(want, got) { + t.Fatalf("item[%d].value does not match: %v vs %v", i, want, got) + } + } +} From ab57dc0069ce73efe994f9fd163365de62bedd19 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Wed, 24 Jun 2026 11:59:02 -0400 Subject: [PATCH 11/19] Make utf8 replacement char test pass on Go 1.27 --- .../pkg/apis/runtime/v1/api_json_126_test.go | 22 +++++++++++++++++++ .../pkg/apis/runtime/v1/api_json_127_test.go | 22 +++++++++++++++++++ .../pkg/apis/runtime/v1/api_json_test.go | 8 +++---- 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_126_test.go create mode 100644 staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_127_test.go diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_126_test.go b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_126_test.go new file mode 100644 index 0000000000000..a0a7d908d6de2 --- /dev/null +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_126_test.go @@ -0,0 +1,22 @@ +//go:build !go1.27 + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +// 1.26 marshals a \u-escaped replacement char +const stdlibSerializedReplacementChar = "\\ufffd" diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_127_test.go b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_127_test.go new file mode 100644 index 0000000000000..e9cf35cc977f7 --- /dev/null +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_127_test.go @@ -0,0 +1,22 @@ +//go:build go1.27 + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +// 1.27 marshals the replacement char without escaping +const stdlibSerializedReplacementChar = "\ufffd" diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go index bfa4494afe7be..182f9d72f2486 100644 --- a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go @@ -62,10 +62,10 @@ func TestKeyValueCompat(t *testing.T) { }, { name: "non-utf8 env", - envs: []*KeyValue{{Key: "key", Value: []byte{'A', 0x80, 'Z'}}}, // invalid utf8 continuation byte (0x80) - variantJSON: `[{"key":"key","value":"A` + "\x80" + `Z"}]`, // an alternate JSON input containing the invalid utf8 byte that should coerce to the same result - expectedJSON: `[{"key":"key","value":"A\ufffdZ"}]`, // coerced to utf8 replacement character (\ufffd) on marshal - expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("A\ufffdZ")}}, // round-trips to replacement character (\ufffd) on unmarshal + envs: []*KeyValue{{Key: "key", Value: []byte{'A', 0x80, 'Z'}}}, // invalid utf8 continuation byte (0x80) + variantJSON: `[{"key":"key","value":"A` + "\x80" + `Z"}]`, // an alternate JSON input containing the invalid utf8 byte that should coerce to the same result + expectedJSON: `[{"key":"key","value":"A` + stdlibSerializedReplacementChar + `Z"}]`, // coerced to utf8 replacement character (\ufffd) on marshal + expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("A\ufffdZ")}}, // round-trips to replacement character (\ufffd) on unmarshal }, } From ccca5a96bfb9d65a9826c42058eec3b946ef835c Mon Sep 17 00:00:00 2001 From: Mike Robbins Date: Thu, 18 Jun 2026 15:06:36 -0400 Subject: [PATCH 12/19] kubelet startPodSync: reuse the previous context to fix memory leak regression --- pkg/kubelet/pod_workers.go | 16 +++++++++++++++- pkg/kubelet/pod_workers_test.go | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/kubelet/pod_workers.go b/pkg/kubelet/pod_workers.go index 0f3034e26225e..a71f1fbcbd284 100644 --- a/pkg/kubelet/pod_workers.go +++ b/pkg/kubelet/pod_workers.go @@ -336,6 +336,16 @@ const ( // podSyncStatus tracks per-pod transitions through the three phases of pod // worker sync (setup, terminating, terminated). type podSyncStatus struct { + // ctx is reused across normal pod syncs. + // A new ctx is created on the next startPodSync after explicit cancellation. + // + // TODO: remove this from the struct by having the context initialized + // in startPodSync, the cancelFn used by UpdatePod, and cancellation of + // a parent context for tearing down workers (if needed) on shutdown. + // Be careful not to leak contexts (see #139823). + // Be careful that long-lived goroutines (such as prober workers) outlive + // the lifetime of a single startPodSync cancellation context. + ctx context.Context // cancelFn if set is expected to cancel the current podSyncer operation. cancelFn context.CancelFunc @@ -1152,7 +1162,11 @@ func (p *podWorkers) startPodSync(parentCtx context.Context, podUID types.UID) ( default: } - ctx, status.cancelFn = context.WithCancel(parentCtx) + if status.ctx == nil || status.ctx.Err() != nil { + // create a context with parentCtx's values, and reuse it until it is canceled + status.ctx, status.cancelFn = context.WithCancel(context.WithoutCancel(parentCtx)) + } + ctx = status.ctx // if we are already started, make our state visible to downstream components if status.IsStarted() { diff --git a/pkg/kubelet/pod_workers_test.go b/pkg/kubelet/pod_workers_test.go index ac446fe133f08..7fad7fb43a7b7 100644 --- a/pkg/kubelet/pod_workers_test.go +++ b/pkg/kubelet/pod_workers_test.go @@ -602,6 +602,7 @@ func TestUpdatePod(t *testing.T) { } else { expected.cancelFn, status.cancelFn = nil, nil } + expected.ctx, status.ctx = nil, nil } if e, a := expected, status; !reflect.DeepEqual(e, a) { t.Fatalf("unexpected status: %s", cmp.Diff(e, a, cmp.AllowUnexported(podSyncStatus{}))) From f01529250b2477e4ff34c5bbd020c379b49669e6 Mon Sep 17 00:00:00 2001 From: Joe Betz Date: Tue, 7 Jul 2026 19:00:46 -0400 Subject: [PATCH 13/19] Bump sigs.k8s.io/structured-merge-diff/v6 to v6.3.3 --- go.mod | 2 +- go.sum | 4 +-- staging/src/k8s.io/api/go.mod | 2 +- staging/src/k8s.io/api/go.sum | 4 +-- .../src/k8s.io/apiextensions-apiserver/go.mod | 2 +- .../src/k8s.io/apiextensions-apiserver/go.sum | 4 +-- staging/src/k8s.io/apimachinery/go.mod | 2 +- staging/src/k8s.io/apimachinery/go.sum | 4 +-- staging/src/k8s.io/apiserver/go.mod | 2 +- staging/src/k8s.io/apiserver/go.sum | 4 +-- staging/src/k8s.io/cli-runtime/go.mod | 2 +- staging/src/k8s.io/cli-runtime/go.sum | 4 +-- staging/src/k8s.io/client-go/go.mod | 2 +- staging/src/k8s.io/client-go/go.sum | 4 +-- staging/src/k8s.io/cloud-provider/go.mod | 2 +- staging/src/k8s.io/cloud-provider/go.sum | 4 +-- staging/src/k8s.io/cluster-bootstrap/go.mod | 2 +- staging/src/k8s.io/cluster-bootstrap/go.sum | 4 +-- .../src/k8s.io/code-generator/examples/go.mod | 2 +- .../src/k8s.io/code-generator/examples/go.sum | 4 +-- staging/src/k8s.io/code-generator/go.mod | 2 +- staging/src/k8s.io/code-generator/go.sum | 4 +-- staging/src/k8s.io/component-base/go.mod | 2 +- staging/src/k8s.io/component-base/go.sum | 4 +-- staging/src/k8s.io/component-helpers/go.mod | 2 +- staging/src/k8s.io/component-helpers/go.sum | 4 +-- staging/src/k8s.io/controller-manager/go.mod | 2 +- staging/src/k8s.io/controller-manager/go.sum | 4 +-- staging/src/k8s.io/cri-client/go.sum | 2 +- staging/src/k8s.io/csi-translation-lib/go.mod | 2 +- staging/src/k8s.io/csi-translation-lib/go.sum | 4 +-- .../k8s.io/dynamic-resource-allocation/go.mod | 2 +- .../k8s.io/dynamic-resource-allocation/go.sum | 4 +-- staging/src/k8s.io/endpointslice/go.mod | 2 +- staging/src/k8s.io/endpointslice/go.sum | 4 +-- staging/src/k8s.io/kube-aggregator/go.mod | 2 +- staging/src/k8s.io/kube-aggregator/go.sum | 4 +-- .../src/k8s.io/kube-controller-manager/go.mod | 2 +- .../src/k8s.io/kube-controller-manager/go.sum | 4 +-- staging/src/k8s.io/kube-proxy/go.mod | 2 +- staging/src/k8s.io/kube-proxy/go.sum | 4 +-- staging/src/k8s.io/kube-scheduler/go.mod | 2 +- staging/src/k8s.io/kube-scheduler/go.sum | 4 +-- staging/src/k8s.io/kubectl/go.mod | 2 +- staging/src/k8s.io/kubectl/go.sum | 4 +-- staging/src/k8s.io/kubelet/go.mod | 2 +- staging/src/k8s.io/kubelet/go.sum | 4 +-- staging/src/k8s.io/metrics/go.mod | 2 +- staging/src/k8s.io/metrics/go.sum | 4 +-- .../src/k8s.io/pod-security-admission/go.mod | 2 +- .../src/k8s.io/pod-security-admission/go.sum | 4 +-- staging/src/k8s.io/sample-apiserver/go.mod | 2 +- staging/src/k8s.io/sample-apiserver/go.sum | 4 +-- staging/src/k8s.io/sample-cli-plugin/go.mod | 2 +- staging/src/k8s.io/sample-cli-plugin/go.sum | 4 +-- staging/src/k8s.io/sample-controller/go.mod | 2 +- staging/src/k8s.io/sample-controller/go.sum | 4 +-- vendor/modules.txt | 2 +- .../structured-merge-diff/v6/typed/remove.go | 33 ++----------------- 59 files changed, 88 insertions(+), 117 deletions(-) diff --git a/go.mod b/go.mod index 81bdb045845bd..b3b2590a98e16 100644 --- a/go.mod +++ b/go.mod @@ -119,7 +119,7 @@ require ( sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 sigs.k8s.io/knftables v0.0.21 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 sigs.k8s.io/yaml v1.6.0 ) diff --git a/go.sum b/go.sum index c400792e82c13..11f10d79e5485 100644 --- a/go.sum +++ b/go.sum @@ -516,7 +516,7 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7 sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/api/go.mod b/staging/src/k8s.io/api/go.mod index b017d007fe3f0..59ab3d8150c50 100644 --- a/staging/src/k8s.io/api/go.mod +++ b/staging/src/k8s.io/api/go.mod @@ -31,7 +31,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/api/go.sum b/staging/src/k8s.io/api/go.sum index eab20f29d9034..82168f9210261 100644 --- a/staging/src/k8s.io/api/go.sum +++ b/staging/src/k8s.io/api/go.sum @@ -89,7 +89,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.mod b/staging/src/k8s.io/apiextensions-apiserver/go.mod index ee43f5d07bbae..3b652d15e8e92 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.mod +++ b/staging/src/k8s.io/apiextensions-apiserver/go.mod @@ -37,7 +37,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 sigs.k8s.io/yaml v1.6.0 ) diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.sum b/staging/src/k8s.io/apiextensions-apiserver/go.sum index b4a76793c43e6..d0c809655e4a1 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.sum +++ b/staging/src/k8s.io/apiextensions-apiserver/go.sum @@ -337,7 +337,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/apimachinery/go.mod b/staging/src/k8s.io/apimachinery/go.mod index fd8861090f41d..60603a0f62637 100644 --- a/staging/src/k8s.io/apimachinery/go.mod +++ b/staging/src/k8s.io/apimachinery/go.mod @@ -25,7 +25,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 sigs.k8s.io/yaml v1.6.0 ) diff --git a/staging/src/k8s.io/apimachinery/go.sum b/staging/src/k8s.io/apimachinery/go.sum index 53a98cb1526c5..17aaacf4361ab 100644 --- a/staging/src/k8s.io/apimachinery/go.sum +++ b/staging/src/k8s.io/apimachinery/go.sum @@ -111,7 +111,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/apiserver/go.mod b/staging/src/k8s.io/apiserver/go.mod index 211cf0cf1c921..8acb57d5bb8d5 100644 --- a/staging/src/k8s.io/apiserver/go.mod +++ b/staging/src/k8s.io/apiserver/go.mod @@ -60,7 +60,7 @@ require ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 sigs.k8s.io/yaml v1.6.0 ) diff --git a/staging/src/k8s.io/apiserver/go.sum b/staging/src/k8s.io/apiserver/go.sum index 1111bfbb036fb..3a7b95b6a62bc 100644 --- a/staging/src/k8s.io/apiserver/go.sum +++ b/staging/src/k8s.io/apiserver/go.sum @@ -334,7 +334,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/cli-runtime/go.mod b/staging/src/k8s.io/cli-runtime/go.mod index 7d11b8c9b52f3..41cae45fc0649 100644 --- a/staging/src/k8s.io/cli-runtime/go.mod +++ b/staging/src/k8s.io/cli-runtime/go.mod @@ -65,7 +65,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) replace ( diff --git a/staging/src/k8s.io/cli-runtime/go.sum b/staging/src/k8s.io/cli-runtime/go.sum index 90ae35f8613ae..3bd772d392060 100644 --- a/staging/src/k8s.io/cli-runtime/go.sum +++ b/staging/src/k8s.io/cli-runtime/go.sum @@ -153,7 +153,7 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7 sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/client-go/go.mod b/staging/src/k8s.io/client-go/go.mod index 6d4a9dade8f34..18ebab77f8b7e 100644 --- a/staging/src/k8s.io/client-go/go.mod +++ b/staging/src/k8s.io/client-go/go.mod @@ -31,7 +31,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 sigs.k8s.io/yaml v1.6.0 ) diff --git a/staging/src/k8s.io/client-go/go.sum b/staging/src/k8s.io/client-go/go.sum index e9d51b87c1479..2c3fe1c536977 100644 --- a/staging/src/k8s.io/client-go/go.sum +++ b/staging/src/k8s.io/client-go/go.sum @@ -126,7 +126,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/cloud-provider/go.mod b/staging/src/k8s.io/cloud-provider/go.mod index ae432e193ced3..3f85972a4fc4d 100644 --- a/staging/src/k8s.io/cloud-provider/go.mod +++ b/staging/src/k8s.io/cloud-provider/go.mod @@ -108,7 +108,7 @@ require ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/cloud-provider/go.sum b/staging/src/k8s.io/cloud-provider/go.sum index f9d5f0ea0c105..3c989deb30f65 100644 --- a/staging/src/k8s.io/cloud-provider/go.sum +++ b/staging/src/k8s.io/cloud-provider/go.sum @@ -312,7 +312,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/cluster-bootstrap/go.mod b/staging/src/k8s.io/cluster-bootstrap/go.mod index 39b339d5ae3b1..b5412f9295135 100644 --- a/staging/src/k8s.io/cluster-bootstrap/go.mod +++ b/staging/src/k8s.io/cluster-bootstrap/go.mod @@ -34,7 +34,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) replace ( diff --git a/staging/src/k8s.io/cluster-bootstrap/go.sum b/staging/src/k8s.io/cluster-bootstrap/go.sum index 206bc45fa2e39..bf7af27701fd1 100644 --- a/staging/src/k8s.io/cluster-bootstrap/go.sum +++ b/staging/src/k8s.io/cluster-bootstrap/go.sum @@ -87,7 +87,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/code-generator/examples/go.mod b/staging/src/k8s.io/code-generator/examples/go.mod index 10f56e54c9bc4..b8051ed206776 100644 --- a/staging/src/k8s.io/code-generator/examples/go.mod +++ b/staging/src/k8s.io/code-generator/examples/go.mod @@ -11,7 +11,7 @@ require ( k8s.io/apimachinery v0.0.0 k8s.io/client-go v0.0.0 k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 ) require ( diff --git a/staging/src/k8s.io/code-generator/examples/go.sum b/staging/src/k8s.io/code-generator/examples/go.sum index fe1f2b12e9710..f413c034a5c64 100644 --- a/staging/src/k8s.io/code-generator/examples/go.sum +++ b/staging/src/k8s.io/code-generator/examples/go.sum @@ -105,7 +105,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/code-generator/go.mod b/staging/src/k8s.io/code-generator/go.mod index 0c5f77f345161..61f38b2c93c1c 100644 --- a/staging/src/k8s.io/code-generator/go.mod +++ b/staging/src/k8s.io/code-generator/go.mod @@ -45,7 +45,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) replace ( diff --git a/staging/src/k8s.io/code-generator/go.sum b/staging/src/k8s.io/code-generator/go.sum index f7fcc5e2cd37c..c2db6b1dfd686 100644 --- a/staging/src/k8s.io/code-generator/go.sum +++ b/staging/src/k8s.io/code-generator/go.sum @@ -143,7 +143,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/component-base/go.mod b/staging/src/k8s.io/component-base/go.mod index 2428fba6378fd..a46c4b9482dd6 100644 --- a/staging/src/k8s.io/component-base/go.mod +++ b/staging/src/k8s.io/component-base/go.mod @@ -81,7 +81,7 @@ require ( k8s.io/api v0.0.0 // indirect k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/component-base/go.sum b/staging/src/k8s.io/component-base/go.sum index fecb7afe747a4..9cf6ba2b1e8d4 100644 --- a/staging/src/k8s.io/component-base/go.sum +++ b/staging/src/k8s.io/component-base/go.sum @@ -216,7 +216,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/component-helpers/go.mod b/staging/src/k8s.io/component-helpers/go.mod index 294fc481667c9..f26b1e196085a 100644 --- a/staging/src/k8s.io/component-helpers/go.mod +++ b/staging/src/k8s.io/component-helpers/go.mod @@ -47,7 +47,7 @@ require ( k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/component-helpers/go.sum b/staging/src/k8s.io/component-helpers/go.sum index 5b4a37fdce1c9..06bbb43a7485f 100644 --- a/staging/src/k8s.io/component-helpers/go.sum +++ b/staging/src/k8s.io/component-helpers/go.sum @@ -120,7 +120,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/controller-manager/go.mod b/staging/src/k8s.io/controller-manager/go.mod index 6d1d17649b2dd..d70a477d989b4 100644 --- a/staging/src/k8s.io/controller-manager/go.mod +++ b/staging/src/k8s.io/controller-manager/go.mod @@ -100,7 +100,7 @@ require ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/controller-manager/go.sum b/staging/src/k8s.io/controller-manager/go.sum index 495c8dfaefb6a..2c9bb120cdf72 100644 --- a/staging/src/k8s.io/controller-manager/go.sum +++ b/staging/src/k8s.io/controller-manager/go.sum @@ -307,7 +307,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/cri-client/go.sum b/staging/src/k8s.io/cri-client/go.sum index 1d930637cc8e9..5bdf496668dc6 100644 --- a/staging/src/k8s.io/cri-client/go.sum +++ b/staging/src/k8s.io/cri-client/go.sum @@ -131,5 +131,5 @@ k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0x k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/csi-translation-lib/go.mod b/staging/src/k8s.io/csi-translation-lib/go.mod index e209dd2629c74..1647152eca9ac 100644 --- a/staging/src/k8s.io/csi-translation-lib/go.mod +++ b/staging/src/k8s.io/csi-translation-lib/go.mod @@ -33,7 +33,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) replace ( diff --git a/staging/src/k8s.io/csi-translation-lib/go.sum b/staging/src/k8s.io/csi-translation-lib/go.sum index b35886fdfd67a..baabc5dc57863 100644 --- a/staging/src/k8s.io/csi-translation-lib/go.sum +++ b/staging/src/k8s.io/csi-translation-lib/go.sum @@ -85,7 +85,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/dynamic-resource-allocation/go.mod b/staging/src/k8s.io/dynamic-resource-allocation/go.mod index 86bc9cea30ebe..b8ba01b04ee44 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/go.mod +++ b/staging/src/k8s.io/dynamic-resource-allocation/go.mod @@ -79,7 +79,7 @@ require ( k8s.io/component-base v0.0.0 // indirect k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/dynamic-resource-allocation/go.sum b/staging/src/k8s.io/dynamic-resource-allocation/go.sum index d080394e250e3..850b155411c4f 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/go.sum +++ b/staging/src/k8s.io/dynamic-resource-allocation/go.sum @@ -259,7 +259,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/endpointslice/go.mod b/staging/src/k8s.io/endpointslice/go.mod index 16ed6596dcf9f..ddf169006643f 100644 --- a/staging/src/k8s.io/endpointslice/go.mod +++ b/staging/src/k8s.io/endpointslice/go.mod @@ -61,7 +61,7 @@ require ( k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/endpointslice/go.sum b/staging/src/k8s.io/endpointslice/go.sum index 20d133549ffed..4cd297e07b854 100644 --- a/staging/src/k8s.io/endpointslice/go.sum +++ b/staging/src/k8s.io/endpointslice/go.sum @@ -170,7 +170,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/kube-aggregator/go.mod b/staging/src/k8s.io/kube-aggregator/go.mod index b3e337de327fa..3e65039897bf1 100644 --- a/staging/src/k8s.io/kube-aggregator/go.mod +++ b/staging/src/k8s.io/kube-aggregator/go.mod @@ -27,7 +27,7 @@ require ( k8s.io/streaming v0.0.0 k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 ) require ( diff --git a/staging/src/k8s.io/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index ee73b182dd2bd..1db4a207fb056 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -317,7 +317,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/kube-controller-manager/go.mod b/staging/src/k8s.io/kube-controller-manager/go.mod index 2b599a0fce2b0..cfb432ea59b7d 100644 --- a/staging/src/k8s.io/kube-controller-manager/go.mod +++ b/staging/src/k8s.io/kube-controller-manager/go.mod @@ -31,7 +31,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) replace ( diff --git a/staging/src/k8s.io/kube-controller-manager/go.sum b/staging/src/k8s.io/kube-controller-manager/go.sum index aa0b7a5d54462..5a5062bc30a3b 100644 --- a/staging/src/k8s.io/kube-controller-manager/go.sum +++ b/staging/src/k8s.io/kube-controller-manager/go.sum @@ -138,7 +138,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/kube-proxy/go.mod b/staging/src/k8s.io/kube-proxy/go.mod index 76752ed007801..1bd1a15ca3581 100644 --- a/staging/src/k8s.io/kube-proxy/go.mod +++ b/staging/src/k8s.io/kube-proxy/go.mod @@ -45,7 +45,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/kube-proxy/go.sum b/staging/src/k8s.io/kube-proxy/go.sum index 34132e65c800d..534ee732e58a3 100644 --- a/staging/src/k8s.io/kube-proxy/go.sum +++ b/staging/src/k8s.io/kube-proxy/go.sum @@ -144,7 +144,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/kube-scheduler/go.mod b/staging/src/k8s.io/kube-scheduler/go.mod index 5b057330b143c..8df0ac85bd617 100644 --- a/staging/src/k8s.io/kube-scheduler/go.mod +++ b/staging/src/k8s.io/kube-scheduler/go.mod @@ -73,7 +73,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) replace ( diff --git a/staging/src/k8s.io/kube-scheduler/go.sum b/staging/src/k8s.io/kube-scheduler/go.sum index 7b555f9dd7a76..d1f2be5663f51 100644 --- a/staging/src/k8s.io/kube-scheduler/go.sum +++ b/staging/src/k8s.io/kube-scheduler/go.sum @@ -215,7 +215,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/kubectl/go.mod b/staging/src/k8s.io/kubectl/go.mod index afdf5c9f21df5..9149063a41ed7 100644 --- a/staging/src/k8s.io/kubectl/go.mod +++ b/staging/src/k8s.io/kubectl/go.mod @@ -45,7 +45,7 @@ require ( sigs.k8s.io/kustomize/kustomize/v5 v5.8.1 sigs.k8s.io/kustomize/kyaml v0.21.1 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 sigs.k8s.io/yaml v1.6.0 ) diff --git a/staging/src/k8s.io/kubectl/go.sum b/staging/src/k8s.io/kubectl/go.sum index 290b44a56457e..9f52f2ecf06fb 100644 --- a/staging/src/k8s.io/kubectl/go.sum +++ b/staging/src/k8s.io/kubectl/go.sum @@ -245,7 +245,7 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7 sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/kubelet/go.mod b/staging/src/k8s.io/kubelet/go.mod index 55c2983f4c767..a8a4e7d9d69db 100644 --- a/staging/src/k8s.io/kubelet/go.mod +++ b/staging/src/k8s.io/kubelet/go.mod @@ -51,7 +51,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/kubelet/go.sum b/staging/src/k8s.io/kubelet/go.sum index ff0f4354053c8..374491559b260 100644 --- a/staging/src/k8s.io/kubelet/go.sum +++ b/staging/src/k8s.io/kubelet/go.sum @@ -170,7 +170,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/metrics/go.mod b/staging/src/k8s.io/metrics/go.mod index c09fd5de36a26..fb4526d805aeb 100644 --- a/staging/src/k8s.io/metrics/go.mod +++ b/staging/src/k8s.io/metrics/go.mod @@ -55,7 +55,7 @@ require ( k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/metrics/go.sum b/staging/src/k8s.io/metrics/go.sum index 1db1155e4e79b..dfc5c02d9fee6 100644 --- a/staging/src/k8s.io/metrics/go.sum +++ b/staging/src/k8s.io/metrics/go.sum @@ -128,7 +128,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/pod-security-admission/go.mod b/staging/src/k8s.io/pod-security-admission/go.mod index ac69f107885b2..13f75ff82bd46 100644 --- a/staging/src/k8s.io/pod-security-admission/go.mod +++ b/staging/src/k8s.io/pod-security-admission/go.mod @@ -105,7 +105,7 @@ require ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) replace ( diff --git a/staging/src/k8s.io/pod-security-admission/go.sum b/staging/src/k8s.io/pod-security-admission/go.sum index 495c8dfaefb6a..2c9bb120cdf72 100644 --- a/staging/src/k8s.io/pod-security-admission/go.sum +++ b/staging/src/k8s.io/pod-security-admission/go.sum @@ -307,7 +307,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/sample-apiserver/go.mod b/staging/src/k8s.io/sample-apiserver/go.mod index 6bcebf40d62b2..ab1c1e62a7106 100644 --- a/staging/src/k8s.io/sample-apiserver/go.mod +++ b/staging/src/k8s.io/sample-apiserver/go.mod @@ -17,7 +17,7 @@ require ( k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 sigs.k8s.io/randfill v1.0.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 ) require ( diff --git a/staging/src/k8s.io/sample-apiserver/go.sum b/staging/src/k8s.io/sample-apiserver/go.sum index b5e48ab60747d..dd8b337c22dd4 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -314,7 +314,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/sample-cli-plugin/go.mod b/staging/src/k8s.io/sample-cli-plugin/go.mod index 7b1ba3c125fb4..31d64e5d661cd 100644 --- a/staging/src/k8s.io/sample-cli-plugin/go.mod +++ b/staging/src/k8s.io/sample-cli-plugin/go.mod @@ -62,7 +62,7 @@ require ( sigs.k8s.io/kustomize/api v0.21.1 // indirect sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/staging/src/k8s.io/sample-cli-plugin/go.sum b/staging/src/k8s.io/sample-cli-plugin/go.sum index 90ae35f8613ae..3bd772d392060 100644 --- a/staging/src/k8s.io/sample-cli-plugin/go.sum +++ b/staging/src/k8s.io/sample-cli-plugin/go.sum @@ -153,7 +153,7 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7 sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/staging/src/k8s.io/sample-controller/go.mod b/staging/src/k8s.io/sample-controller/go.mod index 99ce895f58de8..2bf8943c90026 100644 --- a/staging/src/k8s.io/sample-controller/go.mod +++ b/staging/src/k8s.io/sample-controller/go.mod @@ -15,7 +15,7 @@ require ( k8s.io/klog/v2 v2.140.0 k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 ) require ( diff --git a/staging/src/k8s.io/sample-controller/go.sum b/staging/src/k8s.io/sample-controller/go.sum index 91e2a57af7d79..76ac4f41cc0aa 100644 --- a/staging/src/k8s.io/sample-controller/go.sum +++ b/staging/src/k8s.io/sample-controller/go.sum @@ -129,7 +129,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/vendor/modules.txt b/vendor/modules.txt index 834639f3e287c..a643d8678138f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1305,7 +1305,7 @@ sigs.k8s.io/kustomize/kyaml/yaml/walk ## explicit; go 1.18 sigs.k8s.io/randfill sigs.k8s.io/randfill/bytesource -# sigs.k8s.io/structured-merge-diff/v6 v6.3.2 +# sigs.k8s.io/structured-merge-diff/v6 v6.3.3 ## explicit; go 1.23 sigs.k8s.io/structured-merge-diff/v6/fieldpath sigs.k8s.io/structured-merge-diff/v6/merge diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go b/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go index 0db1734f941bd..78ba6f50d0aca 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go @@ -75,7 +75,6 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) { } var newItems []interface{} - hadMatches := false iter := l.RangeUsing(w.allocator) defer w.allocator.Free(iter) for iter.Next() { @@ -99,26 +98,12 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) { continue } if isPrefixMatch { - // Removing nested items within this list item and preserve if it becomes empty - hadMatches = true - wasMap := item.IsMap() - wasList := item.IsList() item = removeItemsWithSchema(item, w.toRemove.WithPrefix(pe), w.schema, t.ElementType, w.shouldExtract) - // If item returned null but we're removing items within the structure(not the item itself), - // preserve the empty container structure - if item.IsNull() && !w.shouldExtract { - if wasMap { - item = value.NewValueInterface(map[string]interface{}{}) - } else if wasList { - item = value.NewValueInterface([]interface{}{}) - } - } } newItems = append(newItems, item.Unstructured()) } } - // Preserve empty lists (non-nil) instead of converting to null when items were matched and removed - if len(newItems) > 0 || (hadMatches && !w.shouldExtract) { + if len(newItems) > 0 { w.out = newItems } return nil @@ -156,7 +141,6 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { } newMap := map[string]interface{}{} - hadMatches := false m.Iterate(func(k string, val value.Value) bool { pe := fieldpath.PathElement{FieldName: &k} path, _ := fieldpath.MakePath(pe) @@ -174,19 +158,7 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { return true } if subset := w.toRemove.WithPrefix(pe); !subset.Empty() { - hadMatches = true - wasMap := val.IsMap() - wasList := val.IsList() val = removeItemsWithSchema(val, subset, w.schema, fieldType, w.shouldExtract) - // If val returned null but we're removing items within the structure (not the field itself), - // preserve the empty container structure - if val.IsNull() && !w.shouldExtract { - if wasMap { - val = value.NewValueInterface(map[string]interface{}{}) - } else if wasList { - val = value.NewValueInterface([]interface{}{}) - } - } } else { // don't save values not on the path when we shouldExtract. if w.shouldExtract { @@ -196,8 +168,7 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { newMap[k] = val.Unstructured() return true }) - // Preserve empty maps (non-nil) instead of converting to null when items were matched and removed - if len(newMap) > 0 || (hadMatches && !w.shouldExtract) { + if len(newMap) > 0 { w.out = newMap } return nil From 4434901e4e14a423875b6a13b688deeee570f94b Mon Sep 17 00:00:00 2001 From: Joe Betz Date: Wed, 1 Jul 2026 21:26:32 -0400 Subject: [PATCH 14/19] Add e2e test for setting maps and slices to null via SSA --- .../test/integration/apply_test.go | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/staging/src/k8s.io/apiextensions-apiserver/test/integration/apply_test.go b/staging/src/k8s.io/apiextensions-apiserver/test/integration/apply_test.go index a30703ae103a2..6149b7dba87ca 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/test/integration/apply_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/test/integration/apply_test.go @@ -19,12 +19,16 @@ package integration import ( "context" "fmt" + "strings" "testing" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" "k8s.io/apiextensions-apiserver/test/integration/fixtures" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/dynamic" ) @@ -114,3 +118,145 @@ values: } } + +// TestApplyNullToObject ensures that when maps and slices are set to null using +// SSA, that the resulting field state is correct. +func TestApplyNullToObject(t *testing.T) { + tearDown, config, _, err := fixtures.StartDefaultServer(t) + if err != nil { + t.Fatal(err) + } + defer tearDown() + + apiExtensionClient, err := clientset.NewForConfig(config) + if err != nil { + t.Fatal(err) + } + dynamicClient, err := dynamic.NewForConfig(config) + if err != nil { + t.Fatal(err) + } + + testCases := []struct { + name string + nullable bool + required bool + subfieldRequired bool + + wantNull bool + wantErr string + }{ + // This behavior is fussy, so we test a wide range of combinations. + {name: "nullable and optional field with optional subfield", nullable: true, wantNull: true}, + {name: "nullable and required field with optional subfield", nullable: true, required: true, wantNull: true}, + {name: "nullable and optional field with required subfield", nullable: true, subfieldRequired: true, wantNull: true}, + {name: "nullable and required field with required subfield", nullable: true, subfieldRequired: true, required: true, wantNull: true}, + + // Applying null to a non-nullable field is rejected by validation. To clear + // a non-nullable field, it must be omitted from the apply request instead. + {name: "non-nullable and optional field with optional subfield", wantErr: "must be of type object"}, + {name: "non-nullable and required field with optional subfield", required: true, wantErr: "must be of type object"}, + {name: "non-nullable and optional field with required subfield", subfieldRequired: true, wantErr: "must be of type object"}, + {name: "non-nullable and required field with required subfield", subfieldRequired: true, required: true, wantErr: "must be of type object"}, + } + + group, version, kind, plural := "stable.example.com", "v1", "Widget", "widgets" + apiVersion := group + "/" + version + gvr := schema.GroupVersionResource{Group: group, Version: version, Resource: plural} + + // Way more efficient to test if we build a single CRD to handle all the test cases. + fieldName := func(i int) string { return fmt.Sprintf("field%d", i) } + specProps := map[string]apiextensionsv1.JSONSchemaProps{} + for i, tc := range testCases { + wrapper := apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{"inner": mkObjectSchema(tc.nullable, tc.subfieldRequired)}, + } + if tc.required { + wrapper.Required = []string{"inner"} + } + specProps[fieldName(i)] = wrapper + } + + crd := &apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{Name: plural + "." + group}, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: group, + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{ + Name: version, + Served: true, + Storage: true, + Schema: &apiextensionsv1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{"spec": {Type: "object", Properties: specProps}}, + }, + }, + }}, + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Plural: plural, + Kind: kind, + ListKind: kind + "List", + }, + Scope: apiextensionsv1.ClusterScoped, + }, + } + if _, err := fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient); err != nil { + t.Fatal(err) + } + + apply := func(object, field string, inner interface{}) (*unstructured.Unstructured, error) { + obj := &unstructured.Unstructured{Object: map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{"name": object}, + "spec": map[string]interface{}{field: map[string]interface{}{"inner": inner}}, + }} + return dynamicClient.Resource(gvr).Apply(context.TODO(), object, obj, metav1.ApplyOptions{FieldManager: "apply_test"}) + } + + for i, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + object, field := fieldName(i), fieldName(i) + if _, err := apply(object, field, map[string]interface{}{"a": "1", "b": "2"}); err != nil { + t.Fatalf("populating apply failed: %v", err) + } + got, err := apply(object, field, nil) + if tc.wantErr != "" { + if err == nil { + t.Fatalf("want apply to be rejected with %q, but it succeeded", tc.wantErr) + } + if !strings.Contains(err.Error(), tc.wantErr) { + t.Fatalf("want apply error to contain %q, got: %v", tc.wantErr, err) + } + return + } + if err != nil { + t.Fatalf("clearing apply was rejected: %v", err) + } + + inner, _, err := unstructured.NestedFieldNoCopy(got.Object, "spec", field, "inner") + if err != nil { + t.Fatalf("reading spec.%s.inner: %v", field, err) + } + if tc.wantNull && inner != nil { + t.Errorf("want inner to be null, got %#v", inner) + } + }) + } +} + +func mkObjectSchema(nullable, subfieldRequired bool) apiextensionsv1.JSONSchemaProps { + s := apiextensionsv1.JSONSchemaProps{ + Type: "object", + Nullable: nullable, + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "a": {Type: "string"}, + "b": {Type: "string"}, + }, + } + if subfieldRequired { + s.Required = []string{"a", "b"} + } + return s +} From fb2467e2c313a26bd272f31cd8ae23dbbec6bd09 Mon Sep 17 00:00:00 2001 From: HirazawaUi <695097494plus@gmail.com> Date: Thu, 2 Jul 2026 00:46:45 +0800 Subject: [PATCH 15/19] stop logging missing optional container annotations --- pkg/kubelet/kuberuntime/labels.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pkg/kubelet/kuberuntime/labels.go b/pkg/kubelet/kuberuntime/labels.go index cef97ec0511bc..0a9f783131429 100644 --- a/pkg/kubelet/kuberuntime/labels.go +++ b/pkg/kubelet/kuberuntime/labels.go @@ -201,22 +201,22 @@ func getContainerInfoFromAnnotations(ctx context.Context, annotations map[string if containerInfo.RestartCount, err = getIntValueFromLabel(logger, annotations, containerRestartCountLabel); err != nil { logger.Error(err, "Unable to get label value from annotations", "label", containerRestartCountLabel, "annotations", annotations) } - if containerInfo.PodDeletionGracePeriod, err = getInt64PointerFromLabel(logger, annotations, podDeletionGracePeriodLabel); err != nil { + if containerInfo.PodDeletionGracePeriod, err = getInt64PointerFromLabel(annotations, podDeletionGracePeriodLabel); err != nil { logger.Error(err, "Unable to get label value from annotations", "label", podDeletionGracePeriodLabel, "annotations", annotations) } - if containerInfo.PodTerminationGracePeriod, err = getInt64PointerFromLabel(logger, annotations, podTerminationGracePeriodLabel); err != nil { + if containerInfo.PodTerminationGracePeriod, err = getInt64PointerFromLabel(annotations, podTerminationGracePeriodLabel); err != nil { logger.Error(err, "Unable to get label value from annotations", "label", podTerminationGracePeriodLabel, "annotations", annotations) } preStopHandler := &v1.LifecycleHandler{} - if found, err := getJSONObjectFromLabel(logger, annotations, containerPreStopHandlerLabel, preStopHandler); err != nil { + if found, err := getJSONObjectFromLabel(annotations, containerPreStopHandlerLabel, preStopHandler); err != nil { logger.Error(err, "Unable to get label value from annotations", "label", containerPreStopHandlerLabel, "annotations", annotations) } else if found { containerInfo.PreStopHandler = preStopHandler } containerPorts := []v1.ContainerPort{} - if found, err := getJSONObjectFromLabel(logger, annotations, containerPortsLabel, &containerPorts); err != nil { + if found, err := getJSONObjectFromLabel(annotations, containerPortsLabel, &containerPorts); err != nil { logger.Error(err, "Unable to get label value from annotations", "label", containerPortsLabel, "annotations", annotations) } else if found { containerInfo.ContainerPorts = containerPorts @@ -266,7 +266,7 @@ func getUint64ValueFromLabel(ctx context.Context, labels map[string]string, labe return 0, nil } -func getInt64PointerFromLabel(logger klog.Logger, labels map[string]string, label string) (*int64, error) { +func getInt64PointerFromLabel(labels map[string]string, label string) (*int64, error) { if strValue, found := labels[label]; found { int64Value, err := strconv.ParseInt(strValue, 10, 64) if err != nil { @@ -275,17 +275,15 @@ func getInt64PointerFromLabel(logger klog.Logger, labels map[string]string, labe return &int64Value, nil } // If the label is not found, return pointer nil. - logger.V(4).Info("Label not found", "label", label) return nil, nil } // getJSONObjectFromLabel returns a bool value indicating whether an object is found. -func getJSONObjectFromLabel(logger klog.Logger, labels map[string]string, label string, value interface{}) (bool, error) { +func getJSONObjectFromLabel(labels map[string]string, label string, value interface{}) (bool, error) { if strValue, found := labels[label]; found { err := json.Unmarshal([]byte(strValue), value) return found, err } // If the label is not found, return not found. - logger.V(4).Info("Label not found", "label", label) return false, nil } From 2c14a99ab7744b91eccd84ae618ffe598387e795 Mon Sep 17 00:00:00 2001 From: Nabarun Pal Date: Wed, 15 Jul 2026 12:55:44 +0700 Subject: [PATCH 16/19] Bump images and versions to golang 1.26.5 and update distroless-iptables Signed-off-by: Nabarun Pal --- .go-version | 2 +- build/build-image/cross/VERSION | 2 +- build/common.sh | 4 ++-- build/dependencies.yaml | 6 +++--- test/utils/image/manifest.go | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.go-version b/.go-version index ea0928cedf0da..8fe00a57fe1d3 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.26.4 +1.26.5 diff --git a/build/build-image/cross/VERSION b/build/build-image/cross/VERSION index eaff4eee6313c..8d181a62ca5f6 100644 --- a/build/build-image/cross/VERSION +++ b/build/build-image/cross/VERSION @@ -1 +1 @@ -v1.36.0-go1.26.4-bullseye.0 \ No newline at end of file +v1.36.0-go1.26.5-bullseye.0 diff --git a/build/common.sh b/build/common.sh index 4e6a5307b630a..718f549036b18 100755 --- a/build/common.sh +++ b/build/common.sh @@ -77,8 +77,8 @@ readonly REMOTE_OUTPUT_BINPATH="${REMOTE_OUTPUT_SUBPATH}/bin" readonly REMOTE_OUTPUT_GOPATH="${REMOTE_OUTPUT_SUBPATH}/go" # These are the default versions (image tags) for their respective base images. -readonly __default_distroless_iptables_version=v0.9.3 -readonly __default_go_runner_version=v2.4.0-go1.26.4-bookworm.0 +readonly __default_distroless_iptables_version=v0.9.6 +readonly __default_go_runner_version=v2.4.0-go1.26.5-bookworm.0 readonly __default_setcap_version=bookworm-v1.0.6 # The default image for all binaries which are dynamically linked. diff --git a/build/dependencies.yaml b/build/dependencies.yaml index ba2532f5de25f..2096e578db198 100644 --- a/build/dependencies.yaml +++ b/build/dependencies.yaml @@ -137,7 +137,7 @@ dependencies: # should also be updated, but go-runner is much harder to exploit and has # far less relevancy to go updates for Kubernetes more generally. - name: "registry.k8s.io/kube-cross: dependents" - version: v1.36.0-go1.26.4-bullseye.0 + version: v1.36.0-go1.26.5-bullseye.0 refPaths: - path: build/build-image/cross/VERSION @@ -175,7 +175,7 @@ dependencies: match: registry\.k8s\.io\/build-image\/debian-base:[a-zA-Z]+\-v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?) - name: "registry.k8s.io/distroless-iptables: dependents" - version: v0.9.3 + version: v0.9.6 refPaths: - path: build/common.sh match: __default_distroless_iptables_version= @@ -183,7 +183,7 @@ dependencies: match: configs\[DistrolessIptables\] = Config{list\.BuildImageRegistry, "distroless-iptables", "v([0-9]+)\.([0-9]+)\.([0-9]+)"} - name: "registry.k8s.io/go-runner: dependents" - version: v2.4.0-go1.26.4-bookworm.0 + version: v2.4.0-go1.26.5-bookworm.0 refPaths: - path: build/common.sh match: __default_go_runner_version= diff --git a/test/utils/image/manifest.go b/test/utils/image/manifest.go index 02bb51ec14e20..0cb29deba7f99 100644 --- a/test/utils/image/manifest.go +++ b/test/utils/image/manifest.go @@ -214,7 +214,7 @@ func initImageConfigs(list RegistryList) (map[ImageID]Config, map[ImageID]Config configs[APIServer] = Config{list.PromoterE2eRegistry, "sample-apiserver", "1.29.2"} configs[AppArmorLoader] = Config{list.PromoterE2eRegistry, "apparmor-loader", "1.4"} configs[BusyBox] = Config{list.PromoterE2eRegistry, "busybox", "1.37.0-1"} - configs[DistrolessIptables] = Config{list.BuildImageRegistry, "distroless-iptables", "v0.9.3"} + configs[DistrolessIptables] = Config{list.BuildImageRegistry, "distroless-iptables", "v0.9.6"} configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.6.8-0"} configs[InvalidRegistryImage] = Config{list.InvalidRegistry, "alpine", "3.1"} configs[IpcUtils] = Config{list.PromoterE2eRegistry, "ipc-utils", "1.4"} From 5874ee71eefe03003a6f24f593dfdff1272418d7 Mon Sep 17 00:00:00 2001 From: thc1006 <84045975+thc1006@users.noreply.github.com> Date: Wed, 15 Jul 2026 14:27:20 +0000 Subject: [PATCH 17/19] DRA: roll back reserved state in allocateDevice Backport of #140431 to release-1.36 (six commits squashed). allocateDevice reserves a device's shared counters and adds claim constraints before it may reject a candidate on a device taint or a claim constraint, and for an accepted candidate it also marks the device in use and reserves consumable capacity. Some rejection and backtracking paths did not reverse what they had done, so a leaked counter reservation made the allocator treat a counter set as exhausted and fail to allocate a device combination a node can satisfy. Each call now records what it mutated in a small deviceRollbackState value and reverses it with one rollbackDevice method, on every rejection path and on the backtracking undo. It also preserves the shared empty-capacity marker when rolling back one share of an allow-multiple device that another live share still relies on, so a later share is no longer wrongly rejected with insufficient counters. DRAConsumableCapacity, DRADeviceTaints, and DRAPartitionableDevices are beta and on by default in 1.36, so the bug is reachable on a default cluster. --- .../allocatortesting/allocator_testing.go | 314 ++++++++++++++++++ .../experimental/allocator_experimental.go | 114 +++++-- .../incubating/allocator_incubating.go | 114 +++++-- .../internal/stable/allocator_stable.go | 78 ++++- 4 files changed, 546 insertions(+), 74 deletions(-) diff --git a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/allocatortesting/allocator_testing.go b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/allocatortesting/allocator_testing.go index c6a68c2043dee..593d766235aaf 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/allocatortesting/allocator_testing.go +++ b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/allocatortesting/allocator_testing.go @@ -2006,6 +2006,51 @@ func TestAllocator(t *testing.T, expectError: gomega.MatchError(gomega.ContainSubstring("claim claim-0, request req-0: cannot add device driver-a/pool-1/device-2 because a claim constraint would not be satisfied")), }, + "partitionable-all-mode-constraint-must-error-with-reserved-counter": { + // Covers allocateDevice's must=true error path when the rejected device + // has already reserved a shared counter. An all-mode request over two + // devices with mismatched constraint attributes fails on the second + // device, which consumes the counter, so rollbackDevice runs with a + // reserved counter before the must-error is returned. The error aborts the + // whole allocation, so this asserts the error contract and exercises the + // counter-release branch; the released counter is not separately + // observable through the allocation result. + features: Features{ + PartitionableDevices: true, + }, + claimsToAllocate: objects( + func() wrapResourceClaim { + claim := claimWithRequests( + claim0, + []resourceapi.DeviceConstraint{{MatchAttribute: &intAttribute}}, + request(req0, classA, 0), + ) + claim.Spec.Devices.Requests[0].Exactly.AllocationMode = resourceapi.DeviceAllocationModeAll + return claim + }(), + ), + classes: objects(class(classA, driverA)), + slices: unwrapResourceSlices( + sliceWithDevices(slice1, node1, resourcePool(pool1, 2), driverA, + device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "numa": {IntValue: new(int64(1))}, + }), + // device2 mismatches the constraint and consumes the single + // counter, so it reserves the counter first and then fails the + // constraint, reaching the must-error path with state to undo. + device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "numa": {IntValue: new(int64(2))}, + }).withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + sliceWithCounterSets(slice2, node1, resourcePool(pool1, 2), driverA, + counterSet(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + node: node(node1, region1), + expectError: gomega.MatchError(gomega.ContainSubstring("claim claim-0, request req-0: cannot add device driver-a/pool-1/device-2 because a claim constraint would not be satisfied")), + }, "with-constraint-not-matching-string-attribute": { claimsToAllocate: objects(claimWithRequests( claim0, @@ -2858,6 +2903,275 @@ func TestAllocator(t *testing.T, deviceAllocationResult(req0, driverA, pool1, device1, false), )}, }, + "partitionable-devices-taint-releases-counter": { + features: Features{ + PartitionableDevices: true, + DeviceTaints: true, + }, + claimsToAllocate: objects( + claimWithRequests(claim0, nil, request(req0, classA, 1)), + ), + classes: objects(class(classA, driverA)), + slices: unwrapResourceSlices( + sliceWithDevices(slice1, node1, resourcePool(pool1, 2), driverA, + device(device1, nil, nil).withTaints(taintNoSchedule).withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + device(device2, nil, nil).withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + sliceWithCounterSets(slice2, node1, resourcePool(pool1, 2), driverA, + counterSet(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + node: node(node1, region1), + // device1 is rejected by its NoSchedule taint after its counter is + // reserved. Releasing that reservation lets the clean device2 allocate. + expectResults: []any{allocationResult( + localNodeSelector(node1), + deviceAllocationResult(req0, driverA, pool1, device2, false), + )}, + }, + "partitionable-devices-constraint-releases-counter": { + features: Features{ + PartitionableDevices: true, + }, + claimsToAllocate: objects( + claimWithRequests(claim0, + []resourceapi.DeviceConstraint{{MatchAttribute: &stringAttribute}}, + request(req0, classA, 2), + ), + ), + classes: objects(class(classA, driverA)), + slices: unwrapResourceSlices( + sliceWithDevices(slice1, node1, resourcePool(pool1, 2), driverA, + device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "stringAttribute": {StringValue: new("red")}, + }).withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "stringAttribute": {StringValue: new("blue")}, + }).withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + device(device3, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "stringAttribute": {StringValue: new("blue")}, + }).withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + sliceWithCounterSets(slice2, node1, resourcePool(pool1, 2), driverA, + counterSet(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("2")}), + ), + ), + node: node(node1, region1), + // device1 (red) is accepted first; the blue candidates are rejected by + // the match-attribute constraint after their counters are reserved. + // Releasing those reservations lets the two blue devices allocate. + expectResults: []any{allocationResult( + localNodeSelector(node1), + deviceAllocationResult(req0, driverA, pool1, device2, false), + deviceAllocationResult(req0, driverA, pool1, device3, false), + )}, + }, + "partitionable-consumable-capacity-backtrack-releases-counter": { + features: Features{ + PartitionableDevices: true, + ConsumableCapacity: true, + }, + claimsToAllocate: objects( + claimWithRequests(claim0, nil, + request(req0, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].kind == "shared"`, driverA), + }}), + request(req1, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].kind == "counteronly"`, driverA), + }}), + ), + ), + classes: objects(class(classA, driverA)), + slices: unwrapResourceSlices( + sliceWithDevices(slice1, node1, resourcePool(pool1, 2), driverA, + // device1 allows multiple allocations and consumes the single + // shared counter. It is listed first, so req0 reserves its counter + // on the first try. + device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "kind": {StringValue: new("shared")}, + }).withAllowMultipleAllocations().withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + // device2 consumes no counter and is the correct choice for req0 + // once device1 has been backtracked. + device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "kind": {StringValue: new("shared")}, + }), + // device3 is the only device that satisfies req1 and needs the same + // counter device1 reserved. + device(device3, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "kind": {StringValue: new("counteronly")}, + }).withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + sliceWithCounterSets(slice2, node1, resourcePool(pool1, 2), driverA, + counterSet(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + node: node(node1, region1), + // device1 allows multiple allocations and reserves the single shared + // counter when req0 tries it first. req1 can only use device3, which needs + // that same counter, so the search must backtrack device1. The backtracking + // undo has to release device1's counter reservation; otherwise req0 cannot + // fall back to device2 and req1 cannot take device3. + expectResults: []any{allocationResult( + localNodeSelector(node1), + deviceAllocationResult(req0, driverA, pool1, device2, false), + deviceAllocationResult(req1, driverA, pool1, device3, false), + )}, + }, + "consumable-capacity-rejection-rolls-back-constraints": { + features: Features{ + ConsumableCapacity: true, + PrioritizedList: true, + }, + claimsToAllocate: objects( + // claim0 consumes all of device1's capacity first. Its request is not + // subject to claim1's constraint, so it does not set the reference value. + claim(claim0).withRequests( + deviceRequest(req0, classA, 1). + withCapacityRequest(new(two)). + withSelectors(resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].stringAttribute == "cap"`, driverA), + }}), + ), + // claim1 has a match-attribute constraint. Its first (all-mode) + // subrequest includes device1, which was capacity-sufficient when the + // candidate list was built but is now full, so it is rejected on the + // in-function capacity check after being added to the constraint. The + // fallback subrequest then needs device2, whose attribute differs. + claim(claim1). + withConstraints(resourceapi.DeviceConstraint{MatchAttribute: &stringAttribute}). + withRequests(requestWithPrioritizedList(req0, + subRequest(subReq0, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].stringAttribute == "cap"`, driverA), + }}). + withAllocationMode(resourceapi.DeviceAllocationModeAll). + withCapacityRequest(new(two)), + subRequest(subReq1, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].stringAttribute == "fb"`, driverA), + }}), + )), + ), + classes: objects(class(classA, driverA)), + slices: unwrapResourceSlices( + sliceWithDevices(slice1, node1, pool1, driverA, + device(device1, map[resourceapi.QualifiedName]resource.Quantity{capacity0: two}, + map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "stringAttribute": {StringValue: new("cap")}, + }).withAllowMultipleAllocations(), + device(device2, nil, + map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "stringAttribute": {StringValue: new("fb")}, + }), + ), + ), + node: node(node1, region1), + // claim1's all-mode subReq0 adds device1 to the match constraint and is then + // rejected because claim0 already consumed device1's capacity. Rolling back + // that rejected candidate's constraint entry is what lets the fallback + // subReq1 take device2; otherwise device1's leaked attribute value blocks it. + expectResults: []any{ + allocationResult(localNodeSelector(node1), + deviceRequestAllocationResult(req0, driverA, pool1, device1). + withConsumedCapacity(&fixedShareID, map[resourceapi.QualifiedName]resource.Quantity{capacity0: two})), + allocationResult(localNodeSelector(node1), + deviceAllocationResult(req0SubReq1, driverA, pool1, device2, false)), + }, + }, + "partitionable-empty-capacity-multiple-share-backtrack-keeps-counter-ownership": { + features: Features{ + PartitionableDevices: true, + ConsumableCapacity: true, + }, + claimsToAllocate: objects( + // claim0 pins device1 as the first share and reserves its single + // shared counter. + claimWithRequests(claim0, nil, + request(req0, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].kind == "shared"`, driverA), + }}), + ), + // claim1's req1 first tries device1 as a second share (skipping the + // counter, since claim0 already reserved it), but the match-attribute + // constraint with req2 forces it to backtrack onto device2. req3 then + // shares device1 again, after req1 has already left it. + claimWithRequests(claim1, + []resourceapi.DeviceConstraint{ + {MatchAttribute: &stringAttribute, Requests: []string{req1, req2}}, + }, + request(req1, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].kind == "shared" || device.attributes["%s"].kind == "fallback"`, driverA, driverA), + }}), + request(req2, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].kind == "gate"`, driverA), + }}), + request(req3, classA, 1, resourceapi.DeviceSelector{ + CEL: &resourceapi.CELDeviceSelector{ + Expression: fmt.Sprintf(`device.attributes["%s"].kind == "shared"`, driverA), + }}), + ), + ), + classes: objects(class(classA, driverA)), + slices: unwrapResourceSlices( + sliceWithDevices(slice1, node1, resourcePool(pool1, 2), driverA, + // device1: allow-multiple, no capacity, consumes the single counter. + // kind steers the selectors; stringAttribute steers the constraint. + device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "kind": {StringValue: new("shared")}, + "stringAttribute": {StringValue: new("red")}, + }).withAllowMultipleAllocations().withDeviceCounterConsumption( + deviceCounterConsumption(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + // device2: the fallback for req1, matching req2's stringAttribute. + device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "kind": {StringValue: new("fallback")}, + "stringAttribute": {StringValue: new("blue")}, + }), + // device3: the only device req2 can take. + device(device3, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{ + "kind": {StringValue: new("gate")}, + "stringAttribute": {StringValue: new("blue")}, + }), + ), + sliceWithCounterSets(slice2, node1, resourcePool(pool1, 2), driverA, + counterSet(counterSet1, map[string]resource.Quantity{"c": resource.MustParse("1")}), + ), + ), + node: node(node1, region1), + // claim0 reserves device1's counter as the first share. claim1's req1 tries + // device1 as a second share, skips the counter, then backtracks onto device2 + // because of the constraint with req2. Rolling back that empty-capacity share + // must not drop device1's shared marker, because claim0's share still holds + // the counter. req3 then shares device1 again without recharging the counter. + expectResults: []any{ + allocationResult(localNodeSelector(node1), + deviceRequestAllocationResult(req0, driverA, pool1, device1).withConsumedCapacity(&fixedShareID, nil)), + allocationResult(localNodeSelector(node1), + deviceAllocationResult(req1, driverA, pool1, device2, false), + deviceAllocationResult(req2, driverA, pool1, device3, false), + deviceRequestAllocationResult(req3, driverA, pool1, device1).withConsumedCapacity(&fixedShareID, nil)), + }, + }, "partitionable-devices-prioritized-list": { features: Features{ PrioritizedList: true, diff --git a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/experimental/allocator_experimental.go b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/experimental/allocator_experimental.go index d2a2ecb92aaee..51a299942626a 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/experimental/allocator_experimental.go +++ b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/experimental/allocator_experimental.go @@ -1463,6 +1463,10 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus skipCounterCheck := allowMultipleAllocations && alloc.deviceCapacityInUse(device.id) // The API validation logic has checked the ConsumesCounters referred should exist inside SharedCounters. + // countersReserved records whether checkAvailableCounters actually reserved + // this device's counters. It is not the same as len(device.ConsumesCounters) > 0, + // because skipCounterCheck can bypass the reservation. + countersReserved := false if !skipCounterCheck && len(device.ConsumesCounters) > 0 { // If a device consumes counters from a counter set, verify that // there is sufficient counters available. @@ -1474,6 +1478,7 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus alloc.logger.V(7).Info("Insufficient counters", "device", device.id) return false, nil, nil } + countersReserved = true } var parentRequestName string @@ -1487,39 +1492,48 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus subRequestName = requestData.request.name() } + // state records the mutations this call makes so rollbackDevice can undo + // them. Every rejection path after a successful counter reservation calls + // rollbackDevice synchronously, and the success path returns a closure that + // calls the same helper during backtracking, so both undo routes stay + // identical. Passing the state by value to rollbackDevice keeps it (and the flags) on the + // stack for the rejection paths; only the success closure escapes. + state := deviceRollbackState{ + countersReserved: countersReserved, + previousNumResults: len(alloc.result[r.claimIndex].devices), + } + // Might be tainted, in which case the taint has to be tolerated. // The check is skipped if the feature is disabled. if alloc.features.DeviceTaints && taintPreventsAllocation(device.Device, request) { + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) return false, nil, nil } // It's available. Now check constraints. - for i, constraint := range alloc.constraints[r.claimIndex] { - added := constraint.add(baseRequestName, subRequestName, device.Device, device.id) - if !added { + for _, constraint := range alloc.constraints[r.claimIndex] { + if !constraint.add(baseRequestName, subRequestName, device.Device, device.id) { + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) if must { // It does not make sense to declare a claim where a constraint prevents getting // all devices. Treat this as an error. return false, nil, fmt.Errorf("claim %s, request %s: cannot add device %s because a claim constraint would not be satisfied", klog.KObj(claim), request.name(), device.id) } - - // Roll back for all previous constraints before we return. - for e := 0; e < i; e++ { - alloc.constraints[r.claimIndex][e].remove(baseRequestName, subRequestName, device.Device, device.id) - } return false, nil, nil } + state.constraintsAdded++ } // All constraints satisfied. Mark as in use (unless we do admin access or allow multiple allocations) // and record the result. alloc.logger.V(7).Info("Device allocated", "device", device.id) - if alloc.allocatingDevices[device.id] == nil { - alloc.allocatingDevices[device.id] = make(sets.Set[int]) - } if !allowMultipleAllocations { + if alloc.allocatingDevices[device.id] == nil { + alloc.allocatingDevices[device.id] = make(sets.Set[int]) + } alloc.allocatingDevices[device.id].Insert(r.claimIndex) + state.deviceMarked = true } consumedCapacity := make(map[resourceapi.QualifiedName]resource.Quantity, 0) @@ -1531,10 +1545,12 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus if err != nil { alloc.logger.V(7).Info("Failed to compare device capacity request on allocateDevice", "device", device, "request", requestData.request.name(), "err", err) + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) return false, nil, nil } if !success { alloc.logger.V(7).Info("Device capacity not enough", "device", device) + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) return false, nil, nil } @@ -1543,7 +1559,14 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus shareID = GenerateNewShareID() alloc.logger.V(7).Info("Device capacity allocated", "device", device.id, "consumed capacity", klog.Format(consumedCapacity)) + // A prior share of this device may already hold the capacity entry. + // That entry doubles as the "already shared" marker that lets a later + // share skip the counter check, so record whether it predated this + // share; rollback must not delete it while another share still needs it. + _, state.capacityEntryExisted = alloc.allocatingCapacity[device.id] alloc.allocatingCapacity.Insert(NewDeviceConsumedCapacity(device.id, consumedCapacity)) + state.capacityInserted = true + state.consumedCapacity = consumedCapacity } } @@ -1561,29 +1584,64 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus if len(consumedCapacity) > 0 { result.consumedCapacity = consumedCapacity } - previousNumResults := len(alloc.result[r.claimIndex].devices) alloc.result[r.claimIndex].devices = append(alloc.result[r.claimIndex].devices, result) + state.resultAdded = true + // Only this success path builds an escaping closure, so backtracking can undo + // a committed candidate. undo is a copy: capturing state directly would move it + // and its flags to the heap on the rejection paths too, which never escape. + undo := state return true, func() { - for _, constraint := range alloc.constraints[r.claimIndex] { - constraint.remove(baseRequestName, subRequestName, device.Device, device.id) - } - alloc.allocatingDevices[device.id].Delete(r.claimIndex) - if allowMultipleAllocations { - requestedResource := alloc.result[r.claimIndex].devices[previousNumResults].consumedCapacity - if requestedResource != nil { - alloc.allocatingCapacity.Remove(NewDeviceConsumedCapacity(device.id, requestedResource)) - } - } else { - alloc.allocatingDevices[device.id].Delete(r.claimIndex) - if alloc.features.PartitionableDevices && len(device.ConsumesCounters) > 0 { - alloc.deallocateCountersForDevice(device) + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, undo) + }, nil +} + +// deviceRollbackState records the mutations allocateDevice makes for a single +// candidate so rollbackDevice can undo them, both when the candidate is rejected +// and when the backtracking search abandons a previously successful candidate. +type deviceRollbackState struct { + countersReserved bool + constraintsAdded int + deviceMarked bool + capacityInserted bool + capacityEntryExisted bool + resultAdded bool + previousNumResults int + consumedCapacity map[resourceapi.QualifiedName]resource.Quantity +} + +// rollbackDevice reverses the mutations recorded in state, in the opposite order +// they were applied. It is called synchronously on the rejection paths and, via +// the closure returned on success, during backtracking. +func (alloc *allocator) rollbackDevice(r deviceIndices, device deviceWithID, baseRequestName, subRequestName string, state deviceRollbackState) { + if state.resultAdded { + alloc.result[r.claimIndex].devices = alloc.result[r.claimIndex].devices[:state.previousNumResults] + } + if state.capacityInserted { + alloc.allocatingCapacity.Remove(NewDeviceConsumedCapacity(device.id, state.consumedCapacity)) + if state.capacityEntryExisted { + // Remove drops the entry once it becomes empty, which also erases the + // shared marker that the earlier share still relies on. Restore an empty + // entry in that case so the earlier share stays accounted as shared. + if _, found := alloc.allocatingCapacity[device.id]; !found { + alloc.allocatingCapacity[device.id] = NewConsumedCapacity() } } - // Truncate, but keep the underlying slice. - alloc.result[r.claimIndex].devices = alloc.result[r.claimIndex].devices[:previousNumResults] + } + if state.deviceMarked { + alloc.allocatingDevices[device.id].Delete(r.claimIndex) + } + for i := state.constraintsAdded - 1; i >= 0; i-- { + alloc.constraints[r.claimIndex][i].remove(baseRequestName, subRequestName, device.Device, device.id) + } + if state.countersReserved { + alloc.deallocateCountersForDevice(device) + } + if state.resultAdded { + // Only a fully allocated candidate recorded a result, so this is a real + // deallocation during backtracking, not a rejection rollback. alloc.logger.V(7).Info("Device deallocated", "device", device.id) - }, nil + } } func taintPreventsAllocation(device *draapi.Device, request requestAccessor) bool { diff --git a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/incubating/allocator_incubating.go b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/incubating/allocator_incubating.go index a77feed54ca06..335dca2a8e7c1 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/incubating/allocator_incubating.go +++ b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/incubating/allocator_incubating.go @@ -1335,6 +1335,10 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus skipCounterCheck := allowMultipleAllocations && alloc.deviceCapacityInUse(device.id) // The API validation logic has checked the ConsumesCounters referred should exist inside SharedCounters. + // countersReserved records whether checkAvailableCounters actually reserved + // this device's counters. It is not the same as len(device.ConsumesCounters) > 0, + // because skipCounterCheck can bypass the reservation. + countersReserved := false if !skipCounterCheck && len(device.ConsumesCounters) > 0 { // If a device consumes counters from a counter set, verify that // there is sufficient counters available. @@ -1346,6 +1350,7 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus alloc.logger.V(7).Info("Insufficient counters", "device", device.id) return false, nil, nil } + countersReserved = true } var parentRequestName string @@ -1359,39 +1364,48 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus subRequestName = requestData.request.name() } + // state records the mutations this call makes so rollbackDevice can undo + // them. Every rejection path after a successful counter reservation calls + // rollbackDevice synchronously, and the success path returns a closure that + // calls the same helper during backtracking, so both undo routes stay + // identical. Passing the state by value to rollbackDevice keeps it (and the flags) on the + // stack for the rejection paths; only the success closure escapes. + state := deviceRollbackState{ + countersReserved: countersReserved, + previousNumResults: len(alloc.result[r.claimIndex].devices), + } + // Might be tainted, in which case the taint has to be tolerated. // The check is skipped if the feature is disabled. if alloc.features.DeviceTaints && taintPreventsAllocation(device.Device, request) { + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) return false, nil, nil } // It's available. Now check constraints. - for i, constraint := range alloc.constraints[r.claimIndex] { - added := constraint.add(baseRequestName, subRequestName, device.Device, device.id) - if !added { + for _, constraint := range alloc.constraints[r.claimIndex] { + if !constraint.add(baseRequestName, subRequestName, device.Device, device.id) { + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) if must { // It does not make sense to declare a claim where a constraint prevents getting // all devices. Treat this as an error. return false, nil, fmt.Errorf("claim %s, request %s: cannot add device %s because a claim constraint would not be satisfied", klog.KObj(claim), request.name(), device.id) } - - // Roll back for all previous constraints before we return. - for e := 0; e < i; e++ { - alloc.constraints[r.claimIndex][e].remove(baseRequestName, subRequestName, device.Device, device.id) - } return false, nil, nil } + state.constraintsAdded++ } // All constraints satisfied. Mark as in use (unless we do admin access or allow multiple allocations) // and record the result. alloc.logger.V(7).Info("Device allocated", "device", device.id) - if alloc.allocatingDevices[device.id] == nil { - alloc.allocatingDevices[device.id] = make(sets.Set[int]) - } if !allowMultipleAllocations { + if alloc.allocatingDevices[device.id] == nil { + alloc.allocatingDevices[device.id] = make(sets.Set[int]) + } alloc.allocatingDevices[device.id].Insert(r.claimIndex) + state.deviceMarked = true } consumedCapacity := make(map[resourceapi.QualifiedName]resource.Quantity, 0) @@ -1403,10 +1417,12 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus if err != nil { alloc.logger.V(7).Info("Failed to compare device capacity request on allocateDevice", "device", device, "request", requestData.request.name(), "err", err) + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) return false, nil, nil } if !success { alloc.logger.V(7).Info("Device capacity not enough", "device", device) + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) return false, nil, nil } @@ -1415,7 +1431,14 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus shareID = GenerateNewShareID() alloc.logger.V(7).Info("Device capacity allocated", "device", device.id, "consumed capacity", klog.Format(consumedCapacity)) + // A prior share of this device may already hold the capacity entry. + // That entry doubles as the "already shared" marker that lets a later + // share skip the counter check, so record whether it predated this + // share; rollback must not delete it while another share still needs it. + _, state.capacityEntryExisted = alloc.allocatingCapacity[device.id] alloc.allocatingCapacity.Insert(NewDeviceConsumedCapacity(device.id, consumedCapacity)) + state.capacityInserted = true + state.consumedCapacity = consumedCapacity } } @@ -1433,29 +1456,64 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus if len(consumedCapacity) > 0 { result.consumedCapacity = consumedCapacity } - previousNumResults := len(alloc.result[r.claimIndex].devices) alloc.result[r.claimIndex].devices = append(alloc.result[r.claimIndex].devices, result) + state.resultAdded = true + // Only this success path builds an escaping closure, so backtracking can undo + // a committed candidate. undo is a copy: capturing state directly would move it + // and its flags to the heap on the rejection paths too, which never escape. + undo := state return true, func() { - for _, constraint := range alloc.constraints[r.claimIndex] { - constraint.remove(baseRequestName, subRequestName, device.Device, device.id) - } - alloc.allocatingDevices[device.id].Delete(r.claimIndex) - if allowMultipleAllocations { - requestedResource := alloc.result[r.claimIndex].devices[previousNumResults].consumedCapacity - if requestedResource != nil { - alloc.allocatingCapacity.Remove(NewDeviceConsumedCapacity(device.id, requestedResource)) - } - } else { - alloc.allocatingDevices[device.id].Delete(r.claimIndex) - if alloc.features.PartitionableDevices && len(device.ConsumesCounters) > 0 { - alloc.deallocateCountersForDevice(device) + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, undo) + }, nil +} + +// deviceRollbackState records the mutations allocateDevice makes for a single +// candidate so rollbackDevice can undo them, both when the candidate is rejected +// and when the backtracking search abandons a previously successful candidate. +type deviceRollbackState struct { + countersReserved bool + constraintsAdded int + deviceMarked bool + capacityInserted bool + capacityEntryExisted bool + resultAdded bool + previousNumResults int + consumedCapacity map[resourceapi.QualifiedName]resource.Quantity +} + +// rollbackDevice reverses the mutations recorded in state, in the opposite order +// they were applied. It is called synchronously on the rejection paths and, via +// the closure returned on success, during backtracking. +func (alloc *allocator) rollbackDevice(r deviceIndices, device deviceWithID, baseRequestName, subRequestName string, state deviceRollbackState) { + if state.resultAdded { + alloc.result[r.claimIndex].devices = alloc.result[r.claimIndex].devices[:state.previousNumResults] + } + if state.capacityInserted { + alloc.allocatingCapacity.Remove(NewDeviceConsumedCapacity(device.id, state.consumedCapacity)) + if state.capacityEntryExisted { + // Remove drops the entry once it becomes empty, which also erases the + // shared marker that the earlier share still relies on. Restore an empty + // entry in that case so the earlier share stays accounted as shared. + if _, found := alloc.allocatingCapacity[device.id]; !found { + alloc.allocatingCapacity[device.id] = NewConsumedCapacity() } } - // Truncate, but keep the underlying slice. - alloc.result[r.claimIndex].devices = alloc.result[r.claimIndex].devices[:previousNumResults] + } + if state.deviceMarked { + alloc.allocatingDevices[device.id].Delete(r.claimIndex) + } + for i := state.constraintsAdded - 1; i >= 0; i-- { + alloc.constraints[r.claimIndex][i].remove(baseRequestName, subRequestName, device.Device, device.id) + } + if state.countersReserved { + alloc.deallocateCountersForDevice(device) + } + if state.resultAdded { + // Only a fully allocated candidate recorded a result, so this is a real + // deallocation during backtracking, not a rejection rollback. alloc.logger.V(7).Info("Device deallocated", "device", device.id) - }, nil + } } func taintPreventsAllocation(device *draapi.Device, request requestAccessor) bool { diff --git a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/stable/allocator_stable.go b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/stable/allocator_stable.go index bb85ff5286cb2..3b434bac95363 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/stable/allocator_stable.go +++ b/staging/src/k8s.io/dynamic-resource-allocation/structured/internal/stable/allocator_stable.go @@ -1124,6 +1124,9 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus } // The API validation logic has checked the ConsumesCounters referred should exist inside SharedCounters. + // countersReserved records whether checkAvailableCounters actually reserved + // this device's counters, so the rollback below only releases what was taken. + countersReserved := false if len(device.ConsumesCounters) > 0 { // If a device consumes counters from a counter set, verify that // there is sufficient counters available. @@ -1135,6 +1138,7 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus alloc.logger.V(7).Info("Insufficient counters", "device", device.id) return false, nil, nil } + countersReserved = true } var parentRequestName string @@ -1148,28 +1152,36 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus subRequestName = requestData.request.name() } + // state records the mutations this call makes so rollbackDevice can undo + // them. Every rejection path after a successful counter reservation calls + // rollbackDevice synchronously, and the success path returns a closure that + // calls the same helper during backtracking, so both undo routes stay + // identical. Passing the state by value to rollbackDevice keeps it (and the flags) on the + // stack for the rejection paths; only the success closure escapes. + state := deviceRollbackState{ + countersReserved: countersReserved, + previousNumResults: len(alloc.result[r.claimIndex].devices), + } + // Might be tainted, in which case the taint has to be tolerated. // The check is skipped if the feature is disabled. if alloc.features.DeviceTaints && taintPreventsAllocation(device.Device, request) { + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) return false, nil, nil } // It's available. Now check constraints. - for i, constraint := range alloc.constraints[r.claimIndex] { - added := constraint.add(baseRequestName, subRequestName, device.Device, device.id) - if !added { + for _, constraint := range alloc.constraints[r.claimIndex] { + if !constraint.add(baseRequestName, subRequestName, device.Device, device.id) { + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, state) if must { // It does not make sense to declare a claim where a constraint prevents getting // all devices. Treat this as an error. return false, nil, fmt.Errorf("claim %s, request %s: cannot add device %s because a claim constraint would not be satisfied", klog.KObj(claim), request.name(), device.id) } - - // Roll back for all previous constraints before we return. - for e := 0; e < i; e++ { - alloc.constraints[r.claimIndex][e].remove(baseRequestName, subRequestName, device.Device, device.id) - } return false, nil, nil } + state.constraintsAdded++ } // All constraints satisfied. Mark as in use (unless we do admin access) @@ -1180,6 +1192,7 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus alloc.allocatingDevices[device.id] = make(sets.Set[int]) } alloc.allocatingDevices[device.id].Insert(r.claimIndex) + state.deviceMarked = true result := internalDeviceResult{ request: request.name(), @@ -1191,21 +1204,50 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus if request.adminAccess() { result.adminAccess = ptr.To(request.adminAccess()) } - previousNumResults := len(alloc.result[r.claimIndex].devices) alloc.result[r.claimIndex].devices = append(alloc.result[r.claimIndex].devices, result) + state.resultAdded = true + // Only this success path builds an escaping closure, so backtracking can undo + // a committed candidate. undo is a copy: capturing state directly would move it + // and its flags to the heap on the rejection paths too, which never escape. + undo := state return true, func() { - for _, constraint := range alloc.constraints[r.claimIndex] { - constraint.remove(baseRequestName, subRequestName, device.Device, device.id) - } + alloc.rollbackDevice(r, device, baseRequestName, subRequestName, undo) + }, nil +} + +// deviceRollbackState records the mutations allocateDevice makes for a single +// candidate so rollbackDevice can undo them, both when the candidate is rejected +// and when the backtracking search abandons a previously successful candidate. +type deviceRollbackState struct { + countersReserved bool + constraintsAdded int + deviceMarked bool + resultAdded bool + previousNumResults int +} + +// rollbackDevice reverses the mutations recorded in state, in the opposite order +// they were applied. It is called synchronously on the rejection paths and, via +// the closure returned on success, during backtracking. +func (alloc *allocator) rollbackDevice(r deviceIndices, device deviceWithID, baseRequestName, subRequestName string, state deviceRollbackState) { + if state.resultAdded { + alloc.result[r.claimIndex].devices = alloc.result[r.claimIndex].devices[:state.previousNumResults] + } + if state.deviceMarked { alloc.allocatingDevices[device.id].Delete(r.claimIndex) - if alloc.features.PartitionableDevices && len(device.ConsumesCounters) > 0 { - alloc.deallocateCountersForDevice(device) - } - // Truncate, but keep the underlying slice. - alloc.result[r.claimIndex].devices = alloc.result[r.claimIndex].devices[:previousNumResults] + } + for i := state.constraintsAdded - 1; i >= 0; i-- { + alloc.constraints[r.claimIndex][i].remove(baseRequestName, subRequestName, device.Device, device.id) + } + if state.countersReserved { + alloc.deallocateCountersForDevice(device) + } + if state.resultAdded { + // Only a fully allocated candidate recorded a result, so this is a real + // deallocation during backtracking, not a rejection rollback. alloc.logger.V(7).Info("Device deallocated", "device", device.id) - }, nil + } } func taintPreventsAllocation(device *draapi.Device, request requestAccessor) bool { From 0f29094e5b73085e3802ecc1298ecae13866bfe6 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Wed, 22 Jul 2026 18:07:38 +0000 Subject: [PATCH 18/19] Release commit for Kubernetes v1.36.3 From 9deb7254b07e0ab3b65d6d12763dd211d938af4b Mon Sep 17 00:00:00 2001 From: Chai Bot Date: Mon, 27 Jul 2026 09:33:33 +0000 Subject: [PATCH 19/19] UPSTREAM: : hack/update-vendor.sh, make update and update image --- go.mod | 6 +- go.sum | 12 ++-- .../images/hyperkube/Dockerfile.rhel | 2 +- .../src/k8s.io/apiextensions-apiserver/go.mod | 4 +- .../src/k8s.io/apiextensions-apiserver/go.sum | 10 +-- staging/src/k8s.io/apiserver/go.mod | 2 +- staging/src/k8s.io/apiserver/go.sum | 8 +-- staging/src/k8s.io/cloud-provider/go.mod | 2 +- staging/src/k8s.io/cloud-provider/go.sum | 8 +-- .../src/k8s.io/code-generator/examples/go.mod | 30 +++++--- staging/src/k8s.io/controller-manager/go.sum | 2 +- .../k8s.io/dynamic-resource-allocation/go.sum | 2 +- staging/src/k8s.io/kube-aggregator/go.mod | 2 +- staging/src/k8s.io/kube-aggregator/go.sum | 8 +-- .../src/k8s.io/kube-controller-manager/go.sum | 2 +- staging/src/k8s.io/kube-scheduler/go.sum | 2 +- .../src/k8s.io/pod-security-admission/go.mod | 2 +- .../src/k8s.io/pod-security-admission/go.sum | 8 +-- staging/src/k8s.io/sample-apiserver/go.mod | 2 +- staging/src/k8s.io/sample-apiserver/go.sum | 8 +-- staging/src/k8s.io/sample-controller/go.mod | 38 ++++++---- .../api/config/v1/types_infrastructure.go | 30 ++++++++ .../api/config/v1/types_kmsencryption.go | 49 ++++++++++++- ..._generated.featuregated-crd-manifests.yaml | 1 + .../v1/zz_generated.swagger_doc_generated.go | 17 ++--- .../openshift/api/features/features.go | 20 +++++- .../openshift/api/operator/v1/types.go | 12 ++++ .../api/operator/v1/types_kmsencryption.go | 70 +++++++++++++++++++ .../api/operator/v1/zz_generated.deepcopy.go | 34 +++++++++ .../operator/v1/zz_generated.model_name.go | 10 +++ .../v1/zz_generated.swagger_doc_generated.go | 23 ++++++ .../config/v1/vaultkmspluginconfig.go | 55 ++++++++------- .../applyconfigurations/internal/internal.go | 6 +- vendor/modules.txt | 6 +- 34 files changed, 379 insertions(+), 114 deletions(-) diff --git a/go.mod b/go.mod index b33d07e18ee4f..8d790008cc00b 100644 --- a/go.mod +++ b/go.mod @@ -45,10 +45,10 @@ require ( github.com/opencontainers/cgroups v0.0.6 github.com/opencontainers/selinux v1.13.1 github.com/openshift-eng/openshift-tests-extension v0.0.0-20260707142426-572a3e9deb7a - github.com/openshift/api v0.0.0-20260715165912-72066cc9718b + github.com/openshift/api v0.0.0-20260726224011-9bcaa16cb258 github.com/openshift/apiserver-library-go v0.0.0-20260715200723-42e5e402ca43 - github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec - github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece + github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73 + github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.67.5 diff --git a/go.sum b/go.sum index a627d3583d233..f80f1f88e2806 100644 --- a/go.sum +++ b/go.sum @@ -336,15 +336,15 @@ github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22 github.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg= github.com/openshift-eng/openshift-tests-extension v0.0.0-20260707142426-572a3e9deb7a h1:ulT0JZ/x6S4hYhyjUJ9T49YAxDLl1i5idFOMm9RHBkY= github.com/openshift-eng/openshift-tests-extension v0.0.0-20260707142426-572a3e9deb7a/go.mod h1:pHOS9c6BjZv91OkkHyIHAOWnYhxwcxWQkyYGEvPyUCE= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b h1:gN3SihCYEwoIksD+f24wHhwiEgvaV0RxNjgmkDvBBeg= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= +github.com/openshift/api v0.0.0-20260726224011-9bcaa16cb258 h1:H3YE8JauUO8zH06YF4pA8J8mO8ZO7MhB3IkO4mu7XSE= +github.com/openshift/api v0.0.0-20260726224011-9bcaa16cb258/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/apiserver-library-go v0.0.0-20260715200723-42e5e402ca43 h1:V9hWaBi9cnohNk1F0Ph6wpI0otMWqMHleJ3oj5603Bc= github.com/openshift/apiserver-library-go v0.0.0-20260715200723-42e5e402ca43/go.mod h1:ZuzfEq1ccZpHNx05xEUKlm2TcMHt2iXVutb79kAuTfM= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec h1:UDjX+mot5IVLpcChyBqLXG1oSB29s4UkqFmgNb0Xsqc= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec/go.mod h1:iMHec0APKVjOH8GfL/RxddX8DuiuSvPlRe+s7KDqlyA= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece h1:Uec2loy7Mvq2ngzFqiJyEJkQn/ZMsDL8Z92iCMZgqxE= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73 h1:sM06vuu8s7EyWnOQZ4CMqLl2sJLFop1fL54GeK6nE0A= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 h1:zY/1DboFSjayWXzdaTAw3gCLmigBFh7vWLK6DwZ7wZU= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20260424201627-4d4cc33d669d h1:t+XyaZL4LpQx/AY2SETlMCQPLc9vd05ZZ7WXvD9doME= github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20260424201627-4d4cc33d669d/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= diff --git a/openshift-hack/images/hyperkube/Dockerfile.rhel b/openshift-hack/images/hyperkube/Dockerfile.rhel index ac000558bde21..c306f87d1a14b 100644 --- a/openshift-hack/images/hyperkube/Dockerfile.rhel +++ b/openshift-hack/images/hyperkube/Dockerfile.rhel @@ -15,4 +15,4 @@ COPY --from=builder /tmp/build/* /usr/bin/ LABEL io.k8s.display-name="OpenShift Kubernetes Server Commands" \ io.k8s.description="OpenShift is a platform for developing, building, and deploying containerized applications." \ io.openshift.tags="openshift,hyperkube" \ - io.openshift.build.versions="kubernetes=1.36.2" + io.openshift.build.versions="kubernetes=1.36.3" diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.mod b/staging/src/k8s.io/apiextensions-apiserver/go.mod index 320766b601566..bd8788d49aced 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.mod +++ b/staging/src/k8s.io/apiextensions-apiserver/go.mod @@ -13,7 +13,7 @@ require ( github.com/google/gnostic-models v0.7.0 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 - github.com/openshift/api v0.0.0-20260715165912-72066cc9718b + github.com/openshift/api v0.0.0-20260726224011-9bcaa16cb258 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 @@ -89,7 +89,7 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece // indirect + github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.sum b/staging/src/k8s.io/apiextensions-apiserver/go.sum index 816181b954b72..f126c07702ef5 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.sum +++ b/staging/src/k8s.io/apiextensions-apiserver/go.sum @@ -190,12 +190,12 @@ github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6u github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b h1:gN3SihCYEwoIksD+f24wHhwiEgvaV0RxNjgmkDvBBeg= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= +github.com/openshift/api v0.0.0-20260726224011-9bcaa16cb258 h1:H3YE8JauUO8zH06YF4pA8J8mO8ZO7MhB3IkO4mu7XSE= +github.com/openshift/api v0.0.0-20260726224011-9bcaa16cb258/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec/go.mod h1:iMHec0APKVjOH8GfL/RxddX8DuiuSvPlRe+s7KDqlyA= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece h1:Uec2loy7Mvq2ngzFqiJyEJkQn/ZMsDL8Z92iCMZgqxE= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 h1:zY/1DboFSjayWXzdaTAw3gCLmigBFh7vWLK6DwZ7wZU= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= diff --git a/staging/src/k8s.io/apiserver/go.mod b/staging/src/k8s.io/apiserver/go.mod index c64a9a9677dd1..aadb2324d9aba 100644 --- a/staging/src/k8s.io/apiserver/go.mod +++ b/staging/src/k8s.io/apiserver/go.mod @@ -22,7 +22,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f - github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece + github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 go.etcd.io/etcd/api/v3 v3.6.8 diff --git a/staging/src/k8s.io/apiserver/go.sum b/staging/src/k8s.io/apiserver/go.sum index 2734adbbc3662..cfa18cfff13d0 100644 --- a/staging/src/k8s.io/apiserver/go.sum +++ b/staging/src/k8s.io/apiserver/go.sum @@ -191,11 +191,11 @@ github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6u github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= +github.com/openshift/api v0.0.0-20260723163829-0f2bcae5eb15/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec/go.mod h1:iMHec0APKVjOH8GfL/RxddX8DuiuSvPlRe+s7KDqlyA= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece h1:Uec2loy7Mvq2ngzFqiJyEJkQn/ZMsDL8Z92iCMZgqxE= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 h1:zY/1DboFSjayWXzdaTAw3gCLmigBFh7vWLK6DwZ7wZU= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= diff --git a/staging/src/k8s.io/cloud-provider/go.mod b/staging/src/k8s.io/cloud-provider/go.mod index 9986b0e9497b6..be54a451285b8 100644 --- a/staging/src/k8s.io/cloud-provider/go.mod +++ b/staging/src/k8s.io/cloud-provider/go.mod @@ -71,7 +71,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece // indirect + github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect diff --git a/staging/src/k8s.io/cloud-provider/go.sum b/staging/src/k8s.io/cloud-provider/go.sum index f3ca0ecfbd11f..86f30cf4f0b85 100644 --- a/staging/src/k8s.io/cloud-provider/go.sum +++ b/staging/src/k8s.io/cloud-provider/go.sum @@ -184,11 +184,11 @@ github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6u github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= +github.com/openshift/api v0.0.0-20260723163829-0f2bcae5eb15/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec/go.mod h1:iMHec0APKVjOH8GfL/RxddX8DuiuSvPlRe+s7KDqlyA= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece h1:Uec2loy7Mvq2ngzFqiJyEJkQn/ZMsDL8Z92iCMZgqxE= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 h1:zY/1DboFSjayWXzdaTAw3gCLmigBFh7vWLK6DwZ7wZU= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= diff --git a/staging/src/k8s.io/code-generator/examples/go.mod b/staging/src/k8s.io/code-generator/examples/go.mod index b8051ed206776..958cc4e6d57dd 100644 --- a/staging/src/k8s.io/code-generator/examples/go.mod +++ b/staging/src/k8s.io/code-generator/examples/go.mod @@ -10,7 +10,7 @@ require ( k8s.io/api v0.0.0 k8s.io/apimachinery v0.0.0 k8s.io/client-go v0.0.0 - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a + k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 sigs.k8s.io/structured-merge-diff/v6 v6.3.3 ) @@ -21,12 +21,21 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -34,18 +43,17 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.49.0 // indirect + golang.org/x/net v0.55.1-0.20260602153038-42abb857022c // indirect golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect - golang.org/x/time v0.14.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/time v0.15.0 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect + k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/staging/src/k8s.io/controller-manager/go.sum b/staging/src/k8s.io/controller-manager/go.sum index 3ed9ec6ea253a..38b1bd1277754 100644 --- a/staging/src/k8s.io/controller-manager/go.sum +++ b/staging/src/k8s.io/controller-manager/go.sum @@ -154,7 +154,7 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/staging/src/k8s.io/dynamic-resource-allocation/go.sum b/staging/src/k8s.io/dynamic-resource-allocation/go.sum index aa1ea686bab7e..1ff506d0b1627 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/go.sum +++ b/staging/src/k8s.io/dynamic-resource-allocation/go.sum @@ -137,7 +137,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20260424201627-4d4cc33d669d h1:t+XyaZL4LpQx/AY2SETlMCQPLc9vd05ZZ7WXvD9doME= github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20260424201627-4d4cc33d669d/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= diff --git a/staging/src/k8s.io/kube-aggregator/go.mod b/staging/src/k8s.io/kube-aggregator/go.mod index 5c5b0cfeee2cf..e7358b5c49896 100644 --- a/staging/src/k8s.io/kube-aggregator/go.mod +++ b/staging/src/k8s.io/kube-aggregator/go.mod @@ -77,7 +77,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece // indirect + github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect diff --git a/staging/src/k8s.io/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index f5f4d7344d7e5..078c42bd139ce 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -183,11 +183,11 @@ github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6u github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= +github.com/openshift/api v0.0.0-20260723163829-0f2bcae5eb15/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec/go.mod h1:iMHec0APKVjOH8GfL/RxddX8DuiuSvPlRe+s7KDqlyA= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece h1:Uec2loy7Mvq2ngzFqiJyEJkQn/ZMsDL8Z92iCMZgqxE= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 h1:zY/1DboFSjayWXzdaTAw3gCLmigBFh7vWLK6DwZ7wZU= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= diff --git a/staging/src/k8s.io/kube-controller-manager/go.sum b/staging/src/k8s.io/kube-controller-manager/go.sum index fbec2a9d5f031..8fb50190d77ee 100644 --- a/staging/src/k8s.io/kube-controller-manager/go.sum +++ b/staging/src/k8s.io/kube-controller-manager/go.sum @@ -68,7 +68,7 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/staging/src/k8s.io/kube-scheduler/go.sum b/staging/src/k8s.io/kube-scheduler/go.sum index 60473cc087873..11cbc7098b553 100644 --- a/staging/src/k8s.io/kube-scheduler/go.sum +++ b/staging/src/k8s.io/kube-scheduler/go.sum @@ -121,7 +121,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/staging/src/k8s.io/pod-security-admission/go.mod b/staging/src/k8s.io/pod-security-admission/go.mod index 301ce368f392c..17b928123a757 100644 --- a/staging/src/k8s.io/pod-security-admission/go.mod +++ b/staging/src/k8s.io/pod-security-admission/go.mod @@ -67,7 +67,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece // indirect + github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect diff --git a/staging/src/k8s.io/pod-security-admission/go.sum b/staging/src/k8s.io/pod-security-admission/go.sum index c1271c8e8c2e1..d82af3cfb5427 100644 --- a/staging/src/k8s.io/pod-security-admission/go.sum +++ b/staging/src/k8s.io/pod-security-admission/go.sum @@ -180,11 +180,11 @@ github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6u github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= +github.com/openshift/api v0.0.0-20260723163829-0f2bcae5eb15/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec/go.mod h1:iMHec0APKVjOH8GfL/RxddX8DuiuSvPlRe+s7KDqlyA= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece h1:Uec2loy7Mvq2ngzFqiJyEJkQn/ZMsDL8Z92iCMZgqxE= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 h1:zY/1DboFSjayWXzdaTAw3gCLmigBFh7vWLK6DwZ7wZU= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= diff --git a/staging/src/k8s.io/sample-apiserver/go.mod b/staging/src/k8s.io/sample-apiserver/go.mod index e1bba13882f0c..66a82fdc6fc8d 100644 --- a/staging/src/k8s.io/sample-apiserver/go.mod +++ b/staging/src/k8s.io/sample-apiserver/go.mod @@ -66,7 +66,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece // indirect + github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect diff --git a/staging/src/k8s.io/sample-apiserver/go.sum b/staging/src/k8s.io/sample-apiserver/go.sum index b442bae7bc235..9602441d25f3a 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -180,11 +180,11 @@ github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6u github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= -github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= +github.com/openshift/api v0.0.0-20260723163829-0f2bcae5eb15/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= -github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec/go.mod h1:iMHec0APKVjOH8GfL/RxddX8DuiuSvPlRe+s7KDqlyA= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece h1:Uec2loy7Mvq2ngzFqiJyEJkQn/ZMsDL8Z92iCMZgqxE= -github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece/go.mod h1:iWcB6wgeOhsByZAZGhmzBtEnrLQzABL0s3aeou8AmSI= +github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 h1:zY/1DboFSjayWXzdaTAw3gCLmigBFh7vWLK6DwZ7wZU= +github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= diff --git a/staging/src/k8s.io/sample-controller/go.mod b/staging/src/k8s.io/sample-controller/go.mod index 2bf8943c90026..862d65a5cc121 100644 --- a/staging/src/k8s.io/sample-controller/go.mod +++ b/staging/src/k8s.io/sample-controller/go.mod @@ -7,14 +7,14 @@ go 1.26.0 godebug default=go1.26 require ( - golang.org/x/time v0.14.0 + golang.org/x/time v0.15.0 k8s.io/api v0.0.0 k8s.io/apimachinery v0.0.0 k8s.io/client-go v0.0.0 k8s.io/code-generator v0.0.0 k8s.io/klog/v2 v2.140.0 - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a - k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 + k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 + k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 sigs.k8s.io/structured-merge-diff/v6 v6.3.3 ) @@ -25,32 +25,40 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/spf13/pflag v1.0.9 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.32.0 // indirect - golang.org/x/net v0.49.0 // indirect + golang.org/x/mod v0.35.0 // indirect + golang.org/x/net v0.55.1-0.20260602153038-42abb857022c // indirect golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect - golang.org/x/tools v0.41.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/tools v0.44.0 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go index 5d9f10374eb73..86c98664df9a3 100644 --- a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go +++ b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go @@ -210,6 +210,21 @@ const ( DNSRecordsTypeInternal DNSRecordsType = "Internal" ) +// VIPManagementType defines which mechanism manages the API and Ingress +// VIPs on an on-premise cluster. +// +kubebuilder:validation:Enum=Keepalived;BGP +// +enum +type VIPManagementType string + +const ( + // VIPManagementTypeKeepalived means the VIPs are managed by the default + // keepalived/VRRP mechanism. + VIPManagementTypeKeepalived VIPManagementType = "Keepalived" + // VIPManagementTypeBGP means the VIPs are advertised via BGP by kube-vip + // (Routing Table Mode) and frr-k8s running as static pods. + VIPManagementTypeBGP VIPManagementType = "BGP" +) + // PlatformType is a specific supported infrastructure provider. // +kubebuilder:validation:Enum="";AWS;Azure;BareMetal;GCP;Libvirt;OpenStack;None;VSphere;oVirt;IBMCloud;KubeVirt;EquinixMetal;PowerVS;AlibabaCloud;Nutanix;External type PlatformType string @@ -1074,6 +1089,21 @@ type BareMetalPlatformStatus struct { // +optional LoadBalancer *BareMetalPlatformLoadBalancer `json:"loadBalancer,omitempty"` + // vipManagement indicates which VIP management mechanism is active + // on this cluster. + // Allowed values are `Keepalived`, `BGP`, and omitted. + // Once set to a non-empty value, this field is immutable. + // When set to `BGP`, kube-vip (Routing Table Mode) and frr-k8s are + // deployed as static pods to advertise VIPs via BGP, replacing the + // default keepalived/VRRP mechanism. + // When set to `Keepalived`, the default keepalived-based VIP + // management is used. + // When omitted, the default keepalived-based VIP management is used. + // +kubebuilder:validation:XValidation:rule="oldSelf == '' || self == oldSelf",message="vipManagement is immutable once set" + // +openshift:enable:FeatureGate=BGPBasedVIPManagement + // +optional + VIPManagement VIPManagementType `json:"vipManagement,omitempty"` + // dnsRecordsType determines whether records for api, api-int, and ingress // are provided by the internal DNS service or externally. // Allowed values are `Internal`, `External`, and omitted. diff --git a/vendor/github.com/openshift/api/config/v1/types_kmsencryption.go b/vendor/github.com/openshift/api/config/v1/types_kmsencryption.go index 6b58d9da49bae..0430a25cc3004 100644 --- a/vendor/github.com/openshift/api/config/v1/types_kmsencryption.go +++ b/vendor/github.com/openshift/api/config/v1/types_kmsencryption.go @@ -181,6 +181,23 @@ type VaultKMSPluginConfig struct { // +optional VaultNamespace string `json:"vaultNamespace,omitempty"` + // vaultAuthNamespace specifies the Vault namespace to use for authentication. + // This is only applicable for Vault Enterprise installations where authentication + // and Transit operations may be in different namespaces. + // When this field is not set, the value of vaultNamespace is used for both + // authentication and Transit key operations. + // + // The value must be between 1 and 4096 characters. + // The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=4096 + // +kubebuilder:validation:XValidation:rule="!self.endsWith('/')",message="vaultAuthNamespace cannot end with a forward slash" + // +kubebuilder:validation:XValidation:rule="!self.contains(' ')",message="vaultAuthNamespace cannot contain spaces" + // +kubebuilder:validation:XValidation:rule="!(self in ['root', 'sys', 'audit', 'auth', 'cubbyhole', 'identity'])",message="vaultAuthNamespace cannot be a reserved string (root, sys, audit, auth, cubbyhole, identity)" + // +optional + VaultAuthNamespace string `json:"vaultAuthNamespace,omitempty"` + // tls contains the TLS configuration for connecting to the Vault server. // When this field is not set, system default TLS settings are used. // +optional @@ -191,7 +208,32 @@ type VaultKMSPluginConfig struct { // +required Authentication VaultAuthentication `json:"authentication,omitzero"` + // vaultKeyPath specifies the full path to the encryption key in Vault's Transit secrets engine, + // combining the Transit engine mount path and the key name separated by "/keys/". + // Format: /keys/ (e.g., transit/keys/my-key, myteam/transit/keys/production-key). + // + // The total path length must be between 8 and 1542 characters. + // The path cannot start or end with a forward slash, cannot contain consecutive forward slashes, + // must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, period, underscore, tilde) + // and forward slashes as path separators, and must not contain "." or ".." path segments. + // The key name must start and end with an alphanumeric character or underscore, and may contain + // alphanumeric characters, underscores, hyphens, and periods in the middle. + // + // +kubebuilder:validation:MinLength=8 + // +kubebuilder:validation:MaxLength=1542 + // +kubebuilder:validation:XValidation:rule="!self.startsWith('/')",message="vaultKeyPath cannot start with a forward slash" + // +kubebuilder:validation:XValidation:rule="!self.endsWith('/')",message="vaultKeyPath cannot end with a forward slash" + // +kubebuilder:validation:XValidation:rule="!self.contains('//')",message="vaultKeyPath cannot contain consecutive forward slashes" + // +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._~/-]+$')",message="vaultKeyPath must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, period, underscore, tilde) and forward slashes" + // +kubebuilder:validation:XValidation:rule="self.split('/').filter(s, s == '.' || s == '..').size() == 0",message="vaultKeyPath must not contain '.' or '..' path segments" + // +kubebuilder:validation:XValidation:rule=`self.matches('^[a-zA-Z0-9._~-]+(/[a-zA-Z0-9._~-]+)*/keys/[a-zA-Z0-9_]([a-zA-Z0-9_.-]*[a-zA-Z0-9_])?$')`,message="vaultKeyPath must follow the format /keys/ where the key name starts and ends with an alphanumeric character or underscore and may contain alphanumeric characters, underscores, hyphens, and periods" + // +required + VaultKeyPath string `json:"vaultKeyPath,omitempty"` + + // --- TOMBSTONE --- // transitMount specifies the mount path of the Vault Transit engine. + // It has been replaced by vaultKeyPath which combines the mount and key into a single path. + // The field name is reserved to prevent reuse. // // The transit mount must be between 1 and 1024 characters, cannot start or // end with a forward slash, cannot contain consecutive forward slashes, and @@ -205,10 +247,13 @@ type VaultKMSPluginConfig struct { // +kubebuilder:validation:XValidation:rule="!self.contains('//')",message="transitMount cannot contain consecutive forward slashes" // +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._~/-]+$')",message="transitMount must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, period, underscore, tilde) and forward slashes" // +required - TransitMount string `json:"transitMount,omitempty"` + // TransitMount string `json:"transitMount,omitempty"` + // --- TOMBSTONE --- // transitKey specifies the name of the encryption key in Vault's Transit engine. // This key is used to encrypt and decrypt data. + // It has been replaced by vaultKeyPath which combines the mount and key into a single path. + // The field name is reserved to prevent reuse. // // The transit key must be between 1 and 512 characters, cannot contain forward slashes, // and must only contain alphanumeric characters, hyphens, periods, and underscores. @@ -218,7 +263,7 @@ type VaultKMSPluginConfig struct { // +kubebuilder:validation:XValidation:rule="!self.contains('/')",message="transitKey cannot contain forward slashes" // +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._-]+$')",message="transitKey must only contain alphanumeric characters, hyphens, periods, and underscores" // +required - TransitKey string `json:"transitKey,omitempty"` + // TransitKey string `json:"transitKey,omitempty"` } // VaultTLSConfig contains TLS configuration for connecting to Vault. diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml index 76f78df82d1db..7707626383f24 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml @@ -397,6 +397,7 @@ infrastructures.config.openshift.io: - AWSClusterHostedDNSInstall - AWSDualStackInstall - AzureDualStackInstall + - BGPBasedVIPManagement - DualReplica - DyanmicServiceEndpointIBMCloud - MutableTopology diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go index 631f11a1b2926..b763c1b5313d5 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go @@ -1698,6 +1698,7 @@ var map_BareMetalPlatformStatus = map[string]string{ "ingressIPs": "ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one.", "nodeDNSIP": "nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for BareMetal deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster.", "loadBalancer": "loadBalancer defines how the load balancer used by the cluster is configured.", + "vipManagement": "vipManagement indicates which VIP management mechanism is active on this cluster. Allowed values are `Keepalived`, `BGP`, and omitted. Once set to a non-empty value, this field is immutable. When set to `BGP`, kube-vip (Routing Table Mode) and frr-k8s are deployed as static pods to advertise VIPs via BGP, replacing the default keepalived/VRRP mechanism. When set to `Keepalived`, the default keepalived-based VIP management is used. When omitted, the default keepalived-based VIP management is used.", "dnsRecordsType": "dnsRecordsType determines whether records for api, api-int, and ingress are provided by the internal DNS service or externally. Allowed values are `Internal`, `External`, and omitted. When set to `Internal`, records are provided by the internal infrastructure and no additional user configuration is required for the cluster to function. When set to `External`, records are not provided by the internal infrastructure and must be configured by the user on a DNS server outside the cluster. Cluster nodes must use this external server for their upstream DNS requests. This value may only be set when loadBalancer.type is set to UserManaged. When omitted, this means the user has no opinion and the platform is left to choose reasonable defaults. These defaults are subject to change over time. The current default is `Internal`.", "machineNetworks": "machineNetworks are IP networks used to connect all the OpenShift cluster nodes.", } @@ -2501,14 +2502,14 @@ func (VaultConfigMapReference) SwaggerDoc() map[string]string { } var map_VaultKMSPluginConfig = map[string]string{ - "": "VaultKMSPluginConfig defines the KMS plugin configuration specific to Vault KMS", - "kmsPluginImage": "kmsPluginImage specifies the container image for the HashiCorp Vault KMS plugin.\n\nThe image must be a fully qualified OCI image pull spec with a SHA256 digest. The format is: host[:port][/namespace]/name@sha256: where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. The total length must be between 75 and 447 characters.\n\nShort names (e.g., \"vault-plugin\" or \"hashicorp/vault-plugin\") are not allowed. The registry hostname must be included and must contain at least one dot. Image tags (e.g., \":latest\", \":v1.0.0\") are not allowed.\n\nConsult the OpenShift documentation for compatible plugin versions with your cluster version, then obtain the image digest for that version from HashiCorp's container registry.\n\nFor disconnected environments, mirror the plugin image to an accessible registry and reference the mirrored location with its digest.", - "vaultAddress": "vaultAddress specifies the address of the HashiCorp Vault instance. The value must be a valid HTTPS URL containing only scheme, host, and optional port. Paths, user info, query parameters, and fragments are not allowed.\n\nFormat: https://hostname[:port] Example: https://vault.example.com:8200\n\nThe value must be between 1 and 512 characters.", - "vaultNamespace": "vaultNamespace specifies the Vault namespace where the Transit secrets engine is mounted. This is only applicable for Vault Enterprise installations. When this field is not set, no namespace is used.\n\nThe value must be between 1 and 4096 characters. The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity.", - "tls": "tls contains the TLS configuration for connecting to the Vault server. When this field is not set, system default TLS settings are used.", - "authentication": "authentication defines the authentication method used to authenticate with Vault.", - "transitMount": "transitMount specifies the mount path of the Vault Transit engine.\n\nThe transit mount must be between 1 and 1024 characters, cannot start or end with a forward slash, cannot contain consecutive forward slashes, and must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, period, underscore, tilde) and forward slashes as path separators.", - "transitKey": "transitKey specifies the name of the encryption key in Vault's Transit engine. This key is used to encrypt and decrypt data.\n\nThe transit key must be between 1 and 512 characters, cannot contain forward slashes, and must only contain alphanumeric characters, hyphens, periods, and underscores.", + "": "VaultKMSPluginConfig defines the KMS plugin configuration specific to Vault KMS", + "kmsPluginImage": "kmsPluginImage specifies the container image for the HashiCorp Vault KMS plugin.\n\nThe image must be a fully qualified OCI image pull spec with a SHA256 digest. The format is: host[:port][/namespace]/name@sha256: where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. The total length must be between 75 and 447 characters.\n\nShort names (e.g., \"vault-plugin\" or \"hashicorp/vault-plugin\") are not allowed. The registry hostname must be included and must contain at least one dot. Image tags (e.g., \":latest\", \":v1.0.0\") are not allowed.\n\nConsult the OpenShift documentation for compatible plugin versions with your cluster version, then obtain the image digest for that version from HashiCorp's container registry.\n\nFor disconnected environments, mirror the plugin image to an accessible registry and reference the mirrored location with its digest.", + "vaultAddress": "vaultAddress specifies the address of the HashiCorp Vault instance. The value must be a valid HTTPS URL containing only scheme, host, and optional port. Paths, user info, query parameters, and fragments are not allowed.\n\nFormat: https://hostname[:port] Example: https://vault.example.com:8200\n\nThe value must be between 1 and 512 characters.", + "vaultNamespace": "vaultNamespace specifies the Vault namespace where the Transit secrets engine is mounted. This is only applicable for Vault Enterprise installations. When this field is not set, no namespace is used.\n\nThe value must be between 1 and 4096 characters. The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity.", + "vaultAuthNamespace": "vaultAuthNamespace specifies the Vault namespace to use for authentication. This is only applicable for Vault Enterprise installations where authentication and Transit operations may be in different namespaces. When this field is not set, the value of vaultNamespace is used for both authentication and Transit key operations.\n\nThe value must be between 1 and 4096 characters. The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity.", + "tls": "tls contains the TLS configuration for connecting to the Vault server. When this field is not set, system default TLS settings are used.", + "authentication": "authentication defines the authentication method used to authenticate with Vault.", + "vaultKeyPath": "vaultKeyPath specifies the full path to the encryption key in Vault's Transit secrets engine, combining the Transit engine mount path and the key name separated by \"/keys/\". Format: /keys/ (e.g., transit/keys/my-key, myteam/transit/keys/production-key).\n\nThe total path length must be between 8 and 1542 characters. The path cannot start or end with a forward slash, cannot contain consecutive forward slashes, must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, period, underscore, tilde) and forward slashes as path separators, and must not contain \".\" or \"..\" path segments. The key name must start and end with an alphanumeric character or underscore, and may contain alphanumeric characters, underscores, hyphens, and periods in the middle.", } func (VaultKMSPluginConfig) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/features/features.go b/vendor/github.com/openshift/api/features/features.go index b45bef7705634..afdcef92b405d 100644 --- a/vendor/github.com/openshift/api/features/features.go +++ b/vendor/github.com/openshift/api/features/features.go @@ -469,7 +469,7 @@ var ( contactPerson("joelanford"). productScope(ocpSpecific). enhancementPR("https://github.com/openshift/enhancements/pull/1991"). - enable(inClusterProfile(SelfManaged), inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). + enable(inDefault(), inOKD(), inClusterProfile(SelfManaged), inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). mustRegister() FeatureGateInsightsOnDemandDataGather = newFeatureGate("InsightsOnDemandDataGather"). @@ -663,7 +663,7 @@ var ( contactPerson("miciah"). productScope(ocpSpecific). enhancementPR("https://github.com/openshift/enhancements/pull/1687"). - enable(inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()). + enable(inDefault(), inOKD(), inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()). mustRegister() FeatureGateIngressComponentRouteLabels = newFeatureGate("IngressComponentRouteLabels"). @@ -888,6 +888,14 @@ var ( enable(inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). mustRegister() + FeatureGateGCPSovereignCloudInstall = newFeatureGate("GCPSovereignCloudInstall"). + reportProblemsToJiraComponent("Installer"). + contactPerson("barbacbd"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1977"). + enable(inDevPreviewNoUpgrade()). + mustRegister() + FeatureCBORServingAndStorage = newFeatureGate("CBORServingAndStorage"). reportProblemsToJiraComponent("kube-apiserver"). contactPerson("benluddy"). @@ -950,6 +958,14 @@ var ( enable(inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). mustRegister() + FeatureGateBGPBasedVIPManagement = newFeatureGate("BGPBasedVIPManagement"). + reportProblemsToJiraComponent("Networking / On-Prem Networking"). + contactPerson("mkowalski"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1982"). + enable(inDevPreviewNoUpgrade()). + mustRegister() + FeatureGateProvisioningRequestAvailable = newFeatureGate("ProvisioningRequestAvailable"). reportProblemsToJiraComponent("Cluster Autoscaler"). contactPerson("elmiko"). diff --git a/vendor/github.com/openshift/api/operator/v1/types.go b/vendor/github.com/openshift/api/operator/v1/types.go index 3a2141abb98fc..599ceb03e1081 100644 --- a/vendor/github.com/openshift/api/operator/v1/types.go +++ b/vendor/github.com/openshift/api/operator/v1/types.go @@ -266,6 +266,18 @@ type NodeStatus struct { // +required NodeName string `json:"nodeName"` + // nodeUID is the UID of the node. + // This field is used to detect that a node has been deleted and recreated + // with the same name. When the UID changes, it indicates the node is a + // new instance and the controller should treat this status entry as stale. + // When omitted, UID-based node replacement detection is not available + // for this entry. + // +kubebuilder:validation:MinLength=36 + // +kubebuilder:validation:MaxLength=36 + // +kubebuilder:validation:Format=uuid + // +optional + NodeUID string `json:"nodeUID,omitempty"` + // currentRevision is the generation of the most recently successful deployment. // Can not be set on creation of a nodeStatus. Updates must only increase the value. // +kubebuilder:validation:XValidation:rule="self >= oldSelf",message="must only increase" diff --git a/vendor/github.com/openshift/api/operator/v1/types_kmsencryption.go b/vendor/github.com/openshift/api/operator/v1/types_kmsencryption.go index a5dcf7d334e61..e8c4b1c6f7660 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_kmsencryption.go +++ b/vendor/github.com/openshift/api/operator/v1/types_kmsencryption.go @@ -77,4 +77,74 @@ type KMSEncryptionStatus struct { // +listMapKey=nodeName // +listMapKey=keyId HealthReports []KMSPluginHealthReport `json:"healthReports,omitempty"` + + // preflight contains the state of KMS preflight validation for this operator. + // The preflight validates the KMS provider configuration before it is used + // to create a new encryption key, catching configuration issues early such + // as incorrect login credentials or an unreachable Vault service. + // When omitted, no preflight validation is in progress. + // +optional + Preflight KMSPreflightCheck `json:"preflight,omitzero"` +} + +// KMSPreflightCheck describes a preflight validation request and its result. +// +// +kubebuilder:validation:MinProperties=1 +type KMSPreflightCheck struct { + // observedConfigHash is a hash of the KMS provider configuration and + // its referenced resources that has been observed and requires preflight + // validation before a new encryption key can be created. + // The value must be exactly 8 characters. + // +kubebuilder:validation:MinLength=8 + // +kubebuilder:validation:MaxLength=8 + // +kubebuilder:validation:XValidation:rule="self.matches('^[A-Za-z0-9_-]*={0,2}$')",message="must be a valid base64url encoded value" + // +required + ObservedConfigHash string `json:"observedConfigHash,omitempty"` + + // result contains the outcome of the most recent preflight check. + // Preflight is considered passed when result.status is Succeeded and + // result.configHash matches observedConfigHash. + // When omitted, no preflight check result has been reported yet. + // +optional + Result KMSPreflightResult `json:"result,omitzero"` +} + +// +kubebuilder:validation:Enum=Succeeded;Failed +type KMSPreflightResultStatus string + +const ( + KMSPreflightResultSucceeded KMSPreflightResultStatus = "Succeeded" + + KMSPreflightResultFailed KMSPreflightResultStatus = "Failed" +) + +// KMSPreflightResult contains the outcome of a preflight validation. +// +// +openshift:compatibility-gen:level=1 +type KMSPreflightResult struct { + // status indicates the outcome of the preflight check. + // Succeeded means the KMS plugin responded to Status, Encrypt, and + // Decrypt calls successfully. + // Failed means the validation did not pass. + // +required + Status KMSPreflightResultStatus `json:"status,omitempty"` + + // configHash is the hash of the configuration that was validated. + // This is compared against observedConfigHash to confirm the result + // corresponds to the current configuration. + // The value must be exactly 8 characters. + // +kubebuilder:validation:MinLength=8 + // +kubebuilder:validation:MaxLength=8 + // +kubebuilder:validation:XValidation:rule="self.matches('^[A-Za-z0-9_-]*={0,2}$')",message="must be a valid base64url encoded value" + // +required + ConfigHash string `json:"configHash,omitempty"` + + // remoteKeyID is the remote key encryption key identifier from KMS v2 + // StatusResponse.key_id. This is not a cryptographic key, but a unique + // representation of the remote key used to encrypt data. + // The value must be between 1 and 1024 characters. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=1024 + // +required + RemoteKeyID string `json:"remoteKeyID,omitempty"` } diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go index 3c244a9867ea9..8f7441b6c7c74 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go @@ -2815,6 +2815,7 @@ func (in *KMSEncryptionStatus) DeepCopyInto(out *KMSEncryptionStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + out.Preflight = in.Preflight return } @@ -2845,6 +2846,39 @@ func (in *KMSPluginHealthReport) DeepCopy() *KMSPluginHealthReport { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPreflightCheck) DeepCopyInto(out *KMSPreflightCheck) { + *out = *in + out.Result = in.Result + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPreflightCheck. +func (in *KMSPreflightCheck) DeepCopy() *KMSPreflightCheck { + if in == nil { + return nil + } + out := new(KMSPreflightCheck) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPreflightResult) DeepCopyInto(out *KMSPreflightResult) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPreflightResult. +func (in *KMSPreflightResult) DeepCopy() *KMSPreflightResult { + if in == nil { + return nil + } + out := new(KMSPreflightResult) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubeAPIServer) DeepCopyInto(out *KubeAPIServer) { *out = *in diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go index 271665a7ecab3..13ab0c5f6f291 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go @@ -625,6 +625,16 @@ func (in KMSPluginHealthReport) OpenAPIModelName() string { return "com.github.openshift.api.operator.v1.KMSPluginHealthReport" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPreflightCheck) OpenAPIModelName() string { + return "com.github.openshift.api.operator.v1.KMSPreflightCheck" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPreflightResult) OpenAPIModelName() string { + return "com.github.openshift.api.operator.v1.KMSPreflightResult" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in KubeAPIServer) OpenAPIModelName() string { return "com.github.openshift.api.operator.v1.KubeAPIServer" diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go index 114b5c7a689b7..2b07b6859d657 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go @@ -37,6 +37,7 @@ func (MyOperatorResource) SwaggerDoc() map[string]string { var map_NodeStatus = map[string]string{ "": "NodeStatus provides information about the current state of a particular node managed by this operator.", "nodeName": "nodeName is the name of the node", + "nodeUID": "nodeUID is the UID of the node. This field is used to detect that a node has been deleted and recreated with the same name. When the UID changes, it indicates the node is a new instance and the controller should treat this status entry as stale. When omitted, UID-based node replacement detection is not available for this entry.", "currentRevision": "currentRevision is the generation of the most recently successful deployment. Can not be set on creation of a nodeStatus. Updates must only increase the value.", "targetRevision": "targetRevision is the generation of the deployment we're trying to apply. Can not be set on creation of a nodeStatus.", "lastFailedRevision": "lastFailedRevision is the generation of the deployment we tried and failed to deploy.", @@ -1390,6 +1391,7 @@ func (InsightsReport) SwaggerDoc() map[string]string { var map_KMSEncryptionStatus = map[string]string{ "healthReports": "healthReports contains all KMS plugin health reports. When omitted, no health reports are available. Each entry must have a unique combination of nodeName and keyId.", + "preflight": "preflight contains the state of KMS preflight validation for this operator. The preflight validates the KMS provider configuration before it is used to create a new encryption key, catching configuration issues early such as incorrect login credentials or an unreachable Vault service. When omitted, no preflight validation is in progress.", } func (KMSEncryptionStatus) SwaggerDoc() map[string]string { @@ -1409,6 +1411,27 @@ func (KMSPluginHealthReport) SwaggerDoc() map[string]string { return map_KMSPluginHealthReport } +var map_KMSPreflightCheck = map[string]string{ + "": "KMSPreflightCheck describes a preflight validation request and its result.", + "observedConfigHash": "observedConfigHash is a hash of the KMS provider configuration and its referenced resources that has been observed and requires preflight validation before a new encryption key can be created. The value must be exactly 8 characters.", + "result": "result contains the outcome of the most recent preflight check. Preflight is considered passed when result.status is Succeeded and result.configHash matches observedConfigHash. When omitted, no preflight check result has been reported yet.", +} + +func (KMSPreflightCheck) SwaggerDoc() map[string]string { + return map_KMSPreflightCheck +} + +var map_KMSPreflightResult = map[string]string{ + "": "KMSPreflightResult contains the outcome of a preflight validation.", + "status": "status indicates the outcome of the preflight check. Succeeded means the KMS plugin responded to Status, Encrypt, and Decrypt calls successfully. Failed means the validation did not pass.", + "configHash": "configHash is the hash of the configuration that was validated. This is compared against observedConfigHash to confirm the result corresponds to the current configuration. The value must be exactly 8 characters.", + "remoteKeyID": "remoteKeyID is the remote key encryption key identifier from KMS v2 StatusResponse.key_id. This is not a cryptographic key, but a unique representation of the remote key used to encrypt data. The value must be between 1 and 1024 characters.", +} + +func (KMSPreflightResult) SwaggerDoc() map[string]string { + return map_KMSPreflightResult +} + var map_KubeAPIServer = map[string]string{ "": "KubeAPIServer provides information to configure an operator to manage kube-apiserver.\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "metadata": "metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", diff --git a/vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1/vaultkmspluginconfig.go b/vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1/vaultkmspluginconfig.go index 736095a27d5c9..235cecb93943b 100644 --- a/vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1/vaultkmspluginconfig.go +++ b/vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1/vaultkmspluginconfig.go @@ -40,24 +40,31 @@ type VaultKMSPluginConfigApplyConfiguration struct { // The value must be between 1 and 4096 characters. // The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity. VaultNamespace *string `json:"vaultNamespace,omitempty"` + // vaultAuthNamespace specifies the Vault namespace to use for authentication. + // This is only applicable for Vault Enterprise installations where authentication + // and Transit operations may be in different namespaces. + // When this field is not set, the value of vaultNamespace is used for both + // authentication and Transit key operations. + // + // The value must be between 1 and 4096 characters. + // The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity. + VaultAuthNamespace *string `json:"vaultAuthNamespace,omitempty"` // tls contains the TLS configuration for connecting to the Vault server. // When this field is not set, system default TLS settings are used. TLS *VaultTLSConfigApplyConfiguration `json:"tls,omitempty"` // authentication defines the authentication method used to authenticate with Vault. Authentication *VaultAuthenticationApplyConfiguration `json:"authentication,omitempty"` - // transitMount specifies the mount path of the Vault Transit engine. + // vaultKeyPath specifies the full path to the encryption key in Vault's Transit secrets engine, + // combining the Transit engine mount path and the key name separated by "/keys/". + // Format: /keys/ (e.g., transit/keys/my-key, myteam/transit/keys/production-key). // - // The transit mount must be between 1 and 1024 characters, cannot start or - // end with a forward slash, cannot contain consecutive forward slashes, and - // must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, - // period, underscore, tilde) and forward slashes as path separators. - TransitMount *string `json:"transitMount,omitempty"` - // transitKey specifies the name of the encryption key in Vault's Transit engine. - // This key is used to encrypt and decrypt data. - // - // The transit key must be between 1 and 512 characters, cannot contain forward slashes, - // and must only contain alphanumeric characters, hyphens, periods, and underscores. - TransitKey *string `json:"transitKey,omitempty"` + // The total path length must be between 8 and 1542 characters. + // The path cannot start or end with a forward slash, cannot contain consecutive forward slashes, + // must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, period, underscore, tilde) + // and forward slashes as path separators, and must not contain "." or ".." path segments. + // The key name must start and end with an alphanumeric character or underscore, and may contain + // alphanumeric characters, underscores, hyphens, and periods in the middle. + VaultKeyPath *string `json:"vaultKeyPath,omitempty"` } // VaultKMSPluginConfigApplyConfiguration constructs a declarative configuration of the VaultKMSPluginConfig type for use with @@ -90,6 +97,14 @@ func (b *VaultKMSPluginConfigApplyConfiguration) WithVaultNamespace(value string return b } +// WithVaultAuthNamespace sets the VaultAuthNamespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the VaultAuthNamespace field is set to the value of the last call. +func (b *VaultKMSPluginConfigApplyConfiguration) WithVaultAuthNamespace(value string) *VaultKMSPluginConfigApplyConfiguration { + b.VaultAuthNamespace = &value + return b +} + // WithTLS sets the TLS field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the TLS field is set to the value of the last call. @@ -106,18 +121,10 @@ func (b *VaultKMSPluginConfigApplyConfiguration) WithAuthentication(value *Vault return b } -// WithTransitMount sets the TransitMount field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the TransitMount field is set to the value of the last call. -func (b *VaultKMSPluginConfigApplyConfiguration) WithTransitMount(value string) *VaultKMSPluginConfigApplyConfiguration { - b.TransitMount = &value - return b -} - -// WithTransitKey sets the TransitKey field in the declarative configuration to the given value +// WithVaultKeyPath sets the VaultKeyPath field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the TransitKey field is set to the value of the last call. -func (b *VaultKMSPluginConfigApplyConfiguration) WithTransitKey(value string) *VaultKMSPluginConfigApplyConfiguration { - b.TransitKey = &value +// If called multiple times, the VaultKeyPath field is set to the value of the last call. +func (b *VaultKMSPluginConfigApplyConfiguration) WithVaultKeyPath(value string) *VaultKMSPluginConfigApplyConfiguration { + b.VaultKeyPath = &value return b } diff --git a/vendor/github.com/openshift/client-go/config/applyconfigurations/internal/internal.go b/vendor/github.com/openshift/client-go/config/applyconfigurations/internal/internal.go index d71561a0bf897..15df23abdc1b7 100644 --- a/vendor/github.com/openshift/client-go/config/applyconfigurations/internal/internal.go +++ b/vendor/github.com/openshift/client-go/config/applyconfigurations/internal/internal.go @@ -4344,13 +4344,13 @@ var schemaYAML = typed.YAMLObject(`types: type: namedType: com.github.openshift.api.config.v1.VaultTLSConfig default: {} - - name: transitKey + - name: vaultAddress type: scalar: string - - name: transitMount + - name: vaultAuthNamespace type: scalar: string - - name: vaultAddress + - name: vaultKeyPath type: scalar: string - name: vaultNamespace diff --git a/vendor/modules.txt b/vendor/modules.txt index 2d27d4f8c97fe..74cba77cd56b4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -544,7 +544,7 @@ github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo github.com/openshift-eng/openshift-tests-extension/pkg/junit github.com/openshift-eng/openshift-tests-extension/pkg/util/sets github.com/openshift-eng/openshift-tests-extension/pkg/version -# github.com/openshift/api v0.0.0-20260715165912-72066cc9718b +# github.com/openshift/api v0.0.0-20260726224011-9bcaa16cb258 ## explicit; go 1.26.0 github.com/openshift/api/apiserver/v1 github.com/openshift/api/apps/v1 @@ -592,7 +592,7 @@ github.com/openshift/apiserver-library-go/pkg/securitycontextconstraints/sysctl github.com/openshift/apiserver-library-go/pkg/securitycontextconstraints/user github.com/openshift/apiserver-library-go/pkg/securitycontextconstraints/util github.com/openshift/apiserver-library-go/pkg/securitycontextconstraints/util/sort -# github.com/openshift/client-go v0.0.0-20260715172546-dac61734e0ec +# github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73 ## explicit; go 1.26.0 github.com/openshift/client-go/apiserver/applyconfigurations github.com/openshift/client-go/apiserver/applyconfigurations/apiserver/v1 @@ -745,7 +745,7 @@ github.com/openshift/client-go/user/informers/externalversions/internalinterface github.com/openshift/client-go/user/informers/externalversions/user github.com/openshift/client-go/user/informers/externalversions/user/v1 github.com/openshift/client-go/user/listers/user/v1 -# github.com/openshift/library-go v0.0.0-20260715193157-1a5091f58ece +# github.com/openshift/library-go v0.0.0-20260724131744-e4053a935312 ## explicit; go 1.26.0 github.com/openshift/library-go/pkg/apiserver/admission/admissionregistrationtesting github.com/openshift/library-go/pkg/apiserver/admission/admissionrestconfig