diff --git a/charts/region/Chart.yaml b/charts/region/Chart.yaml index 656d5b1..be2aa1a 100644 --- a/charts/region/Chart.yaml +++ b/charts/region/Chart.yaml @@ -4,8 +4,8 @@ description: A Helm chart for deploying Unikorn's Region Controller type: application -version: v0.1.26 -appVersion: v0.1.26 +version: v0.1.27 +appVersion: v0.1.27 icon: https://raw.githubusercontent.com/unikorn-cloud/assets/main/images/logos/dark-on-light/icon.png diff --git a/charts/region/crds/region.unikorn-cloud.org_regions.yaml b/charts/region/crds/region.unikorn-cloud.org_regions.yaml index 233d359..a951219 100644 --- a/charts/region/crds/region.unikorn-cloud.org_regions.yaml +++ b/charts/region/crds/region.unikorn-cloud.org_regions.yaml @@ -69,25 +69,12 @@ spec: Flavors defines how flavors are filtered and reported to clients. If not defined, then all flavors are exported. properties: - exclude: - description: Exclude inhibits the export of flavors from - the region service. - items: - properties: - id: - description: ID flavor ID is the immutable Openstack - identifier for the flavor. - type: string - required: - - id - type: object - type: array - include: + metadata: description: |- - Include allows or augments flavors that can be exported by the region - service as defined by the "selectionPolicy" property. This explcitly - allows a flavor to be used, and or allows metadata to be mapped to the - flavor e.g. CPU/GPU information that isn't supported by OpenStack. + Metadata allows flavors to be explicitly augmented with additional metadata. + This acknowledges the fact that OpenStack is inadequate acting as a source + of truth for machine topology, and needs external input to describe things + like add on peripherals. items: properties: baremetal: @@ -99,6 +86,12 @@ spec: cpu: description: CPU defines additional CPU metadata. properties: + count: + description: |- + Count allows you to override the number of CPUs. Usually this wouldn't + be necessary, but alas some operators may not set this correctly for baremetal + flavors to make horizon display overcommit correctly... + type: integer family: description: |- Family is a free-form string that can communicate the CPU family to clients @@ -143,28 +136,36 @@ spec: - vendor type: object id: - description: |- - ID is the immutable Openstack identifier for the flavor. - While most flavor metadata (CPUs/Memory) should be immutable, the name is - not, and may change due to sales and marketing people. + description: ID is the immutable Openstack identifier + for the flavor. type: string + memory: + anyOf: + - type: integer + - type: string + description: Memory allows the memory amount to + be overridden. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - id type: object type: array - selectionPolicy: + selector: description: |- - SelectionPolicy defines the default set of flavors to export. "All" exports - all flavors, the "include" property defines additional metadata to - merge with matching flavors and the "exclude" inhibits export. "None" is a - more secure policy that only exports those flavors defined in the "include" - property, the "exclude" property is ignored as it's redundant. - enum: - - All - - None - type: string - required: - - selectionPolicy + Selector allows flavors to be manually selected for inclusion. The selected + set is a boolean intersection of all defined filters in the selector. + Note that there are some internal rules that will fiter out flavors such as + if the flavor does not have enough resource to function correctly. + properties: + ids: + description: |- + IDs is an explicit list of allowed flavors IDs. If not specified, + then all flavors are considered. + items: + type: string + type: array + type: object type: object serverGroupPolicy: description: |- diff --git a/charts/region/values.schema.json b/charts/region/values.schema.json index 03bd173..7d6cab1 100644 --- a/charts/region/values.schema.json +++ b/charts/region/values.schema.json @@ -217,25 +217,19 @@ "properties": { "flavors": { "type": "object", - "required": [ - "selectionPolicy" - ], "properties": { - "exclude": { - "type": "array", - "items": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { + "selector": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { "type": "string" } } } }, - "include": { + "metadata": { "type": "array", "items": { "type": "object", @@ -248,12 +242,19 @@ }, "cpu": { "properties": { + "count": { + "type": "integer" + }, "family": { "type": "string" } }, "type": "object" }, + "memory": { + "type": "string", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$" + }, "gpu": { "type": "object", "required": [ @@ -267,14 +268,7 @@ "type": "integer" }, "memory": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "string" - } - ], + "type": "string", "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$" }, "model": { diff --git a/charts/region/values.yaml b/charts/region/values.yaml index 79c048a..9d9277d 100644 --- a/charts/region/values.yaml +++ b/charts/region/values.yaml @@ -47,32 +47,22 @@ organization: unikorn-cloud # serverGroupPolicy: soft-anti-affinity # # Flavor selection and configuration. # flavors: -# # The selection policy can be "All" or "None" -# selectionPolicy: All -# # Include specific flavors when the policy is "None". In all cases -# # allows additional metadata to be exposed by the API that Openstack -# # cannot act as a source of truth for. -# include: +# # Include specific flavors. +# selector: +# ids: +# - 60ab8c22-ac61-467d-8680-03d0ecca23c9 +# # Mutate flavors or provide extra information. +# metadata: # - id: 60ab8c22-ac61-467d-8680-03d0ecca23c9 # cpu: +# count: 8 # family: Intel Xeon Platinum 8160T (Skylake) +# memory: 256Gi # gpu: # vendor: NVIDIA # model: H100 # memory: 192Gi # count: 2 -# # Eclude specific flavors when the policy is "All". -# exclude: -# - id: d04d82d9-faa6-4b3b-9247-28b8a158b7ed -# # Flavors containing any of the specified extra specs will be discarded. -# flavorExtraSpecsExclude: -# - resources:CUSTOM_BAREMETAL -# # Define properties on flavors and how to extract the number of GPUs from them. -# gpuDescriptors: -# - property: resources:PGPU -# expression: ^(\d+)$ -# - property: resources:VGPU -# expression: ^(\d+)$ # # Image service configuration. # image: # # Image selection, the result is a boolean intersection of chosen options. diff --git a/pkg/apis/unikorn/v1alpha1/types.go b/pkg/apis/unikorn/v1alpha1/types.go index bb26717..a99914f 100644 --- a/pkg/apis/unikorn/v1alpha1/types.go +++ b/pkg/apis/unikorn/v1alpha1/types.go @@ -114,25 +114,26 @@ const ( ) type OpenstackFlavorsSpec struct { - // SelectionPolicy defines the default set of flavors to export. "All" exports - // all flavors, the "include" property defines additional metadata to - // merge with matching flavors and the "exclude" inhibits export. "None" is a - // more secure policy that only exports those flavors defined in the "include" - // property, the "exclude" property is ignored as it's redundant. - SelectionPolicy OpenstackFlavorSelectionPolicy `json:"selectionPolicy"` - // Include allows or augments flavors that can be exported by the region - // service as defined by the "selectionPolicy" property. This explcitly - // allows a flavor to be used, and or allows metadata to be mapped to the - // flavor e.g. CPU/GPU information that isn't supported by OpenStack. - Include []OpenstackFlavorInclude `json:"include,omitempty"` - // Exclude inhibits the export of flavors from the region service. - Exclude []OpenstackFlavorExclude `json:"exclude,omitempty"` -} - -type OpenstackFlavorInclude struct { + // Selector allows flavors to be manually selected for inclusion. The selected + // set is a boolean intersection of all defined filters in the selector. + // Note that there are some internal rules that will fiter out flavors such as + // if the flavor does not have enough resource to function correctly. + Selector *FlavorSelector `json:"selector,omitempty"` + // Metadata allows flavors to be explicitly augmented with additional metadata. + // This acknowledges the fact that OpenStack is inadequate acting as a source + // of truth for machine topology, and needs external input to describe things + // like add on peripherals. + Metadata []FlavorMetadata `json:"metadata,omitempty"` +} + +type FlavorSelector struct { + // IDs is an explicit list of allowed flavors IDs. If not specified, + // then all flavors are considered. + IDs []string `json:"ids,omitempty"` +} + +type FlavorMetadata struct { // ID is the immutable Openstack identifier for the flavor. - // While most flavor metadata (CPUs/Memory) should be immutable, the name is - // not, and may change due to sales and marketing people. ID string `json:"id"` // Baremetal indicates that this is a baremetal flavor, as opposed to a // virtualized one in case this affects image selection or even how instances @@ -140,17 +141,18 @@ type OpenstackFlavorInclude struct { Baremetal bool `json:"baremetal,omitempty"` // CPU defines additional CPU metadata. CPU *CPUSpec `json:"cpu,omitempty"` + // Memory allows the memory amount to be overridden. + Memory *resource.Quantity `json:"memory,omitempty"` // GPU defines additional GPU metadata. When provided it will enable selection // of images based on GPU vendor and model. GPU *GPUSpec `json:"gpu,omitempty"` } -type OpenstackFlavorExclude struct { - // ID flavor ID is the immutable Openstack identifier for the flavor. - ID string `json:"id"` -} - type CPUSpec struct { + // Count allows you to override the number of CPUs. Usually this wouldn't + // be necessary, but alas some operators may not set this correctly for baremetal + // flavors to make horizon display overcommit correctly... + Count *int `json:"count,omitempty"` // Family is a free-form string that can communicate the CPU family to clients // e.g. "Xeon Platinum 8160T (Skylake)", and allows users to make scheduling // decisions based on CPU architecture and performance etc. diff --git a/pkg/apis/unikorn/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/unikorn/v1alpha1/zz_generated.deepcopy.go index 1b2e301..f5bf1ba 100644 --- a/pkg/apis/unikorn/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/unikorn/v1alpha1/zz_generated.deepcopy.go @@ -29,6 +29,11 @@ import ( // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CPUSpec) DeepCopyInto(out *CPUSpec) { *out = *in + if in.Count != nil { + in, out := &in.Count, &out.Count + *out = new(int) + **out = **in + } if in.Family != nil { in, out := &in.Family, &out.Family *out = new(string) @@ -68,6 +73,58 @@ func (in *ExternalNetworks) DeepCopy() *ExternalNetworks { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlavorMetadata) DeepCopyInto(out *FlavorMetadata) { + *out = *in + if in.CPU != nil { + in, out := &in.CPU, &out.CPU + *out = new(CPUSpec) + (*in).DeepCopyInto(*out) + } + if in.Memory != nil { + in, out := &in.Memory, &out.Memory + x := (*in).DeepCopy() + *out = &x + } + if in.GPU != nil { + in, out := &in.GPU, &out.GPU + *out = new(GPUSpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorMetadata. +func (in *FlavorMetadata) DeepCopy() *FlavorMetadata { + if in == nil { + return nil + } + out := new(FlavorMetadata) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlavorSelector) DeepCopyInto(out *FlavorSelector) { + *out = *in + if in.IDs != nil { + in, out := &in.IDs, &out.IDs + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorSelector. +func (in *FlavorSelector) DeepCopy() *FlavorSelector { + if in == nil { + return nil + } + out := new(FlavorSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GPUSpec) DeepCopyInto(out *GPUSpec) { *out = *in @@ -277,62 +334,20 @@ func (in *NetworkSelector) DeepCopy() *NetworkSelector { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OpenstackFlavorExclude) DeepCopyInto(out *OpenstackFlavorExclude) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenstackFlavorExclude. -func (in *OpenstackFlavorExclude) DeepCopy() *OpenstackFlavorExclude { - if in == nil { - return nil - } - out := new(OpenstackFlavorExclude) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OpenstackFlavorInclude) DeepCopyInto(out *OpenstackFlavorInclude) { +func (in *OpenstackFlavorsSpec) DeepCopyInto(out *OpenstackFlavorsSpec) { *out = *in - if in.CPU != nil { - in, out := &in.CPU, &out.CPU - *out = new(CPUSpec) - (*in).DeepCopyInto(*out) - } - if in.GPU != nil { - in, out := &in.GPU, &out.GPU - *out = new(GPUSpec) + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(FlavorSelector) (*in).DeepCopyInto(*out) } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenstackFlavorInclude. -func (in *OpenstackFlavorInclude) DeepCopy() *OpenstackFlavorInclude { - if in == nil { - return nil - } - out := new(OpenstackFlavorInclude) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OpenstackFlavorsSpec) DeepCopyInto(out *OpenstackFlavorsSpec) { - *out = *in - if in.Include != nil { - in, out := &in.Include, &out.Include - *out = make([]OpenstackFlavorInclude, len(*in)) + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make([]FlavorMetadata, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.Exclude != nil { - in, out := &in.Exclude, &out.Exclude - *out = make([]OpenstackFlavorExclude, len(*in)) - copy(*out, *in) - } return } diff --git a/pkg/handler/handler.go b/pkg/handler/handler.go index bc117de..b9aae92 100644 --- a/pkg/handler/handler.go +++ b/pkg/handler/handler.go @@ -123,6 +123,10 @@ func convertFlavor(in providers.Flavor) openapi.Flavor { }, } + if in.Baremetal { + out.Spec.Baremetal = coreutil.ToPointer(true) + } + if in.GPU != nil { out.Spec.Gpu = &openapi.GpuSpec{ Vendor: convertGpuVendor(in.GPU.Vendor), diff --git a/pkg/openapi/schema.go b/pkg/openapi/schema.go index 6b92250..6f11f65 100644 --- a/pkg/openapi/schema.go +++ b/pkg/openapi/schema.go @@ -19,93 +19,94 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "7j+GdR8f/zcAAP//DBP4glVjAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/pkg/openapi/server.spec.yaml b/pkg/openapi/server.spec.yaml index 46c238f..455cc40 100644 --- a/pkg/openapi/server.spec.yaml +++ b/pkg/openapi/server.spec.yaml @@ -353,6 +353,9 @@ components: - memory - disk properties: + baremetal: + description: Whether the flavor is for a dedicated machine. + type: boolean cpus: description: The number of CPUs. type: integer diff --git a/pkg/openapi/types.go b/pkg/openapi/types.go index 01497a9..b493eb6 100644 --- a/pkg/openapi/types.go +++ b/pkg/openapi/types.go @@ -54,6 +54,9 @@ type Flavor struct { // FlavorSpec A flavor. type FlavorSpec struct { + // Baremetal Whether the flavor is for a dedicated machine. + Baremetal *bool `json:"baremetal,omitempty"` + // CpuFamily A free form CPU family description e.g. model number, architecture. CpuFamily *string `json:"cpuFamily,omitempty"` diff --git a/pkg/providers/openstack/compute.go b/pkg/providers/openstack/compute.go index 0ee6771..4848613 100644 --- a/pkg/providers/openstack/compute.go +++ b/pkg/providers/openstack/compute.go @@ -84,6 +84,32 @@ func (c *ComputeClient) KeyPairs(ctx context.Context) ([]keypairs.KeyPair, error return keypairs.ExtractKeyPairs(page) } +// mutateFlavors allows nova's view of fact to be altered... +func (c *ComputeClient) mutateFlavors(f []flavors.Flavor) { + if c.options == nil || c.options.Flavors == nil { + return + } + + for _, metadata := range c.options.Flavors.Metadata { + index := slices.IndexFunc(f, func(flavor flavors.Flavor) bool { + return flavor.ID == metadata.ID + }) + + if index < 0 { + continue + } + + if metadata.CPU != nil && metadata.CPU.Count != nil { + f[index].VCPUs = *metadata.CPU.Count + } + + if metadata.Memory != nil { + // Convert from bytes to MiB + f[index].RAM = int(metadata.Memory.Value() >> 20) + } + } +} + // Flavors returns a list of flavors. // //nolint:cyclop @@ -107,21 +133,8 @@ func (c *ComputeClient) Flavors(ctx context.Context) ([]flavors.Flavor, error) { return nil, err } - // ************************************************************************* - // HACK HACK HACK - // ************************************************************************* - for i := range result { - f := &result[i] - - if f.ID == "c9b3b8c6-7268-4ed3-98d3-76743e3436cf" { - f.VCPUs = 128 - f.RAM = 2 * 1024 * 1024 - } - - } - // ************************************************************************* - // HACK HACK HACK - // ************************************************************************* + // Mutate any flavors first, as this may alter their selection criteria. + c.mutateFlavors(result) result = slices.DeleteFunc(result, func(flavor flavors.Flavor) bool { // We are admin, so see all the things, throw out private flavors. @@ -137,28 +150,12 @@ func (c *ComputeClient) Flavors(ctx context.Context) ([]flavors.Flavor, error) { } // Don't remove the flavor if it's implicitly selected by a lack of configuration. - if c.options == nil || c.options.Flavors == nil { + if c.options == nil || c.options.Flavors == nil || c.options.Flavors.Selector == nil { return false } - // If the selection policy is "allow all", then only reject if the flavor ID - // is in the exclusion list. If the section policy is "reject all", then only - // allow if the flavor ID is in the inclusion list. - switch c.options.Flavors.SelectionPolicy { - case unikornv1.OpenstackFlavorSelectionPolicySelectAll: - ok := slices.ContainsFunc(c.options.Flavors.Exclude, func(exclusion unikornv1.OpenstackFlavorExclude) bool { - return flavor.ID == exclusion.ID - }) - - if ok { - return true - } - case unikornv1.OpenstackFlavorSelectionPolicySelectNone: - ok := slices.ContainsFunc(c.options.Flavors.Include, func(inclusion unikornv1.OpenstackFlavorInclude) bool { - return flavor.ID == inclusion.ID - }) - - if !ok { + if len(c.options.Flavors.Selector.IDs) > 0 { + if !slices.Contains(c.options.Flavors.Selector.IDs, flavor.ID) { return true } } diff --git a/pkg/providers/openstack/provider.go b/pkg/providers/openstack/provider.go index 88ec509..5e6adec 100644 --- a/pkg/providers/openstack/provider.go +++ b/pkg/providers/openstack/provider.go @@ -254,14 +254,12 @@ func (p *Provider) Flavors(ctx context.Context) (providers.FlavorList, error) { // Apply any extra metadata to the flavor. if p.region.Spec.Openstack.Compute != nil && p.region.Spec.Openstack.Compute.Flavors != nil { - inclusions := p.region.Spec.Openstack.Compute.Flavors.Include - - i := slices.IndexFunc(inclusions, func(inclusion unikornv1.OpenstackFlavorInclude) bool { - return flavor.ID == inclusion.ID + i := slices.IndexFunc(p.region.Spec.Openstack.Compute.Flavors.Metadata, func(metadata unikornv1.FlavorMetadata) bool { + return flavor.ID == metadata.ID }) if i >= 0 { - metadata := &inclusions[i] + metadata := &p.region.Spec.Openstack.Compute.Flavors.Metadata[i] f.Baremetal = metadata.Baremetal