diff --git a/pkg/apis/internal.admin.acorn.io/v1/baseresources.go b/pkg/apis/internal.admin.acorn.io/v1/baseresources.go index f5db33062..58c66ebab 100644 --- a/pkg/apis/internal.admin.acorn.io/v1/baseresources.go +++ b/pkg/apis/internal.admin.acorn.io/v1/baseresources.go @@ -1,9 +1,10 @@ package v1 import ( - "errors" "fmt" "strings" + + "k8s.io/apimachinery/pkg/api/resource" ) // BaseResources defines resources that should be tracked at any scoped. The two main exclusions @@ -15,10 +16,9 @@ type BaseResources struct { Volumes int `json:"volumes"` Images int `json:"images"` - // ComputeClasses and VolumeClasses are used to track the amount of compute and volume storage per their - // respective classes - ComputeClasses ComputeClassResources `json:"computeClasses"` - VolumeClasses VolumeClassResources `json:"volumeClasses"` + VolumeStorage resource.Quantity `json:"volumeStorage"` + Memory resource.Quantity `json:"memory"` + CPU resource.Quantity `json:"cpu"` } // Add will add the BaseResources of another BaseResources struct into the current one. @@ -29,14 +29,9 @@ func (current *BaseResources) Add(incoming BaseResources) { current.Volumes = Add(current.Volumes, incoming.Volumes) current.Images = Add(current.Images, incoming.Images) - if current.ComputeClasses == nil { - current.ComputeClasses = ComputeClassResources{} - } - if current.VolumeClasses == nil { - current.VolumeClasses = VolumeClassResources{} - } - current.ComputeClasses.Add(incoming.ComputeClasses) - current.VolumeClasses.Add(incoming.VolumeClasses) + current.VolumeStorage = AddQuantity(current.VolumeStorage, incoming.VolumeStorage) + current.Memory = AddQuantity(current.Memory, incoming.Memory) + current.CPU = AddQuantity(current.CPU, incoming.CPU) } // Remove will remove the BaseResources of another BaseResources struct from the current one. Calling remove @@ -47,9 +42,13 @@ func (current *BaseResources) Remove(incoming BaseResources, all bool) { current.Jobs = Sub(current.Jobs, incoming.Jobs) current.Volumes = Sub(current.Volumes, incoming.Volumes) current.Images = Sub(current.Images, incoming.Images) - current.ComputeClasses.Remove(incoming.ComputeClasses) + + current.Memory = SubQuantity(current.Memory, incoming.Memory) + current.CPU = SubQuantity(current.CPU, incoming.CPU) + + // Only remove persistent resources if all is true. if all { - current.VolumeClasses.Remove(incoming.VolumeClasses) + current.VolumeStorage = SubQuantity(current.VolumeStorage, incoming.VolumeStorage) } } @@ -59,7 +58,6 @@ func (current *BaseResources) Remove(incoming BaseResources, all bool) { // If the current BaseResources defines unlimited, then it will always fit. func (current *BaseResources) Fits(incoming BaseResources) error { var exceededResources []string - var errs []error // Check if any of the resources are exceeded for _, r := range []struct { @@ -77,26 +75,31 @@ func (current *BaseResources) Fits(incoming BaseResources) error { } } - if len(exceededResources) != 0 { - errs = append(errs, fmt.Errorf("%w: %s", ErrExceededResources, strings.Join(exceededResources, ", "))) - } - - if err := current.ComputeClasses.Fits(incoming.ComputeClasses); err != nil { - errs = append(errs, err) + // Check if any of the quantity resources are exceeded + for _, r := range []struct { + resource string + current, incoming resource.Quantity + }{ + {"VolumeStorage", current.VolumeStorage, incoming.VolumeStorage}, + {"Memory", current.Memory, incoming.Memory}, + {"Cpu", current.CPU, incoming.CPU}, + } { + if !FitsQuantity(r.current, r.incoming) { + exceededResources = append(exceededResources, r.resource) + } } - if err := current.VolumeClasses.Fits(incoming.VolumeClasses); err != nil { - errs = append(errs, err) + // Build an aggregated error message for the exceeded resources + if len(exceededResources) > 0 { + return fmt.Errorf("%w: %s", ErrExceededResources, strings.Join(exceededResources, ", ")) } - // Build an aggregated error message for the exceeded resources - return errors.Join(errs...) + return nil } // ToString will return a string representation of the BaseResources within the struct. func (current *BaseResources) ToString() string { - // make sure that an empty string doesn't have a comma - result := CountResourcesToString( + return ResourcesToString( map[string]int{ "Apps": current.Apps, "Containers": current.Containers, @@ -104,24 +107,11 @@ func (current *BaseResources) ToString() string { "Volumes": current.Volumes, "Images": current.Images, }, - ) - - for _, resource := range []struct { - name string - asString string - }{ - {"ComputeClasses", current.ComputeClasses.ToString()}, - {"VolumeClasses", current.VolumeClasses.ToString()}, - } { - if result != "" && resource.asString != "" { - result += ", " - } - if resource.asString != "" { - result += fmt.Sprintf("%s: %s", resource.name, resource.asString) - } - } - - return result + map[string]resource.Quantity{ + "VolumeStorage": current.VolumeStorage, + "Memory": current.Memory, + "Cpu": current.CPU, + }) } // Equals will check if the current BaseResources struct is equal to another. This is useful @@ -132,6 +122,7 @@ func (current *BaseResources) Equals(incoming BaseResources) bool { current.Jobs == incoming.Jobs && current.Volumes == incoming.Volumes && current.Images == incoming.Images && - current.ComputeClasses.Equals(incoming.ComputeClasses) && - current.VolumeClasses.Equals(incoming.VolumeClasses) + current.VolumeStorage.Cmp(incoming.VolumeStorage) == 0 && + current.Memory.Cmp(incoming.Memory) == 0 && + current.CPU.Cmp(incoming.CPU) == 0 } diff --git a/pkg/apis/internal.admin.acorn.io/v1/baseresources_test.go b/pkg/apis/internal.admin.acorn.io/v1/baseresources_test.go index cd657ad7f..27a7b1ae7 100644 --- a/pkg/apis/internal.admin.acorn.io/v1/baseresources_test.go +++ b/pkg/apis/internal.admin.acorn.io/v1/baseresources_test.go @@ -17,86 +17,79 @@ func TestBaseResourcesAdd(t *testing.T) { expected BaseResources }{ { - name: "add to empty BaseResources resources", - current: BaseResources{}, - incoming: BaseResources{Apps: 1}, - expected: BaseResources{Apps: 1}, - }, - { - name: "add to existing BaseResources resources", - current: BaseResources{Apps: 1}, + name: "add to empty BaseResources resources", + current: BaseResources{}, incoming: BaseResources{ - Apps: 1, - Images: 1, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, expected: BaseResources{ - Apps: 2, - Images: 1, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, }, { - name: "add where current has a resource specified with unlimited", - current: BaseResources{Apps: Unlimited}, - incoming: BaseResources{Apps: 1}, - expected: BaseResources{Apps: Unlimited}, - }, - { - name: "add where incoming has a resource specified with unlimited", - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: Unlimited}, - expected: BaseResources{Apps: Unlimited}, + name: "add to existing BaseResources resources", + current: BaseResources{ + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + Apps: 1, + Images: 1, + VolumeStorage: resource.MustParse("1Mi"), + CPU: resource.MustParse("20m"), + }, + expected: BaseResources{ + Apps: 2, + Images: 1, + VolumeStorage: resource.MustParse("2Mi"), + CPU: resource.MustParse("20m"), + }, }, { - name: "add where current and incoming have a resource specified with unlimited", - current: BaseResources{Apps: Unlimited}, - incoming: BaseResources{Apps: Unlimited}, - expected: BaseResources{Apps: Unlimited}, + name: "add where current has a resource specified with unlimited", + current: BaseResources{ + Apps: Unlimited, + Memory: UnlimitedQuantity(), + }, + incoming: BaseResources{ + Apps: 1, + Memory: resource.MustParse("1Mi"), + }, + expected: BaseResources{ + Apps: Unlimited, + Memory: UnlimitedQuantity(), + }, }, { - name: "add where current and incoming have ComputeClasses and VolumeClasses", + name: "add where incoming has a resource specified with unlimited", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, incoming: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, expected: BaseResources{ - Apps: 2, Containers: 2, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - CPU: resource.MustParse("2m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, }, { - name: "add where current is empty and incoming has ComputeClasses and VolumeClasses", - current: BaseResources{}, + name: "add where current and incoming have a resource specified with unlimited", + current: BaseResources{ + Apps: Unlimited, + Memory: UnlimitedQuantity(), + }, incoming: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, expected: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, }, } @@ -120,73 +113,107 @@ func TestBaseResourcesRemove(t *testing.T) { expected BaseResources }{ { - name: "remove from empty BaseResources resources", - current: BaseResources{}, - incoming: BaseResources{Apps: 1}, + name: "remove from empty BaseResources resources", + current: BaseResources{}, + incoming: BaseResources{ + Apps: 1, + Memory: resource.MustParse("1Mi"), + }, expected: BaseResources{}, }, { - name: "remove from existing BaseResources resources", - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: 1}, + name: "remove from existing BaseResources resources", + current: BaseResources{ + Apps: 1, + Memory: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + Apps: 1, + Memory: resource.MustParse("1Mi"), + }, expected: BaseResources{}, }, { - name: "should never get negative values", - all: true, - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: 2}, + name: "should never get negative values", + all: true, + current: BaseResources{ + Apps: 1, + Memory: resource.MustParse("1Mi"), + VolumeStorage: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + Apps: 2, + Memory: resource.MustParse("2Mi"), + VolumeStorage: resource.MustParse("2Mi"), + }, expected: BaseResources{}, }, { - name: "remove where current has a resource specified with unlimited", - current: BaseResources{Apps: Unlimited}, - incoming: BaseResources{Apps: 1}, - expected: BaseResources{Apps: Unlimited}, - }, - { - name: "remove where incoming has a resource specified with unlimited", - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: Unlimited}, - expected: BaseResources{Apps: 1}, + name: "remove persistent resources with all", + current: BaseResources{ + VolumeStorage: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + VolumeStorage: resource.MustParse("1Mi"), + }, + all: true, + expected: BaseResources{}, }, { - name: "remove where current and incoming have a resource specified with unlimited", - current: BaseResources{Apps: Unlimited}, - incoming: BaseResources{Apps: Unlimited}, - expected: BaseResources{Apps: Unlimited}, + name: "does not remove persistent resources without all", + current: BaseResources{ + VolumeStorage: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + VolumeStorage: resource.MustParse("1Mi"), + }, + expected: BaseResources{ + VolumeStorage: resource.MustParse("1Mi"), + }, }, { - name: "remove where current and incoming have ComputeClasses and VolumeClasses", + name: "remove where current has a resource specified with unlimited", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, incoming: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), + }, + expected: BaseResources{ + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, - all: true, - expected: BaseResources{}, }, { - name: "does not remove volume storage when all is false", + name: "remove where incoming has a resource specified with unlimited", + current: BaseResources{ + Apps: 1, + Memory: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + Apps: Unlimited, + Memory: UnlimitedQuantity(), + }, expected: BaseResources{ - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, + }, + { + name: "remove where current and incoming have a resource specified with unlimited", current: BaseResources{ - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, incoming: BaseResources{ - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), + }, + expected: BaseResources{ + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, }, } @@ -215,62 +242,40 @@ func TestBaseResourcesEquals(t *testing.T) { expected: true, }, { - name: "equal BaseResources resources", - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: 1}, - expected: true, - }, - { - name: "unequal BaseResources resources", - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: 2}, - expected: false, - }, - { - name: "equal BaseResources resources with unlimited values", - current: BaseResources{Apps: Unlimited}, - incoming: BaseResources{Apps: Unlimited}, + name: "equal BaseResources resources", + current: BaseResources{ + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), + }, expected: true, }, { - name: "equal BaseResources with ComputeClasses and VolumeClasses", + name: "unequal BaseResources resources", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, incoming: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: 2, + VolumeStorage: resource.MustParse("1Mi"), }, - expected: true, + expected: false, }, { - name: "unequal BaseResources with ComputeClasses and VolumeClasses", + name: "equal BaseResources resources with unlimited values", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), }, incoming: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), }, - expected: false, + expected: true, }, } @@ -296,64 +301,61 @@ func TestBaseResourcesFits(t *testing.T) { incoming: BaseResources{}, }, { - name: "fits BaseResources", - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: 1}, + name: "fits BaseResources", + current: BaseResources{ + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), + }, }, { - name: "does not fit BaseResources resources", - current: BaseResources{Apps: 1}, - incoming: BaseResources{Apps: 2}, + name: "does not fit BaseResources resources", + current: BaseResources{ + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), + }, + incoming: BaseResources{ + Apps: 2, + VolumeStorage: resource.MustParse("1Mi"), + }, expectedErr: ErrExceededResources, }, { - name: "fits BaseResources resources with specified unlimited values", - current: BaseResources{Apps: Unlimited}, - incoming: BaseResources{Apps: 2}, - }, - { - name: "fits count BaseResources resources with specified unlimited values but not others", - current: BaseResources{Jobs: 0, Apps: Unlimited}, - incoming: BaseResources{Jobs: 2, Apps: 2}, - expectedErr: ErrExceededResources, + name: "fits BaseResources resources with specified unlimited values", + current: BaseResources{ + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), + }, + incoming: BaseResources{ + Apps: 2, + VolumeStorage: resource.MustParse("2Mi"), + }, }, { - name: "fits BaseResources with ComputeClasses and VolumeClasses", + name: "fits count BaseResources resources with specified unlimited values but not others", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Jobs: 0, + Apps: Unlimited, }, incoming: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + Jobs: 2, + Apps: 2, }, + expectedErr: ErrExceededResources, }, + { - name: "does not fit exceeding ComputeClasses and VolumeClasses", + name: "fits quantity BaseResources resources with specified unlimited values but not others", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, + VolumeStorage: UnlimitedQuantity(), }, incoming: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - CPU: resource.MustParse("2m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, + CPU: resource.MustParse("100m"), + VolumeStorage: resource.MustParse("2Mi"), }, expectedErr: ErrExceededResources, }, @@ -383,47 +385,20 @@ func TestBaseResourcesToString(t *testing.T) { expected: "", }, { - name: "populated BaseResources", - current: BaseResources{Apps: 1, Containers: 1}, - expected: "Apps: 1, Containers: 1", - }, - { - name: "populated BaseResources with unlimited values", - current: BaseResources{Apps: Unlimited, Containers: 1}, - expected: "Apps: unlimited, Containers: 1", - }, - { - name: "populated with ComputeClasses and VolumeClasses", + name: "populated BaseResources", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - VolumeClasses: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - }, - expected: "Apps: 1, Containers: 1, ComputeClasses: \"foo\": { Memory: 1Mi, CPU: 1m }, VolumeClasses: \"foo\": { VolumeStorage: 1Mi }", + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), + }, + expected: "Apps: 1, VolumeStorage: 1Mi", }, { - name: "populated with multiple ComputeClasses and VolumeClasses", + name: "populated BaseResources with unlimited values", current: BaseResources{ - Apps: 1, Containers: 1, - ComputeClasses: ComputeClassResources{ - "foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }, - "bar": { - Memory: resource.MustParse("2Mi"), - CPU: resource.MustParse("2m"), - }, - }, - VolumeClasses: VolumeClassResources{ - "foo": {resource.MustParse("1Mi")}, - "bar": {resource.MustParse("2Mi")}, - }, - }, - expected: "Apps: 1, Containers: 1, ComputeClasses: \"bar\": { Memory: 2Mi, CPU: 2m }, \"foo\": { Memory: 1Mi, CPU: 1m }, VolumeClasses: \"bar\": { VolumeStorage: 2Mi }, \"foo\": { VolumeStorage: 1Mi }", + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), + }, + expected: "Apps: unlimited, VolumeStorage: unlimited", }, } diff --git a/pkg/apis/internal.admin.acorn.io/v1/computeclassresources.go b/pkg/apis/internal.admin.acorn.io/v1/computeclassresources.go deleted file mode 100644 index 9ea66620b..000000000 --- a/pkg/apis/internal.admin.acorn.io/v1/computeclassresources.go +++ /dev/null @@ -1,150 +0,0 @@ -package v1 - -import ( - "fmt" - "strings" - - "github.com/acorn-io/baaah/pkg/typed" - "k8s.io/apimachinery/pkg/api/resource" -) - -// AllComputeClasses is a constant that can be used to define a ComputeResources struct that will apply to all -// ComputeClasses. This should only be used when defining a ComputeClassResources struct that is meant to be used -// as a limit and not a usage. The Fits method will work as expected when using this constant but Add and Remove -// do not interact with it. -const AllComputeClasses = "*" - -type ComputeResources struct { - Memory resource.Quantity `json:"memory,omitempty"` - CPU resource.Quantity `json:"cpu,omitempty"` -} - -func (current *ComputeResources) Equals(incoming ComputeResources) bool { - return current.Memory.Cmp(incoming.Memory) == 0 && current.CPU.Cmp(incoming.CPU) == 0 -} - -func (current *ComputeResources) ToString() string { - var resourceStrings []string - - for _, r := range []struct { - resource string - value resource.Quantity - }{ - {"Memory", current.Memory}, - {"CPU", current.CPU}, - } { - switch { - case r.value.CmpInt64(0) > 0: - resourceStrings = append(resourceStrings, fmt.Sprintf("%s: %s", r.resource, r.value.String())) - case r.value.Equal(comparableUnlimitedQuantity): - resourceStrings = append(resourceStrings, fmt.Sprintf("%s: unlimited", r.resource)) - } - } - - return strings.Join(resourceStrings, ", ") -} - -type ComputeClassResources map[string]ComputeResources - -// Add will add the ComputeClassResources of another ComputeClassResources struct into the current one. -func (current ComputeClassResources) Add(incoming ComputeClassResources) { - for computeClass, resources := range incoming { - c := current[computeClass] - c.Memory = AddQuantity(c.Memory, resources.Memory) - c.CPU = AddQuantity(c.CPU, resources.CPU) - current[computeClass] = c - } -} - -// Remove will remove the ComputeClassResources of another ComputeClassResources struct from the current one. Calling remove -// will be a no-op for any resource values that are set to unlimited. -func (current ComputeClassResources) Remove(incoming ComputeClassResources) { - for computeClass, resources := range incoming { - if _, ok := current[computeClass]; !ok { - continue - } - - c := current[computeClass] - c.Memory = SubQuantity(c.Memory, resources.Memory) - c.CPU = SubQuantity(c.CPU, resources.CPU) - - // Don't keep empty ComputeClasses - if c.Equals(ComputeResources{}) { - delete(current, computeClass) - } else { - current[computeClass] = c - } - } -} - -// Fits will check if a group of ComputeClassResources will be able to contain -// another group of ComputeClassResources. If the ComputeClassResources are not able to fit, -// an aggregated error will be returned with all exceeded ComputeClassResources. -// If the current ComputeClassResources defines unlimited, then it will always fit. -func (current ComputeClassResources) Fits(incoming ComputeClassResources) error { - var exceededResources []string - - // Check if any of the quantity resources are exceeded - for computeClass, resources := range incoming { - // If a specific compute class is defined on current then we check if it will - // fit the incoming resources. If is not defined, then we check if the current - // resources has AllComputeClasses defined and if so, we check if the incoming - // resources will fit those. If neither are defined, then we deny the request - // by appending the compute class to the exceeded resources and continuing. - if _, ok := current[computeClass]; !ok { - if _, ok := current[AllComputeClasses]; ok { - computeClass = AllComputeClasses - } - } - - var ccExceededResources []string - for _, r := range []struct { - resource string - current, incoming resource.Quantity - }{ - {"Memory", current[computeClass].Memory, resources.Memory}, - {"CPU", current[computeClass].CPU, resources.CPU}, - } { - if !FitsQuantity(r.current, r.incoming) { - ccExceededResources = append(ccExceededResources, r.resource) - } - } - if len(ccExceededResources) > 0 { - exceededResources = append(exceededResources, fmt.Sprintf("%q: %s", computeClass, strings.Join(ccExceededResources, ", "))) - } - } - - // Build an aggregated error message for the exceeded resources - if len(exceededResources) > 0 { - return fmt.Errorf("%w: ComputeClasses: %s", ErrExceededResources, strings.Join(exceededResources, ", ")) - } - - return nil -} - -// ToString will return a string representation of the ComputeClassResources within the struct. -func (current ComputeClassResources) ToString() string { - var resourceStrings []string - - for _, entry := range typed.Sorted(current) { - resourceStrings = append(resourceStrings, fmt.Sprintf("%q: { %s }", entry.Key, entry.Value.ToString())) - } - - return strings.Join(resourceStrings, ", ") -} - -// Equals will check if the current ComputeClassResources struct is equal to another. This is useful -// to avoid needing to do a deep equal on the entire struct. -func (current ComputeClassResources) Equals(incoming ComputeClassResources) bool { - if len(current) != len(incoming) { - return false - } - - for computeClass, resources := range incoming { - if cc, ok := current[computeClass]; !ok || !cc.Equals(resources) { - return false - } - } - - return true -} diff --git a/pkg/apis/internal.admin.acorn.io/v1/computeclassresources_test.go b/pkg/apis/internal.admin.acorn.io/v1/computeclassresources_test.go deleted file mode 100644 index a84199cda..000000000 --- a/pkg/apis/internal.admin.acorn.io/v1/computeclassresources_test.go +++ /dev/null @@ -1,454 +0,0 @@ -package v1 - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/api/resource" -) - -func TestComputeClassResourcesAdd(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current ComputeClassResources - incoming ComputeClassResources - expected ComputeClassResources - }{ - { - name: "add to empty ComputeClassResources resources", - current: ComputeClassResources{}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - }, - { - name: "add to existing ComputeClassResources resources", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - }}, - }, - { - name: "add where current has a resource specified with unlimited", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - }, - { - name: "add where incoming has a resource specified with unlimited", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - expected: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - }, - { - name: "add where current and incoming have a resource specified with unlimited", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - incoming: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - expected: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - }, - { - name: "add where current and incoming have AllComputeClasses specified at non-unlimited values", - current: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("2Mi"), - }}, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - tc.current.Add(tc.incoming) - assert.True(t, tc.current.Equals(tc.expected)) - }) - } -} - -func TestComputeClassResourcesRemove(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current ComputeClassResources - incoming ComputeClassResources - expected ComputeClassResources - }{ - { - name: "remove from empty ComputeClassResources resources", - current: ComputeClassResources{}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{}, - }, - { - name: "resulting empty does not remove other non-empty ComputeClassResources resources", - current: ComputeClassResources{ - "foo": {Memory: resource.MustParse("1Mi")}, - "bar": {Memory: resource.MustParse("2Mi")}, - }, - incoming: ComputeClassResources{ - "foo": {Memory: resource.MustParse("1Mi")}, - "bar": {Memory: resource.MustParse("1Mi")}, - }, - expected: ComputeClassResources{ - "bar": {Memory: resource.MustParse("1Mi")}, - }, - }, - { - name: "remove from existing ComputeClassResources resources", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{}, - }, - { - name: "should never get negative values", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - }}, - expected: ComputeClassResources{}, - }, - { - name: "remove where current has a resource specified with unlimited", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - }, - { - name: "remove where incoming has a resource specified with unlimited", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - expected: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - }, - { - name: "remove where current and incoming have a resource specified with unlimited", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - incoming: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - expected: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - }, - { - name: "remove where current and incoming have a AllComputeClasses specified with non-unlimited values", - current: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("2Mi"), - }}, - incoming: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("1Mi"), - }}, - expected: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("1Mi"), - }}, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - tc.current.Remove(tc.incoming) - assert.True(t, tc.current.Equals(tc.expected)) - }) - } -} - -func TestComputeClassResourcesEquals(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current ComputeClassResources - incoming ComputeClassResources - expected bool - }{ - { - name: "empty ComputeClassResources resources", - current: ComputeClassResources{}, - incoming: ComputeClassResources{}, - expected: true, - }, - { - name: "equal ComputeClassResources resources", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expected: true, - }, - { - name: "unequal ComputeClassResources resources", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - }}, - expected: false, - }, - { - name: "equal ComputeClassResources resources with unlimited values", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - incoming: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - expected: true, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expected, tc.current.Equals(tc.incoming)) - }) - } -} - -func TestComputeClassResourcesFits(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current ComputeClassResources - incoming ComputeClassResources - expectedErr error - }{ - { - name: "empty ComputeClassResources resources", - current: ComputeClassResources{}, - incoming: ComputeClassResources{}, - }, - { - name: "fits ComputeClassResources", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - }, - { - name: "fits when incoming is empty", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - }, - { - name: "does not fit when current is empty", - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - expectedErr: ErrExceededResources, - }, - { - name: "does not fit ComputeClassResources resources", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - }}, - expectedErr: ErrExceededResources, - }, - { - name: "fits ComputeClassResources resources with specified unlimited values", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - }}, - }, - { - name: "fits quantity ComputeClassResources resources with specified unlimited values but not others", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - CPU: resource.MustParse("1m"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - CPU: resource.MustParse("2m"), - }}, - expectedErr: ErrExceededResources, - }, - { - name: "fits ComputeClassResources with AllComputeClasses specified but not others", - current: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("2Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - }}, - }, - { - name: "fits ComputeClassResources with AllComputeClasses specified and others", - current: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{ - "foo": { - Memory: resource.MustParse("1Mi"), - }, - "bar": { - Memory: resource.MustParse("1Mi"), - }, - }, - }, - { - name: "fits ComputeClassResources with AllComputeClasses specified and others with unlimited set", - current: ComputeClassResources{AllComputeClasses: { - Memory: UnlimitedQuantity(), - }}, - incoming: ComputeClassResources{ - "foo": { - Memory: resource.MustParse("1Mi"), - }, - "bar": { - Memory: resource.MustParse("1Mi"), - }, - }, - }, - { - name: "does not fit ComputeClassResources with AllComputeClasses specified that is not enough", - current: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{"foo": { - Memory: resource.MustParse("2Mi"), - }}, - expectedErr: ErrExceededResources, - }, - { - name: "does not fit ComputeClassResources with AllComputeClasses if one incoming exceeds the resources", - current: ComputeClassResources{AllComputeClasses: { - Memory: resource.MustParse("1Mi"), - }}, - incoming: ComputeClassResources{ - "foo": { - Memory: resource.MustParse("2Mi"), - }, - "bar": { - Memory: resource.MustParse("1Mi"), - }, - }, - expectedErr: ErrExceededResources, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.current.Fits(tc.incoming) - if !errors.Is(err, tc.expectedErr) { - t.Errorf("expected %v, got %v", tc.expectedErr, err) - } - }) - } -} - -func TestComputeClassResourcesToString(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current ComputeClassResources - expected string - }{ - { - name: "empty ComputeClassResources", - current: ComputeClassResources{}, - expected: "", - }, - { - name: "populated ComputeClassResources", - current: ComputeClassResources{"foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }}, - expected: "\"foo\": { Memory: 1Mi, CPU: 1m }", - }, - { - name: "populated ComputeClassResources with unlimited values", - current: ComputeClassResources{"foo": { - Memory: UnlimitedQuantity(), - CPU: UnlimitedQuantity(), - }}, - expected: "\"foo\": { Memory: unlimited, CPU: unlimited }", - }, - { - name: "multiple populated ComputeClassResources", - current: ComputeClassResources{ - "foo": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1m"), - }, - "bar": { - Memory: resource.MustParse("2Mi"), - CPU: resource.MustParse("2m"), - }, - }, - expected: "\"bar\": { Memory: 2Mi, CPU: 2m }, \"foo\": { Memory: 1Mi, CPU: 1m }", - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expected, tc.current.ToString()) - }) - } -} diff --git a/pkg/apis/internal.admin.acorn.io/v1/quotarequests.go b/pkg/apis/internal.admin.acorn.io/v1/quotarequests.go index ffa24da0e..4f57d2fe1 100644 --- a/pkg/apis/internal.admin.acorn.io/v1/quotarequests.go +++ b/pkg/apis/internal.admin.acorn.io/v1/quotarequests.go @@ -110,8 +110,9 @@ func (current *QuotaRequestResources) Fits(incoming QuotaRequestResources) error // ToString will return a string representation of the QuotaRequestResources within the struct. func (current *QuotaRequestResources) ToString() string { - result := CountResourcesToString( + result := ResourcesToString( map[string]int{"Secrets": current.Secrets}, + nil, ) if result != "" { diff --git a/pkg/apis/internal.admin.acorn.io/v1/quotarequests_test.go b/pkg/apis/internal.admin.acorn.io/v1/quotarequests_test.go index ebc46f2ea..0dff933c3 100644 --- a/pkg/apis/internal.admin.acorn.io/v1/quotarequests_test.go +++ b/pkg/apis/internal.admin.acorn.io/v1/quotarequests_test.go @@ -21,17 +21,15 @@ func TestQuotaRequestResourcesAdd(t *testing.T) { current: QuotaRequestResources{}, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -40,27 +38,26 @@ func TestQuotaRequestResourcesAdd(t *testing.T) { name: "add to existing QuotaRequestResources", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {CPU: resource.MustParse("20m")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - Images: 1, - ComputeClasses: ComputeClassResources{"compute-class": {CPU: resource.MustParse("20m")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Images: 1, + VolumeStorage: resource.MustParse("1Mi"), + CPU: resource.MustParse("20m"), }, Secrets: 1, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 2, - Images: 1, - ComputeClasses: ComputeClassResources{"compute-class": {CPU: resource.MustParse("40m")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("2Mi")}}, + Apps: 2, + Images: 1, + VolumeStorage: resource.MustParse("2Mi"), + CPU: resource.MustParse("20m"), }, Secrets: 2, }, @@ -69,25 +66,22 @@ func TestQuotaRequestResourcesAdd(t *testing.T) { name: "add where current has a resource specified with unlimited", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, Secrets: 1, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, @@ -96,25 +90,22 @@ func TestQuotaRequestResourcesAdd(t *testing.T) { name: "add where incoming has a resource specified with unlimited", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, @@ -123,25 +114,22 @@ func TestQuotaRequestResourcesAdd(t *testing.T) { name: "add where current and incoming have a resource specified with unlimited", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, @@ -169,9 +157,8 @@ func TestQuotaRequestResourcesRemove(t *testing.T) { current: QuotaRequestResources{}, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -182,17 +169,17 @@ func TestQuotaRequestResourcesRemove(t *testing.T) { all: true, current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 2, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("2Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("2Mi")}}, + Apps: 2, + Memory: resource.MustParse("2Mi"), + VolumeStorage: resource.MustParse("2Mi"), }, Secrets: 2, }, @@ -204,15 +191,13 @@ func TestQuotaRequestResourcesRemove(t *testing.T) { name: "removes persistent resources with all", current: QuotaRequestResources{ BaseResources: BaseResources{ - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -225,21 +210,19 @@ func TestQuotaRequestResourcesRemove(t *testing.T) { name: "does not remove persistent resources without all", current: QuotaRequestResources{ BaseResources: BaseResources{ - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -248,25 +231,22 @@ func TestQuotaRequestResourcesRemove(t *testing.T) { name: "remove where current has a resource specified with unlimited", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, Secrets: 1, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, @@ -275,25 +255,22 @@ func TestQuotaRequestResourcesRemove(t *testing.T) { name: "remove where incoming has a resource specified with unlimited", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, Secrets: Unlimited, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Memory: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -302,23 +279,20 @@ func TestQuotaRequestResourcesRemove(t *testing.T) { name: "remove where current and incoming have a resource specified with unlimited", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, }, expected: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + Memory: UnlimitedQuantity(), }, }, }, @@ -349,17 +323,15 @@ func TestQuotaRequestResourcesEquals(t *testing.T) { name: "equal QuotaRequestResources", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -369,17 +341,15 @@ func TestQuotaRequestResourcesEquals(t *testing.T) { name: "unequal QuotaRequestResources only", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, }, expected: false, @@ -388,18 +358,16 @@ func TestQuotaRequestResourcesEquals(t *testing.T) { name: "unequal base resources only", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - Containers: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + Containers: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -409,17 +377,15 @@ func TestQuotaRequestResourcesEquals(t *testing.T) { name: "unequal QuotaRequestResources", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 2, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 2, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 2, }, @@ -429,17 +395,15 @@ func TestQuotaRequestResourcesEquals(t *testing.T) { name: "equal QuotaRequestResources with unlimited values", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), }, Secrets: Unlimited, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), }, Secrets: Unlimited, }, @@ -470,17 +434,15 @@ func TestQuotaRequestResourcesFits(t *testing.T) { name: "fits BaseResources", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, @@ -489,17 +451,15 @@ func TestQuotaRequestResourcesFits(t *testing.T) { name: "does not fit QuotaRequestResources", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 2, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 2, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 2, }, @@ -519,16 +479,14 @@ func TestQuotaRequestResourcesFits(t *testing.T) { name: "false as expected with only base resources", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 2, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("1Mi")}}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 2, + VolumeStorage: resource.MustParse("1Mi"), }, }, expectedErr: ErrExceededResources, @@ -537,16 +495,15 @@ func TestQuotaRequestResourcesFits(t *testing.T) { name: "fits QuotaRequestResources with specified unlimited values", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), }, Secrets: Unlimited, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 2, - ComputeClasses: ComputeClassResources{"compute-class": {Memory: resource.MustParse("2Mi")}}, + Apps: 2, + VolumeStorage: resource.MustParse("2Mi"), }, Secrets: 2, }, @@ -573,13 +530,13 @@ func TestQuotaRequestResourcesFits(t *testing.T) { name: "fits quantity QuotaRequestResources with specified unlimited values but not others", current: QuotaRequestResources{ BaseResources: BaseResources{ - ComputeClasses: ComputeClassResources{"compute-class": {Memory: UnlimitedQuantity()}}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + VolumeStorage: UnlimitedQuantity(), }, }, incoming: QuotaRequestResources{ BaseResources: BaseResources{ - ComputeClasses: ComputeClassResources{"compute-class": {CPU: resource.MustParse("100m")}}, + CPU: resource.MustParse("100m"), + VolumeStorage: resource.MustParse("2Mi"), }, }, expectedErr: ErrExceededResources, @@ -612,31 +569,23 @@ func TestQuotaRequestResourcesToString(t *testing.T) { name: "populated BaseResources", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: 1, - ComputeClasses: ComputeClassResources{"compute-class": { - Memory: resource.MustParse("1Mi"), - CPU: resource.MustParse("1Mi"), - }}, - VolumeClasses: VolumeClassResources{"volume-class": {resource.MustParse("1Mi")}}, + Apps: 1, + VolumeStorage: resource.MustParse("1Mi"), }, Secrets: 1, }, - expected: "Secrets: 1, Apps: 1, ComputeClasses: \"compute-class\": { Memory: 1Mi, CPU: 1Mi }, VolumeClasses: \"volume-class\": { VolumeStorage: 1Mi }", + expected: "Secrets: 1, Apps: 1, VolumeStorage: 1Mi", }, { name: "populated BaseResources with unlimited values", current: QuotaRequestResources{ BaseResources: BaseResources{ - Apps: Unlimited, - ComputeClasses: ComputeClassResources{"compute-class": { - Memory: UnlimitedQuantity(), - CPU: UnlimitedQuantity(), - }}, - VolumeClasses: VolumeClassResources{"volume-class": {UnlimitedQuantity()}}, + Apps: Unlimited, + VolumeStorage: UnlimitedQuantity(), }, Secrets: Unlimited, }, - expected: "Secrets: unlimited, Apps: unlimited, ComputeClasses: \"compute-class\": { Memory: unlimited, CPU: unlimited }, VolumeClasses: \"volume-class\": { VolumeStorage: unlimited }", + expected: "Secrets: unlimited, Apps: unlimited, VolumeStorage: unlimited", }, } diff --git a/pkg/apis/internal.admin.acorn.io/v1/resources.go b/pkg/apis/internal.admin.acorn.io/v1/resources.go index 130711871..689885170 100644 --- a/pkg/apis/internal.admin.acorn.io/v1/resources.go +++ b/pkg/apis/internal.admin.acorn.io/v1/resources.go @@ -64,7 +64,7 @@ func SubQuantity(c, i resource.Quantity) resource.Quantity { } c.Sub(i) if c.CmpInt64(0) < 0 { - return *resource.NewQuantity(0, c.Format) + c.Set(0) } return c } @@ -83,9 +83,9 @@ func FitsQuantity(current, incoming resource.Quantity) bool { return true } -// CountResourcesToString will return a string representation of the resource and value +// ResourceToString will return a string representation of the resource and value // if its value is greater than 0. -func CountResourcesToString(resources map[string]int) string { +func ResourcesToString(resources map[string]int, quantityResources map[string]resource.Quantity) string { var resourceStrings []string for _, resource := range typed.Sorted(resources) { @@ -97,15 +97,14 @@ func CountResourcesToString(resources map[string]int) string { } } - return strings.Join(resourceStrings, ", ") -} - -func QuantityResourceToString(name string, quantity resource.Quantity) string { - switch { - case quantity.CmpInt64(0) > 0: - return fmt.Sprintf("%s: %s", name, quantity.String()) - case quantity.Equal(comparableUnlimitedQuantity): - return fmt.Sprintf("%s: unlimited", name) + for _, resource := range typed.Sorted(quantityResources) { + switch { + case resource.Value.CmpInt64(0) > 0: + resourceStrings = append(resourceStrings, fmt.Sprintf("%s: %s", resource.Key, resource.Value.String())) + case resource.Value.Equal(comparableUnlimitedQuantity): + resourceStrings = append(resourceStrings, fmt.Sprintf("%s: unlimited", resource.Key)) + } } - return "" + + return strings.Join(resourceStrings, ", ") } diff --git a/pkg/apis/internal.admin.acorn.io/v1/volumeclassresources.go b/pkg/apis/internal.admin.acorn.io/v1/volumeclassresources.go deleted file mode 100644 index a6bee278a..000000000 --- a/pkg/apis/internal.admin.acorn.io/v1/volumeclassresources.go +++ /dev/null @@ -1,119 +0,0 @@ -package v1 - -import ( - "fmt" - "strings" - - "github.com/acorn-io/baaah/pkg/typed" - "k8s.io/apimachinery/pkg/api/resource" -) - -// AllVolumeClasses is a constant that can be used to define a VolumeResources struct that will apply to all -// VolumeClasses. This should only be used when defining a VolumeClassResources struct that is meant to be used -// as a limit and not a usage. The Fits method will work as expected when using this constant but Add and Remove -// do not interact with it. -const AllVolumeClasses = "*" - -type VolumeResources struct { - VolumeStorage resource.Quantity `json:"volumeStorage"` -} - -func (current *VolumeResources) ToString() string { - switch { - case current.VolumeStorage.CmpInt64(0) > 0: - return "VolumeStorage: " + current.VolumeStorage.String() - case current.VolumeStorage.Equal(comparableUnlimitedQuantity): - return "VolumeStorage: unlimited" - } - return "" -} - -type VolumeClassResources map[string]VolumeResources - -// Add will add the VolumeClassResources of another VolumeClassResources struct into the current one. -func (current VolumeClassResources) Add(incoming VolumeClassResources) { - for volumeClass, resources := range incoming { - c := current[volumeClass] - c.VolumeStorage = AddQuantity(c.VolumeStorage, resources.VolumeStorage) - current[volumeClass] = c - } -} - -// Remove will remove the VolumeClassResources of another VolumeClassResources struct from the current one. Calling remove -// will be a no-op for any resource values that are set to unlimited. -func (current VolumeClassResources) Remove(incoming VolumeClassResources) { - for volumeClass, resources := range incoming { - if _, ok := current[volumeClass]; !ok { - continue - } - - c := current[volumeClass] - c.VolumeStorage = SubQuantity(c.VolumeStorage, resources.VolumeStorage) - - // Don't keep empty VolumeClasses - if c.VolumeStorage.CmpInt64(0) == 0 { - delete(current, volumeClass) - } else { - current[volumeClass] = c - } - } -} - -// Fits will check if a group of VolumeClassResources will be able to contain -// another group of VolumeClassResources. If the VolumeClassResources are not able to fit, -// an aggregated error will be returned with all exceeded VolumeClassResources. -// If the current VolumeClassResources defines unlimited, then it will always fit. -func (current VolumeClassResources) Fits(incoming VolumeClassResources) error { - var exceededResources []string - - // Check if any of the quantity resources are exceeded - for volumeClass, resources := range incoming { - // If a specific volume class is defined on current then we check if it will - // fit the incoming resources. If is not defined, then we check if the current - // resources has AllVolumeClasses defined and if so, we check if the incoming - // resources will fit those. If neither are defined, then we deny the request - // by appending the volume class to the exceeded resources and continuing. - if _, ok := current[volumeClass]; !ok { - if _, ok := current[AllVolumeClasses]; ok { - volumeClass = AllVolumeClasses - } - } - - if !FitsQuantity(current[volumeClass].VolumeStorage, resources.VolumeStorage) { - exceededResources = append(exceededResources, fmt.Sprintf("%q: VolumeStorage", volumeClass)) - } - } - - // Build an aggregated error message for the exceeded resources - if len(exceededResources) > 0 { - return fmt.Errorf("%w: VolumeClasses: %s", ErrExceededResources, strings.Join(exceededResources, ", ")) - } - - return nil -} - -// ToString will return a string representation of the VolumeClassResources within the struct. -func (current VolumeClassResources) ToString() string { - var resourceStrings []string - - for _, entry := range typed.Sorted(current) { - resourceStrings = append(resourceStrings, fmt.Sprintf("%q: { %s }", entry.Key, entry.Value.ToString())) - } - - return strings.Join(resourceStrings, ", ") -} - -// Equals will check if the current VolumeClassResources struct is equal to another. This is useful -// to avoid needing to do a deep equal on the entire struct. -func (current VolumeClassResources) Equals(incoming VolumeClassResources) bool { - if len(current) != len(incoming) { - return false - } - - for volumeClass, resources := range incoming { - if c, ok := current[volumeClass]; !ok || !c.VolumeStorage.Equal(resources.VolumeStorage) { - return false - } - } - return true -} diff --git a/pkg/apis/internal.admin.acorn.io/v1/volumeclassresources_test.go b/pkg/apis/internal.admin.acorn.io/v1/volumeclassresources_test.go deleted file mode 100644 index 0de5271d8..000000000 --- a/pkg/apis/internal.admin.acorn.io/v1/volumeclassresources_test.go +++ /dev/null @@ -1,289 +0,0 @@ -package v1 - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/api/resource" -) - -func TestVolumeClassResourcesAdd(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current VolumeClassResources - incoming VolumeClassResources - expected VolumeClassResources - }{ - { - name: "add to empty VolumeClassResources resources", - current: VolumeClassResources{}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - }, - { - name: "add to existing VolumeClassResources resources", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, - }, - { - name: "add where current has a resource specified with unlimited", - current: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - }, - { - name: "add where incoming has a resource specified with unlimited", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - expected: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - }, - { - name: "add where current and incoming have a resource specified with unlimited", - current: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - incoming: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - expected: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - }, - { - name: "add where current and incoming have a AllVolumeClasses specified with non-unlimited values", - current: VolumeClassResources{AllVolumeClasses: { - VolumeStorage: resource.MustParse("1Mi"), - }}, - incoming: VolumeClassResources{AllVolumeClasses: { - VolumeStorage: resource.MustParse("1Mi"), - }}, - expected: VolumeClassResources{AllVolumeClasses: { - VolumeStorage: resource.MustParse("2Mi"), - }}, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - tc.current.Add(tc.incoming) - assert.True(t, tc.current.Equals(tc.expected)) - }) - } -} - -func TestVolumeClassResourcesRemove(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current VolumeClassResources - incoming VolumeClassResources - expected VolumeClassResources - }{ - { - name: "remove from empty VolumeClassResources resources", - current: VolumeClassResources{}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: VolumeClassResources{}, - }, - { - name: "remove from existing VolumeClassResources resources", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: VolumeClassResources{}, - }, - { - name: "should never get negative values", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, - expected: VolumeClassResources{}, - }, - { - name: "remove where current has a resource specified with unlimited", - current: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - }, - { - name: "remove where incoming has a resource specified with unlimited", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - expected: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - }, - { - name: "remove where current and incoming have a resource specified with unlimited", - current: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - incoming: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - expected: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - }, - { - name: "remove where current and incoming have a AllVolumeClasses specified with non-unlimited values", - current: VolumeClassResources{AllVolumeClasses: { - VolumeStorage: resource.MustParse("2Mi"), - }}, - incoming: VolumeClassResources{AllVolumeClasses: { - VolumeStorage: resource.MustParse("1Mi"), - }}, - expected: VolumeClassResources{AllVolumeClasses: { - VolumeStorage: resource.MustParse("1Mi"), - }}, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - tc.current.Remove(tc.incoming) - assert.True(t, tc.current.Equals(tc.expected)) - }) - } -} - -func TestVolumeClassResourcesEquals(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current VolumeClassResources - incoming VolumeClassResources - expected bool - }{ - { - name: "empty VolumeClassResources resources", - current: VolumeClassResources{}, - incoming: VolumeClassResources{}, - expected: true, - }, - { - name: "equal VolumeClassResources resources", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: true, - }, - { - name: "unequal VolumeClassResources resources", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, - expected: false, - }, - { - name: "equal VolumeClassResources resources with unlimited values", - current: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - incoming: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - expected: true, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expected, tc.current.Equals(tc.incoming)) - }) - } -} - -func TestVolumeClassResourcesFits(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current VolumeClassResources - incoming VolumeClassResources - expectedErr error - }{ - { - name: "empty VolumeClassResources resources", - current: VolumeClassResources{}, - incoming: VolumeClassResources{}, - }, - { - name: "fits VolumeClassResources", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - }, - - { - name: "does not fit VolumeClassResources resources", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, - expectedErr: ErrExceededResources, - }, - { - name: "fits VolumeClassResources resources with specified unlimited values", - current: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, - }, - { - name: "fits VolumeClassResources with AllVolumeClasses specified but not others", - current: VolumeClassResources{AllVolumeClasses: {resource.MustParse("2Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, - }, - { - name: "fits VolumeClassResources with AllVolumeClasses specified and others", - current: VolumeClassResources{AllVolumeClasses: {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{ - "foo": {resource.MustParse("1Mi")}, - "bar": {resource.MustParse("1Mi")}, - }, - }, - { - name: "fits VolumeClassResources with AllVolumeClasses specified and others with unlimited set", - current: VolumeClassResources{AllVolumeClasses: {UnlimitedQuantity()}}, - incoming: VolumeClassResources{ - "foo": {resource.MustParse("1Mi")}, - "bar": {resource.MustParse("1Mi")}, - }, - }, - { - name: "does not fit VolumeClassResources with AllVolumeClasses specified that is not enough", - current: VolumeClassResources{AllVolumeClasses: {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{"foo": {resource.MustParse("2Mi")}}, - expectedErr: ErrExceededResources, - }, - { - name: "does not fit VolumeClassResources with AllVolumeClasses if one incoming exceeds the resources", - current: VolumeClassResources{AllVolumeClasses: {resource.MustParse("1Mi")}}, - incoming: VolumeClassResources{ - "foo": {resource.MustParse("2Mi")}, - "bar": {resource.MustParse("1Mi")}, - }, - expectedErr: ErrExceededResources, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.current.Fits(tc.incoming) - if !errors.Is(err, tc.expectedErr) { - t.Errorf("expected %v, got %v", tc.expectedErr, err) - } - }) - } -} - -func TestVolumeClassResourcesToString(t *testing.T) { - // Define test cases - testCases := []struct { - name string - current VolumeClassResources - expected string - }{ - { - name: "empty VolumeClassResources", - current: VolumeClassResources{}, - expected: "", - }, - { - name: "populated VolumeClassResources", - current: VolumeClassResources{"foo": {resource.MustParse("1Mi")}}, - expected: "\"foo\": { VolumeStorage: 1Mi }", - }, - { - name: "populated VolumeClassResources with unlimited values", - current: VolumeClassResources{"foo": {UnlimitedQuantity()}}, - expected: "\"foo\": { VolumeStorage: unlimited }"}, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expected, tc.current.ToString()) - }) - } -} diff --git a/pkg/apis/internal.admin.acorn.io/v1/zz_generated.deepcopy.go b/pkg/apis/internal.admin.acorn.io/v1/zz_generated.deepcopy.go index eea2c20fd..edb131bc3 100644 --- a/pkg/apis/internal.admin.acorn.io/v1/zz_generated.deepcopy.go +++ b/pkg/apis/internal.admin.acorn.io/v1/zz_generated.deepcopy.go @@ -14,20 +14,9 @@ import ( // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BaseResources) DeepCopyInto(out *BaseResources) { *out = *in - if in.ComputeClasses != nil { - in, out := &in.ComputeClasses, &out.ComputeClasses - *out = make(ComputeClassResources, len(*in)) - for key, val := range *in { - (*out)[key] = *val.DeepCopy() - } - } - if in.VolumeClasses != nil { - in, out := &in.VolumeClasses, &out.VolumeClasses - *out = make(VolumeClassResources, len(*in)) - for key, val := range *in { - (*out)[key] = *val.DeepCopy() - } - } + out.VolumeStorage = in.VolumeStorage.DeepCopy() + out.Memory = in.Memory.DeepCopy() + out.CPU = in.CPU.DeepCopy() } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseResources. @@ -267,44 +256,6 @@ func (in *ComputeClassMemory) DeepCopy() *ComputeClassMemory { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in ComputeClassResources) DeepCopyInto(out *ComputeClassResources) { - { - in := &in - *out = make(ComputeClassResources, len(*in)) - for key, val := range *in { - (*out)[key] = *val.DeepCopy() - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComputeClassResources. -func (in ComputeClassResources) DeepCopy() ComputeClassResources { - if in == nil { - return nil - } - out := new(ComputeClassResources) - in.DeepCopyInto(out) - return *out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ComputeResources) DeepCopyInto(out *ComputeResources) { - *out = *in - out.Memory = in.Memory.DeepCopy() - out.CPU = in.CPU.DeepCopy() -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComputeResources. -func (in *ComputeResources) DeepCopy() *ComputeResources { - if in == nil { - return nil - } - out := new(ComputeResources) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ImageRoleAuthorizationInstance) DeepCopyInto(out *ImageRoleAuthorizationInstance) { *out = *in @@ -703,27 +654,6 @@ func (in *RoleRef) DeepCopy() *RoleRef { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in VolumeClassResources) DeepCopyInto(out *VolumeClassResources) { - { - in := &in - *out = make(VolumeClassResources, len(*in)) - for key, val := range *in { - (*out)[key] = *val.DeepCopy() - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeClassResources. -func (in VolumeClassResources) DeepCopy() VolumeClassResources { - if in == nil { - return nil - } - out := new(VolumeClassResources) - in.DeepCopyInto(out) - return *out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VolumeClassSize) DeepCopyInto(out *VolumeClassSize) { *out = *in @@ -738,19 +668,3 @@ func (in *VolumeClassSize) DeepCopy() *VolumeClassSize { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VolumeResources) DeepCopyInto(out *VolumeResources) { - *out = *in - out.VolumeStorage = in.VolumeStorage.DeepCopy() -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeResources. -func (in *VolumeResources) DeepCopy() *VolumeResources { - if in == nil { - return nil - } - out := new(VolumeResources) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/controller/quota/quota.go b/pkg/controller/quota/quota.go index 379630e6d..11834ed8a 100644 --- a/pkg/controller/quota/quota.go +++ b/pkg/controller/quota/quota.go @@ -124,7 +124,7 @@ func EnsureQuotaRequest(req router.Request, resp router.Response) error { // addContainers adds the number of containers and accounts for the scale of each container. func addContainers(containers map[string]v1.Container, quotaRequest *adminv1.QuotaRequestInstance) { for _, container := range containers { - quotaRequest.Spec.Resources.Containers += int(replicas(container.Scale)) + quotaRequest.Spec.Resources.Containers += replicas(container.Scale) } } @@ -139,21 +139,11 @@ func addCompute(containers map[string]v1.Container, appInstance *v1.AppInstance, requirements = all.Requirements } - computeClass := appInstance.Status.ResolvedOfferings.Containers[name].Class - - // Multiply the memory/cpu requests by the scale of the container - cpu, memory := requirements.Requests["cpu"], requirements.Requests["memory"] - cpu.Mul(replicas(container.Scale)) - memory.Mul(replicas(container.Scale)) - - // Add the compute resources to the quota request - quotaRequest.Spec.Resources.Add(adminv1.QuotaRequestResources{BaseResources: adminv1.BaseResources{ComputeClasses: adminv1.ComputeClassResources{ - computeClass: { - Memory: memory, - CPU: cpu, - }, - }, - }}) + // Add the memory/cpu requests to the quota request for each container at the scale specified + for i := 0; i < replicas(container.Scale); i++ { + quotaRequest.Spec.Resources.CPU.Add(requirements.Requests["cpu"]) + quotaRequest.Spec.Resources.Memory.Add(requirements.Requests["memory"]) + } // Recurse over any sidecars. Since sidecars can't have sidecars, this is safe. addCompute(container.Sidecars, appInstance, quotaRequest) @@ -198,11 +188,7 @@ func addStorage(req router.Request, appInstance *v1.AppInstance, quotaRequest *a sizeQuantity = parsedQuantity } - volumeClass := appInstance.Status.ResolvedOfferings.Volumes[name].Class - quotaRequest.Spec.Resources.Add(adminv1.QuotaRequestResources{ - BaseResources: adminv1.BaseResources{VolumeClasses: adminv1.VolumeClassResources{ - volumeClass: {VolumeStorage: sizeQuantity}, - }}}) + quotaRequest.Spec.Resources.VolumeStorage.Add(sizeQuantity) } // Add the secrets needed to the quota request. We only parse net new secrets, not @@ -270,9 +256,9 @@ func isEnforced(req router.Request, namespace string) (bool, error) { // replicas returns the number of replicas based on an int32 pointer. If the // pointer is nil, it is assumed to be 1. -func replicas(s *int32) int64 { +func replicas(s *int32) int { if s != nil { - return int64(*s) + return int(*s) } return 1 } diff --git a/pkg/controller/quota/testdata/basic/expected.golden b/pkg/controller/quota/testdata/basic/expected.golden index 8f8bf90b4..429072976 100644 --- a/pkg/controller/quota/testdata/basic/expected.golden +++ b/pkg/controller/quota/testdata/basic/expected.golden @@ -9,26 +9,23 @@ metadata: spec: resources: apps: 0 - computeClasses: - default-compute-class: - cpu: 250m - memory: 1Gi containers: 1 + cpu: 250m images: 0 jobs: 1 + memory: 1Gi secrets: 1 - volumeClasses: - default-volume-class: - volumeStorage: 10G + volumeStorage: 10G volumes: 1 status: allocatedResources: apps: 0 - computeClasses: null containers: 0 + cpu: "0" images: 0 jobs: 0 + memory: "0" secrets: 0 - volumeClasses: null + volumeStorage: "0" volumes: 0 ` diff --git a/pkg/controller/quota/testdata/basic/input.yaml b/pkg/controller/quota/testdata/basic/input.yaml index 5de624358..6e6680243 100644 --- a/pkg/controller/quota/testdata/basic/input.yaml +++ b/pkg/controller/quota/testdata/basic/input.yaml @@ -66,21 +66,3 @@ status: requests: cpu: 125m memory: 512Mi - resolvedOfferings: - containers: - "": - class: default-compute-class - cpuScaler: 0.25 - memory: 123456789 - container-name: - class: default-compute-class - cpuScaler: 0.25 - memory: 536870912 - sidecar-name: - class: default-compute-class - cpuScaler: 0.25 - memory: 536870912 - volumes: - test: - class: default-volume-class - size: 536870912 diff --git a/pkg/controller/quota/testdata/implicit-pv-bind/expected.golden b/pkg/controller/quota/testdata/implicit-pv-bind/expected.golden index e008774b6..7963a424e 100644 --- a/pkg/controller/quota/testdata/implicit-pv-bind/expected.golden +++ b/pkg/controller/quota/testdata/implicit-pv-bind/expected.golden @@ -9,24 +9,23 @@ metadata: spec: resources: apps: 0 - computeClasses: - "": - cpu: "0" - memory: "0" containers: 1 + cpu: "0" images: 0 jobs: 0 + memory: "0" secrets: 1 - volumeClasses: {} + volumeStorage: "0" volumes: 1 status: allocatedResources: apps: 0 - computeClasses: null containers: 0 + cpu: "0" images: 0 jobs: 0 + memory: "0" secrets: 0 - volumeClasses: null + volumeStorage: "0" volumes: 0 ` diff --git a/pkg/controller/quota/testdata/status-default-volume-size/expected.golden b/pkg/controller/quota/testdata/status-default-volume-size/expected.golden index 57409264f..71a04063a 100644 --- a/pkg/controller/quota/testdata/status-default-volume-size/expected.golden +++ b/pkg/controller/quota/testdata/status-default-volume-size/expected.golden @@ -9,26 +9,23 @@ metadata: spec: resources: apps: 0 - computeClasses: - "": - cpu: "0" - memory: "0" containers: 1 + cpu: "0" images: 0 jobs: 0 + memory: "0" secrets: 1 - volumeClasses: - "": - volumeStorage: 1Gi + volumeStorage: 1Gi volumes: 1 status: allocatedResources: apps: 0 - computeClasses: null containers: 0 + cpu: "0" images: 0 jobs: 0 + memory: "0" secrets: 0 - volumeClasses: null + volumeStorage: "0" volumes: 0 ` diff --git a/pkg/openapi/generated/openapi_generated.go b/pkg/openapi/generated/openapi_generated.go index f931e36a9..8894dd84b 100644 --- a/pkg/openapi/generated/openapi_generated.go +++ b/pkg/openapi/generated/openapi_generated.go @@ -244,7 +244,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ClusterVolumeClassInstance": schema_pkg_apis_internaladminacornio_v1_ClusterVolumeClassInstance(ref), "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ClusterVolumeClassInstanceList": schema_pkg_apis_internaladminacornio_v1_ClusterVolumeClassInstanceList(ref), "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ComputeClassMemory": schema_pkg_apis_internaladminacornio_v1_ComputeClassMemory(ref), - "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ComputeResources": schema_pkg_apis_internaladminacornio_v1_ComputeResources(ref), "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ImageRoleAuthorizationInstance": schema_pkg_apis_internaladminacornio_v1_ImageRoleAuthorizationInstance(ref), "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ImageRoleAuthorizationInstanceList": schema_pkg_apis_internaladminacornio_v1_ImageRoleAuthorizationInstanceList(ref), "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ImageRoleAuthorizationInstanceSpec": schema_pkg_apis_internaladminacornio_v1_ImageRoleAuthorizationInstanceSpec(ref), @@ -261,7 +260,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.RoleAuthorizations": schema_pkg_apis_internaladminacornio_v1_RoleAuthorizations(ref), "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.RoleRef": schema_pkg_apis_internaladminacornio_v1_RoleRef(ref), "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.VolumeClassSize": schema_pkg_apis_internaladminacornio_v1_VolumeClassSize(ref), - "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.VolumeResources": schema_pkg_apis_internaladminacornio_v1_VolumeResources(ref), "k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource": schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref), "k8s.io/api/core/v1.Affinity": schema_k8sio_api_core_v1_Affinity(ref), "k8s.io/api/core/v1.AttachedVolume": schema_k8sio_api_core_v1_AttachedVolume(ref), @@ -14021,41 +14019,27 @@ func schema_pkg_apis_internaladminacornio_v1_BaseResources(ref common.ReferenceC Format: "int32", }, }, - "computeClasses": { + "volumeStorage": { SchemaProps: spec.SchemaProps{ - Description: "ComputeClasses and VolumeClasses are used to track the amount of compute and volume storage per their respective classes", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ComputeResources"), - }, - }, - }, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), }, }, - "volumeClasses": { + "memory": { SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.VolumeResources"), - }, - }, - }, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "cpu": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), }, }, }, - Required: []string{"apps", "containers", "jobs", "volumes", "images", "computeClasses", "volumeClasses"}, + Required: []string{"apps", "containers", "jobs", "volumes", "images", "volumeStorage", "memory", "cpu"}, }, }, Dependencies: []string{ - "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ComputeResources", "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.VolumeResources"}, + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, } } @@ -14503,30 +14487,6 @@ func schema_pkg_apis_internaladminacornio_v1_ComputeClassMemory(ref common.Refer } } -func schema_pkg_apis_internaladminacornio_v1_ComputeResources(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "memory": { - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), - }, - }, - "cpu": { - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/api/resource.Quantity"}, - } -} - func schema_pkg_apis_internaladminacornio_v1_ImageRoleAuthorizationInstance(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -15171,33 +15131,19 @@ func schema_pkg_apis_internaladminacornio_v1_QuotaRequestResources(ref common.Re Format: "int32", }, }, - "computeClasses": { + "volumeStorage": { SchemaProps: spec.SchemaProps{ - Description: "ComputeClasses and VolumeClasses are used to track the amount of compute and volume storage per their respective classes", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ComputeResources"), - }, - }, - }, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), }, }, - "volumeClasses": { + "memory": { SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.VolumeResources"), - }, - }, - }, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "cpu": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), }, }, "secrets": { @@ -15208,11 +15154,11 @@ func schema_pkg_apis_internaladminacornio_v1_QuotaRequestResources(ref common.Re }, }, }, - Required: []string{"apps", "containers", "jobs", "volumes", "images", "computeClasses", "volumeClasses", "secrets"}, + Required: []string{"apps", "containers", "jobs", "volumes", "images", "volumeStorage", "memory", "cpu", "secrets"}, }, }, Dependencies: []string{ - "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.ComputeResources", "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1.VolumeResources"}, + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, } } @@ -15311,26 +15257,6 @@ func schema_pkg_apis_internaladminacornio_v1_VolumeClassSize(ref common.Referenc } } -func schema_pkg_apis_internaladminacornio_v1_VolumeResources(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "volumeStorage": { - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), - }, - }, - }, - Required: []string{"volumeStorage"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/api/resource.Quantity"}, - } -} - func schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{