diff --git a/.golangci.yaml b/.golangci.yaml index 0290811..4ecf8b8 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -135,7 +135,7 @@ linters: # for github.com/sapcc/keppel et al - github.com/go-gorp/gorp/v3 toolchain-forbidden: true - go-version-pattern: 1\.\d+(\.0)?$ + go-version-pattern: 1\.\d+(\.\d+)?$ gosec: excludes: # gosec wants us to set a short ReadHeaderTimeout to avoid Slowloris attacks, but doing so would expose us to Keep-Alive race conditions (see https://iximiuz.com/en/posts/reverse-proxy-http-keep-alive-and-502s/ diff --git a/cloudprofilesync/imageupdater.go b/cloudprofilesync/imageupdater.go index 4f5929b..51bf07a 100644 --- a/cloudprofilesync/imageupdater.go +++ b/cloudprofilesync/imageupdater.go @@ -17,13 +17,14 @@ import ( func filterImages(log logr.Logger, versions []SourceImage) []SourceImage { filtered := make([]SourceImage, 0, len(versions)) for _, version := range versions { - _, err := semver.Parse(version.Version) + versionStr := version.effectiveVersion() + _, err := semver.Parse(versionStr) if err != nil { - log.V(1).Info("skipping invalid version", "version", version.Version) + log.V(1).Info("skipping invalid version", "version", versionStr) continue } if len(version.Architectures) == 0 { - log.V(1).Info("skipping version with no architectures", "version", version.Version) + log.V(1).Info("skipping version with no architectures", "version", versionStr) continue } filtered = append(filtered, version) @@ -32,10 +33,11 @@ func filterImages(log logr.Logger, versions []SourceImage) []SourceImage { } type ImageUpdater struct { - Log logr.Logger - Source Source - Provider Provider - ImageName string + Log logr.Logger + Source Source + Provider Provider + ImageName string + EnableCapabilities bool } func (iu *ImageUpdater) Update(ctx context.Context, cpSpec *gardenerv1beta1.CloudProfileSpec) error { @@ -48,6 +50,9 @@ func (iu *ImageUpdater) Update(ctx context.Context, cpSpec *gardenerv1beta1.Clou // in the source images may lead to a changed order in the CloudProfile, // causing unnecesscary reconciliations. slices.SortFunc(sourceImages, func(a, b SourceImage) int { + if c := cmp.Compare(a.effectiveVersion(), b.effectiveVersion()); c != 0 { + return c + } return cmp.Compare(a.Version, b.Version) }) imageIndex := slices.IndexFunc(cpSpec.MachineImages, func(img gardenerv1beta1.MachineImage) bool { @@ -62,7 +67,9 @@ func (iu *ImageUpdater) Update(ctx context.Context, cpSpec *gardenerv1beta1.Clou for idx, version := range image.Versions { existingVersions[version.Version] = idx } + for _, sourceImage := range sourceImages { + // Always write the full tag version (legacy path, safe for running Shoots). if idx, exists := existingVersions[sourceImage.Version]; exists { image.Versions[idx].Architectures = sourceImage.Architectures } else { @@ -72,8 +79,30 @@ func (iu *ImageUpdater) Update(ctx context.Context, cpSpec *gardenerv1beta1.Clou }, Architectures: sourceImage.Architectures, }) + existingVersions[sourceImage.Version] = len(image.Versions) - 1 + } + + // When capabilities are enabled, also write the clean version entry. + if iu.EnableCapabilities && sourceImage.CleanVersion != "" && sourceImage.CleanVersion != sourceImage.Version { + if idx, exists := existingVersions[sourceImage.CleanVersion]; exists { + existing := &image.Versions[idx] + for _, arch := range sourceImage.Architectures { + if !slices.Contains(existing.Architectures, arch) { + existing.Architectures = append(existing.Architectures, arch) + } + } + } else { + image.Versions = append(image.Versions, gardenerv1beta1.MachineImageVersion{ + ExpirableVersion: gardenerv1beta1.ExpirableVersion{ + Version: sourceImage.CleanVersion, + }, + Architectures: slices.Clone(sourceImage.Architectures), + }) + existingVersions[sourceImage.CleanVersion] = len(image.Versions) - 1 + } } } + if iu.Provider != nil { if err := iu.Provider.Configure(cpSpec, sourceImages); err != nil { return fmt.Errorf("failed to invoke provider: %w", err) diff --git a/cloudprofilesync/imageupdater_test.go b/cloudprofilesync/imageupdater_test.go index 5e5cf4e..5ffbb99 100644 --- a/cloudprofilesync/imageupdater_test.go +++ b/cloudprofilesync/imageupdater_test.go @@ -6,7 +6,7 @@ package cloudprofilesync_test import ( "encoding/json" - "github.com/gardener/gardener/pkg/apis/core/v1beta1" + gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" "github.com/go-logr/logr" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -16,165 +16,176 @@ import ( var _ = Describe("ImageUpdater", func() { - It("adds an image from the source to the CloudProfile spec", func(ctx SpecContext) { - mockSource.images = []cloudprofilesync.SourceImage{{Version: "1.0.0", Architectures: []string{"amd64"}}} - updater := cloudprofilesync.ImageUpdater{ - Log: logr.Discard(), - Source: &mockSource, - ImageName: "test", - } - var cpSpec v1beta1.CloudProfileSpec - Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) - Expect(cpSpec.MachineImages).To(HaveLen(1)) - Expect(cpSpec.MachineImages[0].Name).To(Equal("test")) - Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(1)) - Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1.0.0")) - Expect(cpSpec.MachineImages[0].Versions[0].Architectures).To(Equal([]string{"amd64"})) - }) + Describe("flag OFF (default behavior)", func() { + It("adds an image from the source to the CloudProfile spec", func(ctx SpecContext) { + mockSource.images = []cloudprofilesync.SourceImage{{Version: "1.0.0", Architectures: []string{"amd64"}}} + updater := cloudprofilesync.ImageUpdater{ + Log: logr.Discard(), + Source: &mockSource, + ImageName: "test", + } + var cpSpec gardencorev1beta1.CloudProfileSpec + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(1)) + Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1.0.0")) + }) + + It("adds multiple images from the source to the CloudProfile spec", func(ctx SpecContext) { + mockSource.images = []cloudprofilesync.SourceImage{ + {Version: "1.0.0", Architectures: []string{"amd64"}}, + {Version: "2.0.0", Architectures: []string{"arm64", "amd64"}}, + } + updater := cloudprofilesync.ImageUpdater{ + Log: GinkgoLogr, + Source: &mockSource, + ImageName: "test", + } + var cpSpec gardencorev1beta1.CloudProfileSpec + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages[0].Versions).To(ConsistOf([]gardencorev1beta1.MachineImageVersion{ + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "1.0.0"}, Architectures: []string{"amd64"}}, + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "2.0.0"}, Architectures: []string{"arm64", "amd64"}}, + })) + }) - It("adds multiple images from the source to the CloudProfile spec", func(ctx SpecContext) { - mockSource.images = []cloudprofilesync.SourceImage{ - {Version: "1.0.0", Architectures: []string{"amd64"}}, - {Version: "2.0.0", Architectures: []string{"arm64", "amd64"}}, - } - updater := cloudprofilesync.ImageUpdater{ - Log: GinkgoLogr, - Source: &mockSource, - ImageName: "test", - } - var cpSpec v1beta1.CloudProfileSpec - Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) - Expect(cpSpec.MachineImages).To(HaveLen(1)) - Expect(cpSpec.MachineImages[0].Name).To(Equal("test")) - Expect(cpSpec.MachineImages[0].Versions).To(ConsistOf([]v1beta1.MachineImageVersion{ - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "1.0.0", + It("updates an image from the source in the CloudProfile spec", func(ctx SpecContext) { + cpSpec := gardencorev1beta1.CloudProfileSpec{ + MachineImages: []gardencorev1beta1.MachineImage{ + {Name: "test", Versions: []gardencorev1beta1.MachineImageVersion{ + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "1.0.0"}, Architectures: []string{"amd64"}}, + }}, }, - Architectures: []string{"amd64"}, - }, - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "2.0.0", + } + mockSource.images = []cloudprofilesync.SourceImage{{Version: "2.0.0", Architectures: []string{"arm64"}}} + updater := cloudprofilesync.ImageUpdater{Log: GinkgoLogr, Source: &mockSource, ImageName: "test"} + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(2)) + Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1.0.0")) + Expect(cpSpec.MachineImages[0].Versions[1].Version).To(Equal("2.0.0")) + }) + + It("does not change unrelated images in the CloudProfile spec", func(ctx SpecContext) { + cpSpec := gardencorev1beta1.CloudProfileSpec{ + MachineImages: []gardencorev1beta1.MachineImage{ + {Name: "test", Versions: []gardencorev1beta1.MachineImageVersion{ + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "1.0.0"}, Architectures: []string{"amd64"}}, + }}, + {Name: "other", Versions: []gardencorev1beta1.MachineImageVersion{ + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "2.0.0"}, Architectures: []string{"arm64"}}, + }}, }, - Architectures: []string{"arm64", "amd64"}, - }, - })) - }) + } + mockSource.images = []cloudprofilesync.SourceImage{{Version: "1.1.0", Architectures: []string{"arm64"}}} + updater := cloudprofilesync.ImageUpdater{Log: GinkgoLogr, Source: &mockSource, ImageName: "test"} + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages).To(ConsistOf([]gardencorev1beta1.MachineImage{ + {Name: "test", Versions: []gardencorev1beta1.MachineImageVersion{ + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "1.0.0"}, Architectures: []string{"amd64"}}, + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "1.1.0"}, Architectures: []string{"arm64"}}, + }}, + {Name: "other", Versions: []gardencorev1beta1.MachineImageVersion{ + {ExpirableVersion: gardencorev1beta1.ExpirableVersion{Version: "2.0.0"}, Architectures: []string{"arm64"}}, + }}, + })) + }) - It("updates an image from the source in the CloudProfile spec", func(ctx SpecContext) { - cpSpec := v1beta1.CloudProfileSpec{ - MachineImages: []v1beta1.MachineImage{ + It("ignores CleanVersion when flag is OFF", func(ctx SpecContext) { + mockSource.images = []cloudprofilesync.SourceImage{ { - Name: "test", - Versions: []v1beta1.MachineImageVersion{ - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "1.0.0", - }, - Architectures: []string{"amd64"}, - }, - }, + Version: "2254.0.0-baremetal-sci-usi-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: gardencorev1beta1.Capabilities{"architecture": {"amd64"}, "feature": {"sci", "_usi"}}, }, - }, - } + } + updater := cloudprofilesync.ImageUpdater{ + Log: GinkgoLogr, + Source: &mockSource, + ImageName: "test", + EnableCapabilities: false, + } + var cpSpec gardencorev1beta1.CloudProfileSpec + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(1)) + Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("2254.0.0-baremetal-sci-usi-amd64")) + }) - mockSource.images = []cloudprofilesync.SourceImage{{Version: "2.0.0", Architectures: []string{"arm64"}}} - updater := cloudprofilesync.ImageUpdater{ - Log: GinkgoLogr, - Source: &mockSource, - ImageName: "test", - } - Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) - Expect(cpSpec.MachineImages).To(HaveLen(1)) - Expect(cpSpec.MachineImages[0].Name).To(Equal("test")) - Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(2)) - Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1.0.0")) - Expect(cpSpec.MachineImages[0].Versions[0].Architectures).To(Equal([]string{"amd64"})) - Expect(cpSpec.MachineImages[0].Versions[1].Version).To(Equal("2.0.0")) - Expect(cpSpec.MachineImages[0].Versions[1].Architectures).To(Equal([]string{"arm64"})) + It("invokes the given provider", func(ctx SpecContext) { + mockSource.images = []cloudprofilesync.SourceImage{{Version: "1.0.0", Architectures: []string{"amd64"}}} + updater := cloudprofilesync.ImageUpdater{ + Log: GinkgoLogr, + Source: &mockSource, + ImageName: "test", + Provider: &MockProvider{}, + } + var cpSpec gardencorev1beta1.CloudProfileSpec + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + var fromProvider []cloudprofilesync.SourceImage + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &fromProvider)).To(Succeed()) + Expect(fromProvider).To(Equal(mockSource.images)) + }) }) - It("does not change unrelated images in the CloudProfile spec", func(ctx SpecContext) { - cpSpec := v1beta1.CloudProfileSpec{ - MachineImages: []v1beta1.MachineImage{ - { - Name: "test", - Versions: []v1beta1.MachineImageVersion{ - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "1.0.0", - }, - Architectures: []string{"amd64"}, - }, - }, - }, + Describe("flag ON (dual-write clean version)", func() { + It("writes both full tag and clean version entries when CleanVersion differs", func(ctx SpecContext) { + mockSource.images = []cloudprofilesync.SourceImage{ { - Name: "other", - Versions: []v1beta1.MachineImageVersion{ - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "2.0.0", - }, - Architectures: []string{"arm64"}, - }, - }, + Version: "2254.0.0-baremetal-sci-usi-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: gardencorev1beta1.Capabilities{"architecture": {"amd64"}, "feature": {"sci", "_usi"}}, }, - }, - } + } + updater := cloudprofilesync.ImageUpdater{ + Log: GinkgoLogr, + Source: &mockSource, + ImageName: "test", + EnableCapabilities: true, + } + var cpSpec gardencorev1beta1.CloudProfileSpec + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(2)) - mockSource.images = []cloudprofilesync.SourceImage{{Version: "1.1.0", Architectures: []string{"arm64"}}} - updater := cloudprofilesync.ImageUpdater{ - Log: GinkgoLogr, - Source: &mockSource, - ImageName: "test", - } - Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) - Expect(cpSpec.MachineImages).To(ConsistOf([]v1beta1.MachineImage{ - { - Name: "test", - Versions: []v1beta1.MachineImageVersion{ - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "1.0.0", - }, - Architectures: []string{"amd64"}, - }, - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "1.1.0", - }, - Architectures: []string{"arm64"}, - }, - }, - }, - { - Name: "other", - Versions: []v1beta1.MachineImageVersion{ - { - ExpirableVersion: v1beta1.ExpirableVersion{ - Version: "2.0.0", - }, - Architectures: []string{"arm64"}, - }, + versions := cpSpec.MachineImages[0].Versions + versionStrings := []string{versions[0].Version, versions[1].Version} + Expect(versionStrings).To(ContainElements("2254.0.0-baremetal-sci-usi-amd64", "2254.0.0")) + }) + + It("does not add a duplicate clean version entry on re-reconcile", func(ctx SpecContext) { + mockSource.images = []cloudprofilesync.SourceImage{ + { + Version: "2254.0.0-baremetal-sci-usi-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: gardencorev1beta1.Capabilities{"architecture": {"amd64"}, "feature": {"sci", "_usi"}}, }, - }, - })) - }) + } + updater := cloudprofilesync.ImageUpdater{ + Log: GinkgoLogr, + Source: &mockSource, + ImageName: "test", + EnableCapabilities: true, + } + var cpSpec gardencorev1beta1.CloudProfileSpec + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(2)) + }) - It("invokes the given provider", func(ctx SpecContext) { - mockSource.images = []cloudprofilesync.SourceImage{{Version: "1.0.0", Architectures: []string{"amd64"}}} - updater := cloudprofilesync.ImageUpdater{ - Log: GinkgoLogr, - Source: &mockSource, - ImageName: "test", - Provider: &MockProvider{}, - } - var cpSpec v1beta1.CloudProfileSpec - Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) - var fromProvider []cloudprofilesync.SourceImage - Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &fromProvider)).To(Succeed()) - Expect(fromProvider).To(Equal(mockSource.images)) + It("writes only full tag when CleanVersion is absent", func(ctx SpecContext) { + mockSource.images = []cloudprofilesync.SourceImage{ + {Version: "1877.0.0", Architectures: []string{"amd64"}}, + } + updater := cloudprofilesync.ImageUpdater{ + Log: GinkgoLogr, + Source: &mockSource, + ImageName: "test", + EnableCapabilities: true, + } + var cpSpec gardencorev1beta1.CloudProfileSpec + Expect(updater.Update(ctx, &cpSpec)).To(Succeed()) + Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(1)) + Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1877.0.0")) + }) }) - }) diff --git a/cloudprofilesync/provider.go b/cloudprofilesync/provider.go index 23b375c..37b475e 100644 --- a/cloudprofilesync/provider.go +++ b/cloudprofilesync/provider.go @@ -7,22 +7,23 @@ import ( "encoding/json" "slices" - "github.com/gardener/gardener/pkg/apis/core/v1beta1" + gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" "github.com/ironcore-dev/gardener-extension-provider-ironcore-metal/pkg/apis/metal/v1alpha1" "k8s.io/apimachinery/pkg/runtime" ) type Provider interface { - Configure(cloudProfile *v1beta1.CloudProfileSpec, versions []SourceImage) error + Configure(cloudProfile *gardencorev1beta1.CloudProfileSpec, versions []SourceImage) error } type IroncoreProvider struct { - Registry string - Repository string - ImageName string + Registry string + Repository string + ImageName string + EnableCapabilities bool } -func (p *IroncoreProvider) Configure(cpSpec *v1beta1.CloudProfileSpec, versions []SourceImage) error { +func (p *IroncoreProvider) Configure(cpSpec *gardencorev1beta1.CloudProfileSpec, versions []SourceImage) error { var cfg v1alpha1.CloudProfileConfig if cpSpec.ProviderConfig != nil { if err := json.Unmarshal(cpSpec.ProviderConfig.Raw, &cfg); err != nil { @@ -41,30 +42,59 @@ func (p *IroncoreProvider) Configure(cpSpec *v1beta1.CloudProfileSpec, versions } image := &cfg.MachineImages[imageIndex] - existingRefs := map[string]struct{}{} - for _, version := range image.Versions { - existingRefs[version.Image] = struct{}{} + existingVersions := make(map[string]int, len(image.Versions)) + for i, v := range image.Versions { + existingVersions[v.Version] = i } - for _, version := range versions { - ref := p.Registry + "/" + p.Repository + ":" + version.Version - if _, ok := existingRefs[ref]; ok { - continue + for _, src := range versions { + ref := p.Registry + "/" + p.Repository + ":" + src.Version + + // Always write the legacy flat entry keyed by the full tag. + for _, arch := range src.Architectures { + archCopy := arch + alreadyPresent := slices.ContainsFunc(image.Versions, func(v v1alpha1.MachineImageVersion) bool { + return v.Image == ref && v.Architecture != nil && *v.Architecture == arch + }) + if !alreadyPresent { + image.Versions = append(image.Versions, v1alpha1.MachineImageVersion{ + Version: src.Version, + Image: ref, + Architecture: &archCopy, + }) + } } - for _, arch := range version.Architectures { - image.Versions = append(image.Versions, v1alpha1.MachineImageVersion{ - Version: version.Version, + + // When capabilities are enabled and the image carries capability metadata, + // also write a CapabilityFlavors entry grouped under the clean version. + if p.EnableCapabilities && src.Capabilities != nil && src.CleanVersion != "" && src.CleanVersion != src.Version { + flavor := v1alpha1.MachineImageFlavor{ Image: ref, - Architecture: &arch, - }) + Capabilities: src.Capabilities, + } + if idx, exists := existingVersions[src.CleanVersion]; exists { + existing := &image.Versions[idx] + alreadyPresent := slices.ContainsFunc(existing.CapabilityFlavors, func(f v1alpha1.MachineImageFlavor) bool { + return f.Image == ref + }) + if !alreadyPresent { + existing.CapabilityFlavors = append(existing.CapabilityFlavors, flavor) + } + } else { + idx := len(image.Versions) + image.Versions = append(image.Versions, v1alpha1.MachineImageVersion{ + Version: src.CleanVersion, + CapabilityFlavors: []v1alpha1.MachineImageFlavor{flavor}, + }) + existingVersions[src.CleanVersion] = idx + } } } + raw, err := json.Marshal(cfg) if err != nil { return err } - cpSpec.ProviderConfig = &runtime.RawExtension{ - Raw: raw, - } - return err + cpSpec.ProviderConfig = &runtime.RawExtension{Raw: raw} + return nil } diff --git a/cloudprofilesync/provider_test.go b/cloudprofilesync/provider_test.go index f566924..c976d6c 100644 --- a/cloudprofilesync/provider_test.go +++ b/cloudprofilesync/provider_test.go @@ -6,7 +6,7 @@ package cloudprofilesync_test import ( "encoding/json" - "github.com/gardener/gardener/pkg/apis/core/v1beta1" + gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" "github.com/ironcore-dev/gardener-extension-provider-ironcore-metal/pkg/apis/metal/v1alpha1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -16,72 +16,206 @@ import ( var _ = Describe("IroncoreProvider", func() { - provider := &cloudprofilesync.IroncoreProvider{ - Registry: "registry.io", - Repository: "repo", - ImageName: "test", + legacyProvider := &cloudprofilesync.IroncoreProvider{ + Registry: "registry.io", + Repository: "repo", + ImageName: "test", + EnableCapabilities: false, } - It("should add an image to the provider config", func() { - var cpSpec v1beta1.CloudProfileSpec - versions := []cloudprofilesync.SourceImage{{Version: "v1.0.0", Architectures: []string{"amd64"}}} - Expect(provider.Configure(&cpSpec, versions)).To(Succeed()) - Expect(cpSpec.ProviderConfig).ToNot(BeNil()) - - var providerConfig v1alpha1.CloudProfileConfig - Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) - Expect(providerConfig.MachineImages).To(HaveLen(1)) - Expect(providerConfig.MachineImages[0].Name).To(Equal("test")) - Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(1)) - Expect(providerConfig.MachineImages[0].Versions[0].Version).To(Equal("v1.0.0")) - Expect(providerConfig.MachineImages[0].Versions[0].Image).To(Equal("registry.io/repo:v1.0.0")) - Expect(providerConfig.MachineImages[0].Versions[0].Architecture).To(HaveValue(Equal("amd64"))) - }) + capProvider := &cloudprofilesync.IroncoreProvider{ + Registry: "registry.io", + Repository: "repo", + ImageName: "test", + EnableCapabilities: true, + } - It("should multiply out architectures", func() { - var cpSpec v1beta1.CloudProfileSpec - versions := []cloudprofilesync.SourceImage{ - {Version: "v1.0.0", Architectures: []string{"amd64", "arm64"}}, - } - Expect(provider.Configure(&cpSpec, versions)).To(Succeed()) - Expect(cpSpec.ProviderConfig).ToNot(BeNil()) - - var providerConfig v1alpha1.CloudProfileConfig - Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) - Expect(providerConfig.MachineImages).To(HaveLen(1)) - Expect(providerConfig.MachineImages[0].Name).To(Equal("test")) - - amd64 := "amd64" - arm64 := "arm64" - Expect(providerConfig.MachineImages[0].Versions).To(ConsistOf([]v1alpha1.MachineImageVersion{ - { - Version: "v1.0.0", - Image: "registry.io/repo:v1.0.0", - Architecture: &amd64, - }, - { - Version: "v1.0.0", - Image: "registry.io/repo:v1.0.0", - Architecture: &arm64, - }, - })) + Describe("flag OFF (legacy format only)", func() { + It("should add an image to the provider config", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{{Version: "v1.0.0", Architectures: []string{"amd64"}}} + Expect(legacyProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(1)) + Expect(providerConfig.MachineImages[0].Versions[0].Version).To(Equal("v1.0.0")) + Expect(providerConfig.MachineImages[0].Versions[0].Image).To(Equal("registry.io/repo:v1.0.0")) + Expect(providerConfig.MachineImages[0].Versions[0].Architecture).To(HaveValue(Equal("amd64"))) + Expect(providerConfig.MachineImages[0].Versions[0].CapabilityFlavors).To(BeEmpty()) + }) + + It("should multiply out architectures", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{ + {Version: "v1.0.0", Architectures: []string{"amd64", "arm64"}}, + } + Expect(legacyProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + + amd64 := "amd64" + arm64 := "arm64" + Expect(providerConfig.MachineImages[0].Versions).To(ConsistOf([]v1alpha1.MachineImageVersion{ + {Version: "v1.0.0", Image: "registry.io/repo:v1.0.0", Architecture: &amd64}, + {Version: "v1.0.0", Image: "registry.io/repo:v1.0.0", Architecture: &arm64}, + })) + }) + + It("should not add duplicate images", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{ + {Version: "v1.0.0", Architectures: []string{"amd64"}}, + {Version: "v1.0.0", Architectures: []string{"arm64"}}, + } + Expect(legacyProvider.Configure(&cpSpec, versions)).To(Succeed()) + Expect(legacyProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(2)) + }) + + It("should ignore Capabilities and CleanVersion", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{ + { + Version: "2254.0.0-baremetal-sci-usi-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: gardencorev1beta1.Capabilities{ + "architecture": {"amd64"}, + "feature": {"sci", "_usi"}, + }, + }, + } + Expect(legacyProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + // Only the legacy flat entry — no CapabilityFlavors entry. + Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(1)) + Expect(providerConfig.MachineImages[0].Versions[0].Version).To(Equal("2254.0.0-baremetal-sci-usi-amd64")) + Expect(providerConfig.MachineImages[0].Versions[0].CapabilityFlavors).To(BeEmpty()) + }) }) - It("should not add duplicate images", func() { - var cpSpec v1beta1.CloudProfileSpec - versions := []cloudprofilesync.SourceImage{ - {Version: "v1.0.0", Architectures: []string{"amd64"}}, - {Version: "v1.0.0", Architectures: []string{"arm64"}}, + Describe("flag ON (dual-write: legacy + CapabilityFlavors)", func() { + capabilities := gardencorev1beta1.Capabilities{ + "architecture": {"amd64"}, + "feature": {"sci", "_usi"}, } - Expect(provider.Configure(&cpSpec, versions)).To(Succeed()) - Expect(provider.Configure(&cpSpec, versions)).To(Succeed()) - Expect(cpSpec.ProviderConfig).ToNot(BeNil()) - - var providerConfig v1alpha1.CloudProfileConfig - Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) - Expect(providerConfig.MachineImages).To(HaveLen(1)) - Expect(providerConfig.MachineImages[0].Name).To(Equal("test")) - Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(2)) - }) + It("should write both legacy flat entry and CapabilityFlavors entry", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{ + { + Version: "2254.0.0-baremetal-sci-usi-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: capabilities, + }, + } + Expect(capProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + // Two entries: one legacy (full tag), one with CapabilityFlavors (clean version). + Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(2)) + + legacyEntry := providerConfig.MachineImages[0].Versions[0] + Expect(legacyEntry.Version).To(Equal("2254.0.0-baremetal-sci-usi-amd64")) + Expect(legacyEntry.Image).To(Equal("registry.io/repo:2254.0.0-baremetal-sci-usi-amd64")) + Expect(legacyEntry.Architecture).To(HaveValue(Equal("amd64"))) + Expect(legacyEntry.CapabilityFlavors).To(BeEmpty()) + + capEntry := providerConfig.MachineImages[0].Versions[1] + Expect(capEntry.Version).To(Equal("2254.0.0")) + Expect(capEntry.Image).To(BeEmpty()) + Expect(capEntry.Architecture).To(BeNil()) + Expect(capEntry.CapabilityFlavors).To(HaveLen(1)) + Expect(capEntry.CapabilityFlavors[0].Image).To(Equal("registry.io/repo:2254.0.0-baremetal-sci-usi-amd64")) + Expect(capEntry.CapabilityFlavors[0].Capabilities).To(Equal(capabilities)) + }) + + It("should group multiple flavors under one clean version entry", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{ + { + Version: "2254.0.0-baremetal-sci-usi-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: gardencorev1beta1.Capabilities{ + "architecture": {"amd64"}, + "feature": {"sci", "_usi"}, + }, + }, + { + Version: "2254.0.0-baremetal-sci-pxe-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: gardencorev1beta1.Capabilities{ + "architecture": {"amd64"}, + "feature": {"sci", "_pxe"}, + }, + }, + } + Expect(capProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + // Two legacy flat entries + one clean version entry with two flavors. + Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(3)) + + var cleanEntry *v1alpha1.MachineImageVersion + for i := range providerConfig.MachineImages[0].Versions { + if providerConfig.MachineImages[0].Versions[i].Version == "2254.0.0" { + cleanEntry = &providerConfig.MachineImages[0].Versions[i] + } + } + Expect(cleanEntry).ToNot(BeNil()) + Expect(cleanEntry.CapabilityFlavors).To(HaveLen(2)) + }) + + It("should not add duplicate capability flavors on re-reconcile", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{ + { + Version: "2254.0.0-baremetal-sci-usi-amd64", + CleanVersion: "2254.0.0", + Architectures: []string{"amd64"}, + Capabilities: capabilities, + }, + } + Expect(capProvider.Configure(&cpSpec, versions)).To(Succeed()) + Expect(capProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(2)) + + var cleanEntry *v1alpha1.MachineImageVersion + for i := range providerConfig.MachineImages[0].Versions { + if providerConfig.MachineImages[0].Versions[i].Version == "2254.0.0" { + cleanEntry = &providerConfig.MachineImages[0].Versions[i] + } + } + Expect(cleanEntry.CapabilityFlavors).To(HaveLen(1)) + }) + + It("should write only legacy entry for images without capabilities", func() { + var cpSpec gardencorev1beta1.CloudProfileSpec + versions := []cloudprofilesync.SourceImage{ + {Version: "1877.0.0", Architectures: []string{"amd64"}}, + } + Expect(capProvider.Configure(&cpSpec, versions)).To(Succeed()) + + var providerConfig v1alpha1.CloudProfileConfig + Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &providerConfig)).To(Succeed()) + Expect(providerConfig.MachineImages[0].Versions).To(HaveLen(1)) + Expect(providerConfig.MachineImages[0].Versions[0].Version).To(Equal("1877.0.0")) + Expect(providerConfig.MachineImages[0].Versions[0].CapabilityFlavors).To(BeEmpty()) + }) + }) }) diff --git a/cloudprofilesync/source.go b/cloudprofilesync/source.go index 128e3ab..3599f10 100644 --- a/cloudprofilesync/source.go +++ b/cloudprofilesync/source.go @@ -7,22 +7,69 @@ import ( "context" "encoding/json" "errors" + "fmt" "strings" + gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" "golang.org/x/sync/semaphore" "oras.land/oras-go/v2/registry/remote" "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras-go/v2/registry/remote/retry" ) +// validFeatureValues is the allowlist of feature values extracted from the feature_set annotation. +var validFeatureValues = map[string]struct{}{ + "chost": {}, + "_pxe": {}, + "sci": {}, + "capi": {}, + "scibase": {}, + "_usi": {}, + "_usidev": {}, +} + +func filterFeatureSet(featureSet string) []string { + raw := strings.Split(featureSet, ",") + seen := make(map[string]struct{}, len(raw)) + result := make([]string, 0, len(raw)) + for _, f := range raw { + f = strings.TrimSpace(f) + if _, valid := validFeatureValues[f]; !valid { + continue + } + if _, dup := seen[f]; dup { + continue + } + seen[f] = struct{}{} + result = append(result, f) + } + return result +} + type Result[T any] struct { value T err error } type SourceImage struct { - Version string + // Version is the full tag from the registry (used as version key for legacy images). + Version string + // CleanVersion is the version from the "version" OCI annotation (e.g. "2262.0.0"). + // When set, flavors are grouped under it in the CloudProfile instead of the full tag. + CleanVersion string + // TODO: deprecate once all images carry capability annotations; use Capabilities["architecture"] instead. Architectures []string + // Capabilities holds parsed OCI manifest annotations. Nil means the image + // predates capability annotations and should use the legacy format. + Capabilities gardencorev1beta1.Capabilities +} + +// effectiveVersion returns CleanVersion when available, falling back to Version. +func (s SourceImage) effectiveVersion() string { + if s.CleanVersion != "" { + return s.CleanVersion + } + return s.Version } type Source interface { @@ -101,13 +148,29 @@ func (o *OCI) GetVersions(ctx context.Context) ([]SourceImage, error) { } arch, ok := manifest.Annotations["architecture"] if !ok { - out <- Result[SourceImage]{err: errors.New("architecture annotation not found in descriptor")} + out <- Result[SourceImage]{err: fmt.Errorf("architecture annotation not found in descriptor. tag: %s", tag)} return } + var capabilities gardencorev1beta1.Capabilities + var cleanVersion string + if featureSet, ok := manifest.Annotations["feature_set"]; ok { + if version, ok := manifest.Annotations["version"]; ok { + features := filterFeatureSet(featureSet) + if len(features) > 0 { + capabilities = gardencorev1beta1.Capabilities{ + "architecture": {arch}, + "feature": features, + } + cleanVersion = version + } + } + } out <- Result[SourceImage]{ value: SourceImage{ Version: strings.ReplaceAll(tag, "_", "+"), // Follow the helm convention + CleanVersion: cleanVersion, Architectures: []string{arch}, + Capabilities: capabilities, }, } }() diff --git a/cloudprofilesync/source_test.go b/cloudprofilesync/source_test.go index 39722d3..a49ee4e 100644 --- a/cloudprofilesync/source_test.go +++ b/cloudprofilesync/source_test.go @@ -8,6 +8,7 @@ import ( "encoding/json" "strings" + gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/opencontainers/image-spec/specs-go" @@ -69,4 +70,128 @@ var _ = Describe("OCISource", func() { cloudprofilesync.SourceImage{Version: "1.0.1+abc", Architectures: []string{"amd64"}})) }) + It("populates capabilities when feature_set annotation is present", func(ctx SpecContext) { + repo, err := remote.NewRepository(registryAddr + "/repo-caps") + Expect(err).To(Succeed()) + repo.PlainHTTP = true + + index := ocispec.Index{ + Versioned: specs.Versioned{SchemaVersion: 2}, + Manifests: []ocispec.Descriptor{ + { + MediaType: ocispec.MediaTypeImageManifest, + Size: 0, + Digest: ocispec.DescriptorEmptyJSON.Digest, + }, + }, + Annotations: map[string]string{ + "architecture": "amd64", + "feature_set": "sci,_usi,_rescue,log", + "version": "2.0.0", + }, + } + indexBlob, err := json.Marshal(index) + Expect(err).To(Succeed()) + indexDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageIndex, indexBlob) + + err = repo.Push(ctx, ocispec.DescriptorEmptyJSON, strings.NewReader("{}")) + Expect(err).To(Succeed()) + err = repo.PushReference(ctx, indexDesc, bytes.NewReader(indexBlob), "2.0.0") + Expect(err).To(Succeed()) + + oci, err := cloudprofilesync.NewOCI(cloudprofilesync.OCIParams{ + Registry: registryAddr, + Repository: "repo-caps", + Parallel: 4, + }, true) + Expect(err).To(Succeed()) + versions, err := oci.GetVersions(ctx) + Expect(err).To(Succeed()) + Expect(versions).To(HaveLen(1)) + Expect(versions[0].Version).To(Equal("2.0.0")) + Expect(versions[0].CleanVersion).To(Equal("2.0.0")) + Expect(versions[0].Architectures).To(Equal([]string{"amd64"})) + Expect(versions[0].Capabilities).To(Equal(gardencorev1beta1.Capabilities{ + "architecture": {"amd64"}, + "feature": {"sci", "_usi"}, // _rescue and log are filtered out + })) + }) + + It("leaves Capabilities nil when only architecture annotation is present", func(ctx SpecContext) { + repo, err := remote.NewRepository(registryAddr + "/repo-legacy") + Expect(err).To(Succeed()) + repo.PlainHTTP = true + + index := ocispec.Index{ + Versioned: specs.Versioned{SchemaVersion: 2}, + Manifests: []ocispec.Descriptor{ + { + MediaType: ocispec.MediaTypeImageManifest, + Size: 0, + Digest: ocispec.DescriptorEmptyJSON.Digest, + }, + }, + Annotations: map[string]string{ + "architecture": "amd64", + }, + } + indexBlob, err := json.Marshal(index) + Expect(err).To(Succeed()) + indexDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageIndex, indexBlob) + + err = repo.Push(ctx, ocispec.DescriptorEmptyJSON, strings.NewReader("{}")) + Expect(err).To(Succeed()) + err = repo.PushReference(ctx, indexDesc, bytes.NewReader(indexBlob), "1.0.0-legacy") + Expect(err).To(Succeed()) + + oci, err := cloudprofilesync.NewOCI(cloudprofilesync.OCIParams{ + Registry: registryAddr, + Repository: "repo-legacy", + Parallel: 4, + }, true) + Expect(err).To(Succeed()) + versions, err := oci.GetVersions(ctx) + Expect(err).To(Succeed()) + Expect(versions).To(HaveLen(1)) + Expect(versions[0].Capabilities).To(BeNil()) + }) + + It("leaves Capabilities nil when feature_set contains no valid values", func(ctx SpecContext) { + repo, err := remote.NewRepository(registryAddr + "/repo-no-valid-features") + Expect(err).To(Succeed()) + repo.PlainHTTP = true + + index := ocispec.Index{ + Versioned: specs.Versioned{SchemaVersion: 2}, + Manifests: []ocispec.Descriptor{ + {MediaType: ocispec.MediaTypeImageManifest, Size: 0, Digest: ocispec.DescriptorEmptyJSON.Digest}, + }, + Annotations: map[string]string{ + "architecture": "amd64", + "feature_set": "_rescue,log,sap,ssh", + "version": "3.0.0", + }, + } + indexBlob, err := json.Marshal(index) + Expect(err).To(Succeed()) + indexDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageIndex, indexBlob) + + err = repo.Push(ctx, ocispec.DescriptorEmptyJSON, strings.NewReader("{}")) + Expect(err).To(Succeed()) + err = repo.PushReference(ctx, indexDesc, bytes.NewReader(indexBlob), "3.0.0-no-valid-features") + Expect(err).To(Succeed()) + + oci, err := cloudprofilesync.NewOCI(cloudprofilesync.OCIParams{ + Registry: registryAddr, + Repository: "repo-no-valid-features", + Parallel: 4, + }, true) + Expect(err).To(Succeed()) + versions, err := oci.GetVersions(ctx) + Expect(err).To(Succeed()) + Expect(versions).To(HaveLen(1)) + Expect(versions[0].Capabilities).To(BeNil()) + Expect(versions[0].CleanVersion).To(BeEmpty()) + }) + }) diff --git a/controllers/managedcloudprofile_controller.go b/controllers/managedcloudprofile_controller.go index a22b08a..85c1dc5 100644 --- a/controllers/managedcloudprofile_controller.go +++ b/controllers/managedcloudprofile_controller.go @@ -60,6 +60,7 @@ type Reconciler struct { client.Client OCISourceFactory OCISourceFactory RegistryProviderFunc func(registry string) (RegistryClient, error) + EnableCapabilities bool } type KeppelTag struct { @@ -300,16 +301,18 @@ func (r *Reconciler) updateMachineImages(ctx context.Context, log logr.Logger, u var provider cloudprofilesync.Provider if update.Provider.IroncoreMetal != nil { provider = &cloudprofilesync.IroncoreProvider{ - Registry: update.Provider.IroncoreMetal.Registry, - Repository: update.Provider.IroncoreMetal.Repository, - ImageName: update.ImageName, + Registry: update.Provider.IroncoreMetal.Registry, + Repository: update.Provider.IroncoreMetal.Repository, + ImageName: update.ImageName, + EnableCapabilities: r.EnableCapabilities, } } imageUpdater := cloudprofilesync.ImageUpdater{ - Log: log, - Source: source, - Provider: provider, - ImageName: update.ImageName, + Log: log, + Source: source, + Provider: provider, + ImageName: update.ImageName, + EnableCapabilities: r.EnableCapabilities, } if err := imageUpdater.Update(ctx, cpSpec); err != nil { return fmt.Errorf("updating machine images failed: %w", err) diff --git a/go.mod b/go.mod index 8e4828e..0bc82ee 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/cobaltcore-dev/cloud-profile-sync -go 1.26.0 +go 1.26.2 require ( github.com/blang/semver/v4 v4.0.0 github.com/distribution/distribution/v3 v3.1.1 - github.com/gardener/gardener/pkg/apis v1.142.1 + github.com/gardener/gardener/pkg/apis v1.144.0 github.com/go-logr/logr v1.4.3 - github.com/ironcore-dev/gardener-extension-provider-ironcore-metal v0.1.0 + github.com/ironcore-dev/gardener-extension-provider-ironcore-metal v0.1.1-0.20260610093013-d6bdd61f63ae github.com/onsi/ginkgo/v2 v2.29.0 github.com/onsi/gomega v1.41.0 github.com/opencontainers/image-spec v1.1.1 @@ -36,49 +36,47 @@ require ( github.com/docker/go-events v0.0.0-20250808211157-605354379745 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect - github.com/evanphx/json-patch v5.9.11+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/fsnotify/fsnotify v1.10.1 // indirect + github.com/fxamacker/cbor/v2 v2.9.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.22.5 // indirect - github.com/go-openapi/jsonreference v0.21.5 // 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.26.0 // indirect - github.com/go-openapi/swag/fileutils v0.26.0 // indirect - github.com/go-openapi/swag/jsonname v0.25.5 // indirect - github.com/go-openapi/swag/jsonutils v0.26.0 // indirect - github.com/go-openapi/swag/loading v0.25.5 // indirect - github.com/go-openapi/swag/mangling v0.25.5 // indirect - github.com/go-openapi/swag/netutils v0.25.4 // indirect - github.com/go-openapi/swag/stringutils v0.26.0 // indirect - github.com/go-openapi/swag/typeutils v0.26.0 // indirect - github.com/go-openapi/swag/yamlutils v0.25.5 // indirect + github.com/go-openapi/jsonpointer v0.23.1 // indirect + github.com/go-openapi/jsonreference v0.21.6 // indirect + github.com/go-openapi/swag v0.26.1 // indirect + github.com/go-openapi/swag/cmdutils v0.26.1 // indirect + github.com/go-openapi/swag/conv v0.26.1 // indirect + github.com/go-openapi/swag/fileutils v0.26.1 // indirect + github.com/go-openapi/swag/jsonname v0.26.1 // indirect + github.com/go-openapi/swag/jsonutils v0.26.1 // indirect + github.com/go-openapi/swag/loading v0.26.1 // indirect + github.com/go-openapi/swag/mangling v0.26.1 // indirect + github.com/go-openapi/swag/netutils v0.26.1 // indirect + github.com/go-openapi/swag/stringutils v0.26.1 // indirect + github.com/go-openapi/swag/typeutils v0.26.1 // indirect + github.com/go-openapi/swag/yamlutils v0.26.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/goccy/go-yaml v1.19.2 // indirect github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect + github.com/google/pprof v0.0.0-20260604005048-7023385849c0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect github.com/hashicorp/golang-lru/arc/v2 v2.0.5 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect - github.com/klauspost/compress v1.18.6 // indirect + github.com/klauspost/compress v1.18.4 // 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/opencontainers/go-digest v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.23.3-0.20260602051030-3537b20ac86b // indirect + github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.68.0 // indirect + github.com/prometheus/common v0.68.1 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/prometheus/procfs v0.20.1 // indirect github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 // indirect @@ -91,50 +89,50 @@ require ( go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect - go.opentelemetry.io/otel v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/prometheus v0.65.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.64.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 // indirect go.opentelemetry.io/otel/log v0.19.0 // indirect - go.opentelemetry.io/otel/metric v1.43.0 // indirect - go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 // indirect go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect - go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.52.0 // indirect - golang.org/x/mod v0.36.0 // indirect + golang.org/x/crypto v0.53.0 // indirect + golang.org/x/mod v0.37.0 // indirect golang.org/x/net v0.55.0 // indirect golang.org/x/oauth2 v0.36.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/sys v0.46.0 // indirect + golang.org/x/term v0.44.0 // indirect + golang.org/x/text v0.38.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.45.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect - google.golang.org/grpc v1.80.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260608224507-4308a22a1bab // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab // indirect + google.golang.org/grpc v1.81.1 // 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.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect + k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25 // 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.4.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index 5dc47ea..edd87d0 100644 --- a/go.sum +++ b/go.sum @@ -44,18 +44,18 @@ github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= -github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= -github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/gardener/gardener/pkg/apis v1.142.1 h1:DLWpTpq1cxPzOHPcfYG7+YL1/0Cb9enxkejtMA65blw= -github.com/gardener/gardener/pkg/apis v1.142.1/go.mod h1:oN2NXhb68BCwMS8DHlVHZeGA88IUtjtCpMT1DapNN5o= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gardener/gardener/pkg/apis v1.144.0 h1:xlnGMbliM5TjlK5o2oCxzyFSmtxgGerP4SDwEXdHL2E= +github.com/gardener/gardener/pkg/apis v1.144.0/go.mod h1:we6hJ8r80nL1rkXzVnOQwey4q77pQXHN3pvoBgeak8g= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= @@ -72,40 +72,40 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= -github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= -github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= -github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= -github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= -github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= -github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= -github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= -github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I= -github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE= -github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU= -github.com/go-openapi/swag/fileutils v0.26.0/go.mod h1:0WDJ7lp67eNjPMO50wAWYlKvhOb6CQ37rzR7wrgI8Tc= -github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= -github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= -github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA= -github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y= -github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= -github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= -github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw= -github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY= -github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= -github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= -github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg= -github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE= -github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4= -github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= -github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= -github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE= -github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4= -github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= +github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= +github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y= +github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY= +github.com/go-openapi/swag v0.26.1 h1:l5sVEyVpwj+DDYeZyo7wQI/Ebn/mKYIyGB/pFwAfGoQ= +github.com/go-openapi/swag v0.26.1/go.mod h1:yNY38BbIVthxbkDtq1UHBCGasBqjakW3lCR6ANzdBEw= +github.com/go-openapi/swag/cmdutils v0.26.1 h1:f2iE1ijYaJ3nuu5PaEMx3zpEhzhZFgivCJObWEObLIQ= +github.com/go-openapi/swag/cmdutils v0.26.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= +github.com/go-openapi/swag/conv v0.26.1 h1:slr5FVkg9Wc3Y5zcwenD8Sd/PQ94b2I/QJI7N7KTBpg= +github.com/go-openapi/swag/conv v0.26.1/go.mod h1:mvQXgPptZk9GTrFgGwWvT4q+dN+zQej9JfmGwnipz1A= +github.com/go-openapi/swag/fileutils v0.26.1 h1:K1XCM2CGhfNsc6YDt6v7Q5+1e59rftYWdcu/isZhvFw= +github.com/go-openapi/swag/fileutils v0.26.1/go.mod h1:mYUgxQAKX4ShS3qvvySx+/9yrlUnDhjiD1CalaQl8lQ= +github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE= +github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc= +github.com/go-openapi/swag/jsonutils v0.26.1 h1:2hdBfFkHg+7Wrz2VsCbeyR6hzkRDs7AztnMR2u84yOY= +github.com/go-openapi/swag/jsonutils v0.26.1/go.mod h1:U+RMJH3wa+6BRiphuRtIyI8fW9HPFqFQ4sHk2oRx0UQ= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1 h1:1CD7NiLLb/TXl3tOnFYU4b+mNfb5rtgHkaA+q7RMYYQ= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1/go.mod h1:ZWafc8nMdYzTE3uYY6W86f0n46+IF0g4uUyRhJw/kXc= +github.com/go-openapi/swag/loading v0.26.1 h1:E9K4wqXeROlhjFQ13K9zMz6ojFGXIggGe+ad1odrK9w= +github.com/go-openapi/swag/loading v0.26.1/go.mod h1:3qvRIlWzWdq1HvmldwmuJ2ohpcAryN6xVt2OTKd0/7E= +github.com/go-openapi/swag/mangling v0.26.1 h1:gpYI4WuPKFJJVjV5cDLGlDVJhFIxYjQc7yN5eEb4CqM= +github.com/go-openapi/swag/mangling v0.26.1/go.mod h1:POETDH01hqAdASXfw7ISEd9bCOE6xBHOt8NHmGZRmYM= +github.com/go-openapi/swag/netutils v0.26.1 h1:BNctoc39WTAUMxyAs355fExOPzMZtPbZ0ZZ1Am2FR5M= +github.com/go-openapi/swag/netutils v0.26.1/go.mod h1:y02vByhZhQPAVwOX+0KipXFZ/hUbk6G/Enhf5rGaOkQ= +github.com/go-openapi/swag/stringutils v0.26.1 h1:f88uYyTso7TnHrKM/bUBsQ5e2wKf37cpgo6pvbzd9yU= +github.com/go-openapi/swag/stringutils v0.26.1/go.mod h1:Sc6d3bU8fgk5AyZR8/8jEQ+Is/Ald+TD/IIggPN8UJk= +github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3cBarXa3OVnU= +github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o= +github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk= +github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M= +github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8= +github.com/go-openapi/testify/enable/yaml/v2 v2.5.1/go.mod h1:JW0MXIotCYps/XsgJnG3a8Q7rE5xAiBwoOD5OfaIQBk= +github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo= +github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= @@ -125,24 +125,24 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= -github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= +github.com/google/pprof v0.0.0-20260604005048-7023385849c0 h1:h1QTMDl6q9wDvDCJVpKQSjgleGFYnd2fOxmg2K+6BGE= +github.com/google/pprof v0.0.0-20260604005048-7023385849c0/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ironcore-dev/gardener-extension-provider-ironcore-metal v0.1.0 h1:I2fjxQn1INGXDV3tYUOPj1s7+xOfroyaDBXPq6xcm+A= -github.com/ironcore-dev/gardener-extension-provider-ironcore-metal v0.1.0/go.mod h1:gE9P8Zl1WCRjWD5GPaLanNgTUyvpcztxHfhdLy1zh3M= +github.com/ironcore-dev/gardener-extension-provider-ironcore-metal v0.1.1-0.20260610093013-d6bdd61f63ae h1:yX0t1s2FGJ1IGkiO9ndl795kRZiHvKv/yR7B/YhYEF4= +github.com/ironcore-dev/gardener-extension-provider-ironcore-metal v0.1.1-0.20260610093013-d6bdd61f63ae/go.mod h1:/RuV/SnSSyug+o56NgX39e0rh5Ai5sVCVIOFZU3lHUg= github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -150,8 +150,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU= github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= -github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -185,22 +185,24 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.23.3-0.20260602051030-3537b20ac86b h1:QNV54DNcRqdeECNdEXiOqTmI75w2rlZtOq5rt8RKhVo= -github.com/prometheus/client_golang v1.23.3-0.20260602051030-3537b20ac86b/go.mod h1:kPaff19KETV3GKIZJehgPmlA2Di3jNeWdgKA9RpObuU= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.68.0 h1:8rQJvQmYltsR2L7h8Zw0Iyj8WYNNmpwikoQTZXwfVeA= -github.com/prometheus/common v0.68.0/go.mod h1:4soH+U8yJSROk7OJ//hmTiWKsxapv6zRGgTt3keN8gQ= +github.com/prometheus/common v0.68.1 h1:omjRRl4QP4komogpXuhfeOiisQg7xdy8VM1UY+pStaY= +github.com/prometheus/common v0.68.1/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y= github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos= github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -256,46 +258,48 @@ go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 h1:dkBzNEAIKADEaFnuESzcXv go.opentelemetry.io/contrib/bridges/prometheus v0.67.0/go.mod h1:Z5RIwRkZgauOIfnG5IpidvLpERjhTninpP1dTG2jTl4= go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 h1:4fnRcNpc6YFtG3zsFw9achKn3XgmxPxuMuqIL5rE8e8= go.opentelemetry.io/contrib/exporters/autoexport v0.67.0/go.mod h1:qTvIHMFKoxW7HXg02gm6/Wofhq5p3Ib/A/NNt1EoBSQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= -go.opentelemetry.io/otel/exporters/prometheus v0.65.0 h1:jOveH/b4lU9HT7y+Gfamf18BqlOuz2PWEvs8yM7Q6XE= -go.opentelemetry.io/otel/exporters/prometheus v0.65.0/go.mod h1:i1P8pcumauPtUI4YNopea1dhzEMuEqWP1xoUZDylLHo= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 h1:GJkybS+crDMdExT/BUNCEgfrmfboztcS6PhvSo88HKM= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0/go.mod h1:NuAyxRYIG2lKX3YQkB+83StTxM7s52PUUkRRiC0wnYI= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 h1:TC+BewnDpeiAmcscXbGMfxkO+mwYUwE/VySwvw88PfA= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0/go.mod h1:J/ZyF4vfPwsSr9xJSPyQ4LqtcTPULFR64KwTikGLe+A= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/exporters/prometheus v0.64.0 h1:g0LRDXMX/G1SEZtK8zl8Chm4K6GBwRkjPKE36LxiTYs= +go.opentelemetry.io/otel/exporters/prometheus v0.64.0/go.mod h1:UrgcjnarfdlBDP3GjDIJWe6HTprwSazNjwsI+Ru6hro= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 h1:KJVjPD3rcPb98rIs3HznyJlrfx9ge5oJvxxlGR+P/7s= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0/go.mod h1:K3kRa2ckmHWQaTWQdPRHc7qGXASuVuoEQXzrvlA98Ws= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 h1:lSZHgNHfbmQTPfuTmWVkEu8J8qXaQwuV30pjCcAUvP8= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0/go.mod h1:so9ounLcuoRDu033MW/E0AD4hhUjVqswrMF5FoZlBcw= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1JF26knRneorus8aOwVIDhvYx9WoDw= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs= go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= +go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -310,10 +314,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= -golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= -golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= -golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= @@ -329,13 +333,13 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= @@ -344,12 +348,12 @@ gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d h1:/aDRtSZJjyLQzm75d+a1wOJaqyKBMvIAfeQmoa3ORiI= -google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:etfGUgejTiadZAUaEP14NP97xi1RGeawqkjDARA/UOs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 h1:tEkOQcXgF6dH1G+MVKZrfpYvozGrzb91k6ha7jireSM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/genproto/googleapis/api v0.0.0-20260608224507-4308a22a1bab h1:Foefixyu0l973HSYkX8Etw/fPxAmKRhyMGwuqXFiVI0= +google.golang.org/genproto/googleapis/api v0.0.0-20260608224507-4308a22a1bab/go.mod h1:KdNqO+rCIWgFumrNBSEDlDNrkrQnpkax7Tv1WxNY8V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab h1:cY0oV1VnAqvaim8VsR8ZyEKAudzbRJMRGwD3W/L7yOw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -376,8 +380,8 @@ k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25 h1:mPMaPMpBij2V1Wv/fR+HW124vVGXXvOSS9ver/9yjWs= +k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= oras.land/oras-go/v2 v2.6.1 h1:bonOEkjLfp8tt6qXWRRWP6p1F+9octchOf2EqnWB4Zs= @@ -388,7 +392,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.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo= +sigs.k8s.io/structured-merge-diff/v6 v6.4.0/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/main.go b/main.go index a35a49a..a3d4f4f 100644 --- a/main.go +++ b/main.go @@ -34,11 +34,13 @@ func init() { func main() { var kubecontext string + var enableMachineImageCapabilities bool opts := zap.Options{ Development: true, TimeEncoder: zapcore.ISO8601TimeEncoder, } flag.StringVar(&kubecontext, "kubecontext", "", "The context to use from the kubeconfig (defaults to current-context)") + flag.BoolVar(&enableMachineImageCapabilities, "enable-machine-image-capabilities", false, "When enabled, cloud-profile-sync writes GEP-33 CapabilityFlavors in providerConfig alongside legacy entries") opts.BindFlags(flag.CommandLine) flag.Parse() @@ -58,7 +60,8 @@ func main() { ctx := ctrl.SetupSignalHandler() reconciler := controllers.Reconciler{ - Client: mgr.GetClient(), + Client: mgr.GetClient(), + EnableCapabilities: enableMachineImageCapabilities, } if err := reconciler.SetupWithManager(mgr); err != nil { setupLog.Error(err, "problem setting up ManagedCloudProfile reconciler")