Skip to content

feat: Add GEP-33 capability flavors support for OpenStack CloudProfiles - #58

Open
ptember wants to merge 2 commits into
cobaltcore-dev:masterfrom
ptember:openstack-gep33-capability-flavors
Open

ptember wants to merge 2 commits into
cobaltcore-dev:masterfrom
ptember:openstack-gep33-capability-flavors

Conversation

@ptember

@ptember ptember commented Sep 23, 2026 •

Copy link
Copy Markdown

Summary

Adds GEP-33 capability flavors support for OpenStack CloudProfiles in cloud-profile-sync. The goal is structural parity with IronCore — not because capability-based image selection is functionally relevant for OpenStack today, but to eliminate a maintenance gap between the two providers.

  • Populate CleanVersion and Capabilities on Glance SourceImage so the capability path in ImageUpdater and OpenStackProvider has data to work with
  • Add EnableCapabilities field and capabilityFlavors dual-write to OpenStackProvider, mirroring the IronCore pattern with per-region UUIDs instead of a single OCI image reference
  • Wire EnableCapabilities through the controller to OpenStackProvider

EnableCapabilities bool
}

func capabilitiesEqual(a, b gardencorev1beta1.Capabilities) bool {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have already this func in ossync/os_image_updater.go:134 file. Shall we reuse it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Thanks!

})
}
flavor := &entry.CapabilityFlavors[flavorIdx]
regionIdx := slices.IndexFunc(flavor.Regions, func(m openstackv1alpha1.RegionIDMapping) bool {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it will re-sort the regions of every flavor on every src iteration. Only the flavor at flavorIdx was touched.
Sort only the modified flavor's regions, not all. I'm assuming something like:
slices.SortFunc(entry.CapabilityFlavors[flavorIdx].Regions, ...)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But each src has it's own copy of regions. So we need to sort all regions for each src

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Version: version,
CleanVersion: version,
Architectures: []string{"amd64"},
Capabilities: gardenerv1beta1.Capabilities{ossync.ArchitectureCapability: []string{"amd64"}},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acceptable for now since OpenStack is amd64-only, but worth a // TODO: derive from namePrefix when arm64 is added comment so it's not silently wrong later

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no test exercising two source images with different capability sets producing two CapabilityFlavors entries on the same version. That scenario is impossible with the current Glance source (all images hardcode amd64), but the provider code supports it and it's the hardest path through the merge logic. Should be added to prevent regressions if multi-arch is introduced

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added TestConfigureCapabilitiesMultipleFlavorsOnSameVersion. Also added several other tests: TestUpsertRegion (table-driven, 7 cases), sort stability tests for both legacy regions and flavor regions, and TestConfigureCapabilitiesMultipleVersionsWithFlavors

Comment on lines +403 to +404
regionDE = "eu-de-1"
regionNL = "eu-nl-1"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have just

region1 = "region1"
region2 = "region2"

})
}
flavor := &entry.CapabilityFlavors[flavorIdx]
regionIdx := slices.IndexFunc(flavor.Regions, func(m openstackv1alpha1.RegionIDMapping) bool {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But each src has it's own copy of regions. So we need to sort all regions for each src

})
} else {
flavor.Regions[regionIdx].ID = r.ID
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is exactly same logic is a little bit earlier. Let's introduce helper function

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted as upsertRegion. Both call sites (legacy entry.Regions and capability flavor.Regions) now use it. Unit tests for the helper live in TestUpsertRegion in provider_test.go.

Signed-off-by: Palina Tember <palina.tember@sap.com>
Signed-off-by: Palina Tember <palina.tember@sap.com>
@ptember
ptember force-pushed the openstack-gep33-capability-flavors branch from c7926ae to bb41319 Compare September 25, 2026 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants