Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .claude/agents/pull-request-creator.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ If `git stash pop` reports conflicts, abort and surface them — something on th

```
git add -A
git commit -m "<commit_message>"
git commit -s -m "<commit_message>"
```

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

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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()
Expand All @@ -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)
Expand All @@ -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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down