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
Original file line number Diff line number Diff line change
Expand Up @@ -172,24 +172,24 @@ func TestCountCommitments(t *testing.T) {
{
name: "Single commitment",
request: newCommitmentRequest("az-a", false, 1234,
createCommitment("ram_hana_1", "project-A", "uuid-1", "confirmed", 2),
createCommitment("hw_version_hana_1_ram", "project-A", "uuid-1", "confirmed", 2),
),
expected: 1,
},
{
name: "Multiple commitments same project",
request: newCommitmentRequest("az-a", false, 1234,
createCommitment("ram_hana_1", "project-A", "uuid-1", "confirmed", 2),
createCommitment("ram_hana_2", "project-A", "uuid-2", "confirmed", 2),
createCommitment("hw_version_hana_1_ram", "project-A", "uuid-1", "confirmed", 2),
createCommitment("hw_version_hana_2_ram", "project-A", "uuid-2", "confirmed", 2),
),
expected: 2,
},
{
name: "Multiple commitments multiple projects",
request: newCommitmentRequest("az-a", false, 1234,
createCommitment("ram_hana_1", "project-A", "uuid-1", "confirmed", 2),
createCommitment("ram_hana_1", "project-B", "uuid-2", "confirmed", 3),
createCommitment("ram_gp_1", "project-C", "uuid-3", "confirmed", 1),
createCommitment("hw_version_hana_1_ram", "project-A", "uuid-1", "confirmed", 2),
createCommitment("hw_version_hana_1_ram", "project-B", "uuid-2", "confirmed", 3),
createCommitment("hw_version_gp_1_ram", "project-C", "uuid-3", "confirmed", 1),
),
expected: 3,
},
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion internal/scheduling/reservations/commitments/api_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (api *HTTPAPI) buildServiceInfo(ctx context.Context, logger logr.Logger) (l
// Build resources map
resources := make(map[liquid.ResourceName]liquid.ResourceInfo)
for groupName, groupData := range flavorGroups {
resourceName := liquid.ResourceName(commitmentResourceNamePrefix + groupName)
resourceName := liquid.ResourceName(ResourceNameFromFlavorGroup(groupName))

flavorNames := make([]string, 0, len(groupData.Flavors))
for _, flavor := range groupData.Flavors {
Expand Down
24 changes: 12 additions & 12 deletions internal/scheduling/reservations/commitments/api_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,38 +218,38 @@ func TestHandleInfo_HasCapacityEqualsHandlesCommitments(t *testing.T) {
t.Fatalf("expected 2 resources, got %d", len(serviceInfo.Resources))
}

// Test fixed ratio group: ram_hana_fixed
fixedResource, ok := serviceInfo.Resources["ram_hana_fixed"]
// Test fixed ratio group: hw_version_hana_fixed_ram
fixedResource, ok := serviceInfo.Resources["hw_version_hana_fixed_ram"]
if !ok {
t.Fatal("expected ram_hana_fixed resource to exist")
t.Fatal("expected hw_version_hana_fixed_ram resource to exist")
}
if !fixedResource.HasCapacity {
t.Error("ram_hana_fixed: expected HasCapacity=true")
t.Error("hw_version_hana_fixed_ram: expected HasCapacity=true")
}
if !fixedResource.HandlesCommitments {
t.Error("ram_hana_fixed: expected HandlesCommitments=true (fixed ratio group)")
t.Error("hw_version_hana_fixed_ram: expected HandlesCommitments=true (fixed ratio group)")
}
if fixedResource.HasCapacity != fixedResource.HandlesCommitments {
t.Errorf("ram_hana_fixed: HasCapacity (%v) should equal HandlesCommitments (%v)",
t.Errorf("hw_version_hana_fixed_ram: HasCapacity (%v) should equal HandlesCommitments (%v)",
fixedResource.HasCapacity, fixedResource.HandlesCommitments)
}

// Test variable ratio group: ram_v2_variable
variableResource, ok := serviceInfo.Resources["ram_v2_variable"]
// Test variable ratio group: hw_version_v2_variable_ram
variableResource, ok := serviceInfo.Resources["hw_version_v2_variable_ram"]
if !ok {
t.Fatal("expected ram_v2_variable resource to exist")
t.Fatal("expected hw_version_v2_variable_ram resource to exist")
}
// Variable ratio groups don't accept commitments, and we only report capacity for groups
// that accept commitments, so both HasCapacity and HandlesCommitments should be false
if variableResource.HasCapacity {
t.Error("ram_v2_variable: expected HasCapacity=false (variable ratio groups don't report capacity)")
t.Error("hw_version_v2_variable_ram: expected HasCapacity=false (variable ratio groups don't report capacity)")
}
if variableResource.HandlesCommitments {
t.Error("ram_v2_variable: expected HandlesCommitments=false (variable ratio group)")
t.Error("hw_version_v2_variable_ram: expected HandlesCommitments=false (variable ratio group)")
}
// Verify HasCapacity == HandlesCommitments for consistency
if variableResource.HasCapacity != variableResource.HandlesCommitments {
t.Errorf("ram_v2_variable: HasCapacity (%v) should equal HandlesCommitments (%v)",
t.Errorf("hw_version_v2_variable_ram: HasCapacity (%v) should equal HandlesCommitments (%v)",
variableResource.HasCapacity, variableResource.HandlesCommitments)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ func TestCapacityCalculator(t *testing.T) {
t.Fatalf("Expected 1 resource, got %d", len(report.Resources))
}

resource := report.Resources[liquid.ResourceName("ram_test-group")]
resource := report.Resources[liquid.ResourceName("hw_version_test-group_ram")]
if resource == nil {
t.Fatal("Expected ram_test-group resource to exist")
t.Fatal("Expected hw_version_test-group_ram resource to exist")
}

// Should have empty perAZ map when no host details
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func TestReportUsageIntegration(t *testing.T) {
Reservations: []*UsageTestReservation{},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {Usage: 0, VMs: []ExpectedVMUsage{}},
},
Expand All @@ -77,7 +77,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 4, // 4096 MB / 1024 MB = 4 units
Expand All @@ -99,7 +99,7 @@ func TestReportUsageIntegration(t *testing.T) {
Reservations: []*UsageTestReservation{}, // No commitments
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 4,
Expand Down Expand Up @@ -127,7 +127,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 12, // 12 units total
Expand Down Expand Up @@ -157,7 +157,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 12,
Expand Down Expand Up @@ -187,7 +187,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 13, // 1 + 4 + 8 = 13 units
Expand Down Expand Up @@ -216,7 +216,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 8,
Expand All @@ -243,7 +243,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a", "az-b"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 4,
Expand Down Expand Up @@ -275,7 +275,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 4, // 4096 MB / 1024 MB = 4 units
Expand All @@ -285,7 +285,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
},
},
"ram_gp_1": {
"hw_version_gp_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 4, // 2048 MB / 512 MB = 4 units
Expand Down Expand Up @@ -332,7 +332,7 @@ func TestReportUsageIntegration(t *testing.T) {
},
AllAZs: []string{"az-a"},
Expected: map[string]ExpectedResourceUsage{
"ram_hana_1": {
"hw_version_hana_1_ram": {
PerAZ: map[string]ExpectedAZUsage{
"az-a": {
Usage: 4,
Expand Down
4 changes: 2 additions & 2 deletions internal/scheduling/reservations/commitments/capacity.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ func (c *CapacityCalculator) CalculateCapacity(ctx context.Context) (liquid.Serv
continue
}

// Resource name follows pattern: ram_<flavorgroup>
resourceName := liquid.ResourceName(commitmentResourceNamePrefix + groupName)
// Resource name follows pattern: hw_version_<flavorgroup>_ram
resourceName := liquid.ResourceName(ResourceNameFromFlavorGroup(groupName))

// Calculate per-AZ capacity and usage
azCapacity, err := c.calculateAZCapacity(ctx, groupName, groupData)
Expand Down
24 changes: 20 additions & 4 deletions internal/scheduling/reservations/commitments/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,30 @@ import (
// commitmentUUIDPattern validates commitment UUID format.
var commitmentUUIDPattern = regexp.MustCompile(`^[a-zA-Z0-9-]{6,40}$`)

// Limes LIQUID resource naming convention: ram_<flavorgroup>
const commitmentResourceNamePrefix = "ram_"
// Limes LIQUID resource naming convention: hw_version_<flavorgroup>_ram
const (
resourceNamePrefix = "hw_version_"
resourceNameSuffix = "_ram"
)

// ResourceNameFromFlavorGroup creates a LIQUID resource name from a flavor group name.
// Format: hw_version_<flavorgroup>_ram
func ResourceNameFromFlavorGroup(flavorGroup string) string {
return resourceNamePrefix + flavorGroup + resourceNameSuffix
}

func getFlavorGroupNameFromResource(resourceName string) (string, error) {
if !strings.HasPrefix(resourceName, commitmentResourceNamePrefix) {
if !strings.HasPrefix(resourceName, resourceNamePrefix) || !strings.HasSuffix(resourceName, resourceNameSuffix) {
return "", fmt.Errorf("invalid resource name: %s", resourceName)
}
return strings.TrimPrefix(resourceName, commitmentResourceNamePrefix), nil
// Remove prefix and suffix
name := strings.TrimPrefix(resourceName, resourceNamePrefix)
name = strings.TrimSuffix(name, resourceNameSuffix)
// Validate that the extracted group name is not empty
if name == "" {
return "", fmt.Errorf("invalid resource name: %s (empty group name)", resourceName)
}
return name, nil
}

// CommitmentState represents desired or current commitment resource allocation.
Expand Down
32 changes: 27 additions & 5 deletions internal/scheduling/reservations/commitments/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestFromCommitment_CalculatesMemoryCorrectly(t *testing.T) {
commitment := Commitment{
UUID: "test-uuid",
ProjectID: "project-1",
ResourceName: "ram_test-group",
ResourceName: "hw_version_test-group_ram",
Amount: 5, // 5 multiples of smallest flavor
}

Expand Down Expand Up @@ -236,7 +236,8 @@ func TestFromReservations_NonCommittedResourceType(t *testing.T) {
}

func TestGetFlavorGroupNameFromResource_Valid(t *testing.T) {
name, err := getFlavorGroupNameFromResource("ram_hana_medium_v2")
// Test valid resource names with underscores in flavor group
name, err := getFlavorGroupNameFromResource("hw_version_hana_medium_v2_ram")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -246,8 +247,29 @@ func TestGetFlavorGroupNameFromResource_Valid(t *testing.T) {
}

func TestGetFlavorGroupNameFromResource_Invalid(t *testing.T) {
_, err := getFlavorGroupNameFromResource("invalid_resource")
if err == nil {
t.Fatal("expected error for invalid resource name, got nil")
invalidCases := []string{
"ram_2101", // old format
"invalid", // completely wrong
"hw_version__ram", // empty group name
"hw_version_2101", // missing suffix
}
for _, input := range invalidCases {
if _, err := getFlavorGroupNameFromResource(input); err == nil {
t.Errorf("expected error for %q, got nil", input)
}
}
}

func TestResourceNameRoundTrip(t *testing.T) {
// Test that ResourceNameFromFlavorGroup and getFlavorGroupNameFromResource are inverses
for _, groupName := range []string{"2101", "hana_1", "hana_medium_v2"} {
resourceName := ResourceNameFromFlavorGroup(groupName)
recovered, err := getFlavorGroupNameFromResource(resourceName)
if err != nil {
t.Fatalf("round-trip failed for %q: %v", groupName, err)
}
if recovered != groupName {
t.Errorf("round-trip mismatch: %q -> %q -> %q", groupName, resourceName, recovered)
}
}
}
7 changes: 1 addition & 6 deletions internal/scheduling/reservations/commitments/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package commitments
import (
"context"
"fmt"
"strings"
"time"

"github.com/cobaltcore-dev/cortex/api/v1alpha1"
Expand Down Expand Up @@ -90,12 +89,8 @@ func (s *Syncer) getCommitmentStates(ctx context.Context, log logr.Logger, flavo
log.Info("skipping non-compute commitment", "id", id, "serviceType", commitment.ServiceType)
continue
}
if !strings.HasPrefix(commitment.ResourceName, commitmentResourceNamePrefix) {
log.Info("skipping non-RAM-flavor-group commitment", "id", id, "resourceName", commitment.ResourceName)
continue
}

// Extract flavor group name from resource name
// Extract flavor group name from resource name (validates format: hw_version_<group>_ram)
flavorGroupName, err := getFlavorGroupNameFromResource(commitment.ResourceName)
if err != nil {
log.Info("skipping commitment with invalid resource name",
Expand Down
10 changes: 5 additions & 5 deletions internal/scheduling/reservations/commitments/syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func TestSyncer_SyncReservations_InstanceCommitments(t *testing.T) {
ID: 1,
UUID: "12345-67890-abcdef",
ServiceType: "compute",
ResourceName: "ram_test_group_v1",
ResourceName: "hw_version_test_group_v1_ram",
AvailabilityZone: "az1",
Amount: 2, // 2 multiples of smallest flavor (2 * 1024MB = 2048MB total)
Unit: "",
Expand Down Expand Up @@ -357,7 +357,7 @@ func TestSyncer_SyncReservations_UpdateExisting(t *testing.T) {
ID: 1,
UUID: "12345-67890-abcdef",
ServiceType: "compute",
ResourceName: "ram_new_group_v1",
ResourceName: "hw_version_new_group_v1_ram",
AvailabilityZone: "az1",
Amount: 1,
Unit: "",
Expand Down Expand Up @@ -459,7 +459,7 @@ func TestSyncer_SyncReservations_UnitMismatch(t *testing.T) {
ID: 1,
UUID: "unit-mismatch-test-uuid",
ServiceType: "compute",
ResourceName: "ram_test_group_v1",
ResourceName: "hw_version_test_group_v1_ram",
AvailabilityZone: "az1",
Amount: 2,
Unit: "2048 MiB", // Mismatched unit - should be "1024 MiB"
Expand Down Expand Up @@ -543,7 +543,7 @@ func TestSyncer_SyncReservations_UnitMatch(t *testing.T) {
ID: 1,
UUID: "unit-match-test-uuid",
ServiceType: "compute",
ResourceName: "ram_test_group_v1",
ResourceName: "hw_version_test_group_v1_ram",
AvailabilityZone: "az1",
Amount: 2,
Unit: "1024 MiB", // Correct unit matching smallest flavor
Expand Down Expand Up @@ -623,7 +623,7 @@ func TestSyncer_SyncReservations_EmptyUUID(t *testing.T) {
ID: 1,
UUID: "", // Empty UUID
ServiceType: "compute",
ResourceName: "ram_test_group_v1",
ResourceName: "hw_version_test_group_v1_ram",
AvailabilityZone: "az1",
Amount: 1,
Unit: "",
Expand Down
2 changes: 1 addition & 1 deletion internal/scheduling/reservations/commitments/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ func (c *UsageCalculator) buildUsageResponse(
if !FlavorGroupAcceptsCommitments(&groupData) {
continue
}
resourceName := liquid.ResourceName(commitmentResourceNamePrefix + flavorGroupName)
resourceName := liquid.ResourceName(ResourceNameFromFlavorGroup(flavorGroupName))

perAZ := make(map[liquid.AvailabilityZone]*liquid.AZResourceUsageReport)

Expand Down
Loading
Loading