From 8567852e51552707166cf3cc98a4d592a519f1de Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Thu, 23 Jul 2026 10:47:17 +0200
Subject: [PATCH 1/2] Skip image property filtering for internal scheduling
intents
Signed-off-by: Philipp Matthes
---
.../filters/filter_image_properties.go | 24 ++++++++++++
.../filters/filter_image_properties_test.go | 39 +++++++++++++++++++
2 files changed, 63 insertions(+)
diff --git a/internal/scheduling/nova/plugins/filters/filter_image_properties.go b/internal/scheduling/nova/plugins/filters/filter_image_properties.go
index 7ce083f87..2fe1ada44 100644
--- a/internal/scheduling/nova/plugins/filters/filter_image_properties.go
+++ b/internal/scheduling/nova/plugins/filters/filter_image_properties.go
@@ -6,8 +6,10 @@ package filters
import (
"context"
"log/slog"
+ "slices"
api "github.com/cobaltcore-dev/cortex/api/external/nova"
+ "github.com/cobaltcore-dev/cortex/api/v1alpha1"
"github.com/cobaltcore-dev/cortex/internal/scheduling/lib"
hv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1"
)
@@ -19,6 +21,26 @@ type FilterImagePropertiesStep struct {
// Filter hosts based on image properties given in the request spec.
func (s *FilterImagePropertiesStep) Run(traceLog *slog.Logger, request api.ExternalSchedulerRequest) (*lib.FilterWeigherPipelineStepResult, error) {
result := s.IncludeAllHostsFromRequest(request)
+
+ // Apply this filter to all requests, unless we know from the request's
+ // intent that image metadata is expected to not be set.
+ if intent, err := request.GetIntent(); err == nil {
+ intentsExpectedToNotHaveImageMeta := []v1alpha1.SchedulingIntent{
+ // Cortex-internal intents in which scheduling requests are sent
+ // mainly based on flavor-related metadata, independent of the
+ // image that'll land there.
+ api.ReserveForFailoverIntent,
+ api.ReuseFailoverReservationIntent,
+ api.ReserveForCommittedResourceIntent,
+ api.CapacityProbeIntent,
+ }
+ if slices.Contains(intentsExpectedToNotHaveImageMeta, intent) {
+ traceLog.Debug("skipping filter: expected to have no image metadata",
+ "intent", intent)
+ return result, nil
+ }
+ }
+
// If the image properties indicate any other hypervisor type than kvm,
// we filter out all known kvm hypervisors.
hvType, err := request.Spec.Data.Image.Data.GetHypervisorType()
@@ -32,6 +54,7 @@ func (s *FilterImagePropertiesStep) Run(traceLog *slog.Logger, request api.Exter
result.Events = append(result.Events, "image_properties_hv_type_undetermined")
return result, nil
}
+
if hvType != api.NovaImageMetaHVTypeKVM {
traceLog.Info("filtering out all known kvm hypervisors since image properties indicate a different hypervisor type",
"image_hypervisor_type", hvType)
@@ -45,6 +68,7 @@ func (s *FilterImagePropertiesStep) Run(traceLog *slog.Logger, request api.Exter
traceLog.Debug("filtering host which is kvm hypervisor", "host", hv.Name)
}
}
+
return result, nil
}
diff --git a/internal/scheduling/nova/plugins/filters/filter_image_properties_test.go b/internal/scheduling/nova/plugins/filters/filter_image_properties_test.go
index c4370e79e..64dd4bb26 100644
--- a/internal/scheduling/nova/plugins/filters/filter_image_properties_test.go
+++ b/internal/scheduling/nova/plugins/filters/filter_image_properties_test.go
@@ -27,6 +27,15 @@ func requestWith(hosts []string, properties map[string]any) api.ExternalSchedule
return request
}
+// requestWithIntent builds an ExternalSchedulerRequest like requestWith, but
+// additionally sets the _nova_check_type scheduler hint so GetIntent resolves
+// to the given intent.
+func requestWithIntent(hosts []string, properties map[string]any, checkType string) api.ExternalSchedulerRequest {
+ request := requestWith(hosts, properties)
+ request.Spec.Data.SchedulerHints = map[string]any{"_nova_check_type": checkType}
+ return request
+}
+
func TestFilterImagePropertiesStep_Run(t *testing.T) {
scheme := runtime.NewScheme()
if err := hv1.AddToScheme(scheme); err != nil {
@@ -81,6 +90,36 @@ func TestFilterImagePropertiesStep_Run(t *testing.T) {
expectedHosts: []string{},
filteredHosts: []string{},
},
+ {
+ name: "reserve_for_failover intent skips filter and keeps all hosts",
+ request: requestWithIntent([]string{"host1", "host2", "host3"}, map[string]any{"hypervisor_type": "vmware"}, "reserve_for_failover"),
+ expectedHosts: []string{"host1", "host2", "host3"},
+ filteredHosts: []string{},
+ },
+ {
+ name: "reuse_failover_reservation intent skips filter and keeps all hosts",
+ request: requestWithIntent([]string{"host1", "host2", "host3"}, map[string]any{"hypervisor_type": "vmware"}, "reuse_failover_reservation"),
+ expectedHosts: []string{"host1", "host2", "host3"},
+ filteredHosts: []string{},
+ },
+ {
+ name: "reserve_for_committed_resource intent skips filter and keeps all hosts",
+ request: requestWithIntent([]string{"host1", "host2", "host3"}, map[string]any{"hypervisor_type": "vmware"}, "reserve_for_committed_resource"),
+ expectedHosts: []string{"host1", "host2", "host3"},
+ filteredHosts: []string{},
+ },
+ {
+ name: "capacity_probe intent skips filter and keeps all hosts",
+ request: requestWithIntent([]string{"host1", "host2", "host3"}, map[string]any{"hypervisor_type": "vmware"}, "capacity_probe"),
+ expectedHosts: []string{"host1", "host2", "host3"},
+ filteredHosts: []string{},
+ },
+ {
+ name: "create intent still filters out known kvm hypervisors",
+ request: requestWithIntent([]string{"host1", "host2", "host3"}, map[string]any{"hypervisor_type": "vmware"}, "create"),
+ expectedHosts: []string{"host3"},
+ filteredHosts: []string{"host1", "host2"},
+ },
}
for _, tt := range tests {
From b96286d7888362f18772877d924b63eb239cb92a Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Thu, 23 Jul 2026 10:55:11 +0200
Subject: [PATCH 2/2] Bonus: instruct pr-creator agent to sign-off on commits
Signed-off-by: Philipp Matthes
---
.claude/agents/pull-request-creator.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.claude/agents/pull-request-creator.md b/.claude/agents/pull-request-creator.md
index 94bd2d596..f5223ea40 100644
--- a/.claude/agents/pull-request-creator.md
+++ b/.claude/agents/pull-request-creator.md
@@ -61,9 +61,11 @@ If `git stash pop` reports conflicts, abort and surface them — something on th
```
git add -A
-git commit -m ""
+git commit -s -m ""
```
+Note: the `-s` adds a Signed-off-by trailer to the commit message. This is required for all commits in this project.
+
## Step 5: Push
```