From 1b4c8338252b1a9cc55672f58938193dfe7a3265 Mon Sep 17 00:00:00 2001 From: halfrost Date: Mon, 15 Aug 2022 21:29:59 -0700 Subject: [PATCH] Add cluster resource modeling api Signed-off-by: halfrost --- api/openapi-spec/swagger.json | 71 ++++++++++ pkg/apis/cluster/types.go | 132 +++++++++++++++++ pkg/apis/cluster/v1alpha1/types.go | 134 ++++++++++++++++++ .../v1alpha1/zz_generated.conversion.go | 102 +++++++++++++ .../cluster/v1alpha1/zz_generated.deepcopy.go | 69 +++++++++ pkg/apis/cluster/zz_generated.deepcopy.go | 69 +++++++++ pkg/generated/openapi/zz_generated.openapi.go | 134 +++++++++++++++++- 7 files changed, 709 insertions(+), 2 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index e1955b55e877..b2c052f3b822 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -14054,6 +14054,22 @@ } } }, + "com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.AllocatableModeling": { + "description": "AllocatableModeling represents the number of nodes in which allocatable resources in a specific resource model grade. E.g. AllocatableModeling{Grade: 2, Count: 10} means 10 nodes belong to resource model in grade 2.", + "type": "object", + "properties": { + "count": { + "description": "Count is the number of nodes that own the resources delineated by this modeling.", + "type": "integer", + "format": "int32" + }, + "grade": { + "description": "Grade is the index of ResourceModel.", + "type": "integer", + "format": "int32" + } + } + }, "com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.Cluster": { "description": "Cluster represents the desire state and status of a member cluster.", "type": "object", @@ -14171,6 +14187,14 @@ "description": "Region represents the region of the member cluster locate in.", "type": "string" }, + "resourceModels": { + "description": "ResourceModels is the list of resource modeling in this cluster. Each modeling quota can be customized by the user. Modeling name must be one of the following: cpu, memory, storage, ephemeral-storage. If the user does not define the modeling name and modeling quota, it will be the default model. The default model grade from 0 to 8. When grade = 0 or grade = 1, the default model's cpu quota and memory quota is a fix value. When grade greater than or equal to 2, each default model's cpu quota is [2^(grade-1), 2^grade), 2 \u003c= grade \u003c= 7 Each default model's memory quota is [2^(grade + 2), 2^(grade + 3)), 2 \u003c= grade \u003c= 7 E.g. grade 0 likes this: - grade: 0\n ranges:\n - name: \"cpu\"\n min: 0 C\n max: 1 C\n - name: \"memory\"\n min: 0 GB\n max: 4 GB\n\n- grade: 1\n ranges:\n - name: \"cpu\"\n min: 1 C\n max: 2 C\n - name: \"memory\"\n min: 4 GB\n max: 16 GB\n\n- grade: 2\n ranges:\n - name: \"cpu\"\n min: 2 C\n max: 4 C\n - name: \"memory\"\n min: 16 GB\n max: 32 GB\n\n- grade: 7\n range:\n - name: \"cpu\"\n min: 64 C\n max: 128 C\n - name: \"memory\"\n min: 512 GB\n max: 1024 GB\n\ngrade 8, the last one likes below. No matter what Max value you pass, the meaning of Max value in this grade is infinite. You can pass any number greater than Min value. - grade: 8\n range:\n - name: \"cpu\"\n min: 128 C\n max: MAXINT\n - name: \"memory\"\n min: 1024 GB\n max: MAXINT", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.ResourceModel" + } + }, "secretRef": { "description": "SecretRef represents the secret contains mandatory credentials to access the member cluster. The secret should hold credentials as follows: - secret.data.token - secret.data.caBundle", "$ref": "#/definitions/com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.LocalSecretReference" @@ -14264,6 +14288,45 @@ } } }, + "com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.ResourceModel": { + "description": "ResourceModel describes the modeling that you want to statistics.", + "type": "object", + "properties": { + "grade": { + "description": "Grade is the index for the resource modeling.", + "type": "integer", + "format": "int32" + }, + "ranges": { + "description": "Ranges describes the resource quota ranges.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.ResourceModelRange" + } + } + } + }, + "com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.ResourceModelRange": { + "description": "ResourceModelRange describes the detail of each modeling quota that ranges from min to max. Please pay attention, by default, the value of min can be inclusive, and the value of max cannot be inclusive. E.g. in an interval, min = 2, max =10 is set, which means the interval [2,10). This rule ensure that all intervals have the same meaning. If the last interval is +∞, it is definitely unreachable. Therefore, we define the right interval as the open interval. For a valid interval, the value on the right is greater than the value on the left, in other words, max must be greater than min.", + "type": "object", + "properties": { + "max": { + "description": "Max is the maximum amount of this resource represented by resource name. Special Instructions, for the last ResourceModelRange, which no matter what Max value you pass, the meaning is infinite. Because for the last item, any ResourceModelRange's quota larger than Min will be classified to the last one. Of course, the value of the Max field is always greater than the value of the Min field. It should be true in any case.", + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" + }, + "min": { + "description": "Min is the minimum amount of this resource represented by resource name.", + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" + }, + "name": { + "description": "Name is the name for the resource that you want to categorize.", + "type": "string" + } + } + }, "com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.ResourceSummary": { "description": "ResourceSummary represents the summary of resources in the member cluster.", "type": "object", @@ -14276,6 +14339,14 @@ "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" } }, + "allocatableModelings": { + "description": "AllocatableModelings represents the statistical resource modeling.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.karmada-io.karmada.pkg.apis.cluster.v1alpha1.AllocatableModeling" + } + }, "allocated": { "description": "Allocated represents the resources of a cluster that have been scheduled. Total amount of required resources of all Pods that have been scheduled to nodes.", "type": "object", diff --git a/pkg/apis/cluster/types.go b/pkg/apis/cluster/types.go index 38edcc98da50..d743a2c77cc6 100644 --- a/pkg/apis/cluster/types.go +++ b/pkg/apis/cluster/types.go @@ -2,9 +2,30 @@ package cluster import ( corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// ResourceName is the name identifying various resources in a ResourceList. +type ResourceName string + +// Resource names must be not more than 63 characters, consisting of upper- or lower-case alphanumeric characters, +// with the -, _, and . characters allowed anywhere, except the first or last character. +// The default convention, matching that for annotations, is to use lower-case names, with dashes, rather than +// camel case, separating compound words. +// Fully-qualified resource typenames are constructed from a DNS-style subdomain, followed by a slash `/` and a name. +const ( + // ResourceCPU in cores. (e,g. 500m = .5 cores) + ResourceCPU ResourceName = "cpu" + // ResourceMemory in bytes. (e,g. 500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceMemory ResourceName = "memory" + // ResourceStorage is volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024) + ResourceStorage ResourceName = "storage" + // ResourceEphemeralStorage is local ephemeral storage, in bytes. (e,g. 500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + // The resource name for ResourceEphemeralStorage is alpha and it can change across releases. + ResourceEphemeralStorage ResourceName = "ephemeral-storage" +) + //revive:disable:exported // +genclient @@ -104,6 +125,101 @@ type ClusterSpec struct { // any resource that does not tolerate the Taint. // +optional Taints []corev1.Taint + + // ResourceModels is the list of resource modeling in this cluster. Each modeling quota can be customized by the user. + // Modeling name must be one of the following: cpu, memory, storage, ephemeral-storage. + // If the user does not define the modeling name and modeling quota, it will be the default model. + // The default model grade from 0 to 8. + // When grade = 0 or grade = 1, the default model's cpu quota and memory quota is a fix value. + // When grade greater than or equal to 2, each default model's cpu quota is [2^(grade-1), 2^grade), 2 <= grade <= 7 + // Each default model's memory quota is [2^(grade + 2), 2^(grade + 3)), 2 <= grade <= 7 + // E.g. grade 0 likes this: + // - grade: 0 + // ranges: + // - name: "cpu" + // min: 0 C + // max: 1 C + // - name: "memory" + // min: 0 GB + // max: 4 GB + // + // - grade: 1 + // ranges: + // - name: "cpu" + // min: 1 C + // max: 2 C + // - name: "memory" + // min: 4 GB + // max: 16 GB + // + // - grade: 2 + // ranges: + // - name: "cpu" + // min: 2 C + // max: 4 C + // - name: "memory" + // min: 16 GB + // max: 32 GB + // + // - grade: 7 + // range: + // - name: "cpu" + // min: 64 C + // max: 128 C + // - name: "memory" + // min: 512 GB + // max: 1024 GB + // + // grade 8, the last one likes below. No matter what Max value you pass, + // the meaning of Max value in this grade is infinite. You can pass any number greater than Min value. + // - grade: 8 + // range: + // - name: "cpu" + // min: 128 C + // max: MAXINT + // - name: "memory" + // min: 1024 GB + // max: MAXINT + // + // +optional + ResourceModels []ResourceModel +} + +// ResourceModel describes the modeling that you want to statistics. +type ResourceModel struct { + // Grade is the index for the resource modeling. + // +optional + Grade int + + // Ranges describes the resource quota ranges. + // +optional + Ranges []ResourceModelRange +} + +// ResourceModelRange describes the detail of each modeling quota that ranges from min to max. +// Please pay attention, by default, the value of min can be inclusive, and the value of max cannot be inclusive. +// E.g. in an interval, min = 2, max =10 is set, which means the interval [2,10). +// This rule ensure that all intervals have the same meaning. If the last interval is +∞, +// it is definitely unreachable. Therefore, we define the right interval as the open interval. +// For a valid interval, the value on the right is greater than the value on the left, +// in other words, max must be greater than min. +type ResourceModelRange struct { + // Name is the name for the resource that you want to categorize. + // +optional + Name ResourceName + + // Min is the minimum amount of this resource represented by resource name. + // +optional + Min resource.Quantity + + // Max is the maximum amount of this resource represented by resource name. + // Special Instructions, for the last ResourceModelRange, which no matter what Max value you pass, + // the meaning is infinite. Because for the last item, + // any ResourceModelRange's quota larger than Min will be classified to the last one. + // Of course, the value of the Max field is always greater than the value of the Min field. + // It should be true in any case. + // +optional + Max resource.Quantity } const ( @@ -216,6 +332,22 @@ type ResourceSummary struct { // Total amount of required resources of all Pods that have been scheduled to nodes. // +optional Allocated corev1.ResourceList + + // AllocatableModelings represents the statistical resource modeling. + // +optional + AllocatableModelings []AllocatableModeling +} + +// AllocatableModeling represents the number of nodes in which allocatable resources in a specific resource model grade. +// E.g. AllocatableModeling{Grade: 2, Count: 10} means 10 nodes belong to resource model in grade 2. +type AllocatableModeling struct { + // Grade is the index of ResourceModel. + // +optional + Grade int + + // Count is the number of nodes that own the resources delineated by this modeling. + // +optional + Count int } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/cluster/v1alpha1/types.go b/pkg/apis/cluster/v1alpha1/types.go index 11bdced409ce..86ab4dc7e6bb 100644 --- a/pkg/apis/cluster/v1alpha1/types.go +++ b/pkg/apis/cluster/v1alpha1/types.go @@ -2,6 +2,7 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -16,6 +17,26 @@ const ( ResourceNamespaceScopedCluster = false ) +// ResourceName is the name identifying various resources in a ResourceList. +type ResourceName string + +// Resource names must be not more than 63 characters, consisting of upper- or lower-case alphanumeric characters, +// with the -, _, and . characters allowed anywhere, except the first or last character. +// The default convention, matching that for annotations, is to use lower-case names, with dashes, rather than +// camel case, separating compound words. +// Fully-qualified resource typenames are constructed from a DNS-style subdomain, followed by a slash `/` and a name. +const ( + // ResourceCPU in cores. (e,g. 500m = .5 cores) + ResourceCPU ResourceName = "cpu" + // ResourceMemory in bytes. (e,g. 500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceMemory ResourceName = "memory" + // ResourceStorage is volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024) + ResourceStorage ResourceName = "storage" + // ResourceEphemeralStorage is local ephemeral storage, in bytes. (e,g. 500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + // The resource name for ResourceEphemeralStorage is alpha and it can change across releases. + ResourceEphemeralStorage ResourceName = "ephemeral-storage" +) + // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -116,6 +137,101 @@ type ClusterSpec struct { // any resource that does not tolerate the Taint. // +optional Taints []corev1.Taint `json:"taints,omitempty"` + + // ResourceModels is the list of resource modeling in this cluster. Each modeling quota can be customized by the user. + // Modeling name must be one of the following: cpu, memory, storage, ephemeral-storage. + // If the user does not define the modeling name and modeling quota, it will be the default model. + // The default model grade from 0 to 8. + // When grade = 0 or grade = 1, the default model's cpu quota and memory quota is a fix value. + // When grade greater than or equal to 2, each default model's cpu quota is [2^(grade-1), 2^grade), 2 <= grade <= 7 + // Each default model's memory quota is [2^(grade + 2), 2^(grade + 3)), 2 <= grade <= 7 + // E.g. grade 0 likes this: + // - grade: 0 + // ranges: + // - name: "cpu" + // min: 0 C + // max: 1 C + // - name: "memory" + // min: 0 GB + // max: 4 GB + // + // - grade: 1 + // ranges: + // - name: "cpu" + // min: 1 C + // max: 2 C + // - name: "memory" + // min: 4 GB + // max: 16 GB + // + // - grade: 2 + // ranges: + // - name: "cpu" + // min: 2 C + // max: 4 C + // - name: "memory" + // min: 16 GB + // max: 32 GB + // + // - grade: 7 + // range: + // - name: "cpu" + // min: 64 C + // max: 128 C + // - name: "memory" + // min: 512 GB + // max: 1024 GB + // + // grade 8, the last one likes below. No matter what Max value you pass, + // the meaning of Max value in this grade is infinite. You can pass any number greater than Min value. + // - grade: 8 + // range: + // - name: "cpu" + // min: 128 C + // max: MAXINT + // - name: "memory" + // min: 1024 GB + // max: MAXINT + // + // +optional + ResourceModels []ResourceModel `json:"resourceModels,omitempty"` +} + +// ResourceModel describes the modeling that you want to statistics. +type ResourceModel struct { + // Grade is the index for the resource modeling. + // +optional + Grade int `json:"grade,omitempty"` + + // Ranges describes the resource quota ranges. + // +optional + Ranges []ResourceModelRange `json:"ranges,omitempty"` +} + +// ResourceModelRange describes the detail of each modeling quota that ranges from min to max. +// Please pay attention, by default, the value of min can be inclusive, and the value of max cannot be inclusive. +// E.g. in an interval, min = 2, max =10 is set, which means the interval [2,10). +// This rule ensure that all intervals have the same meaning. If the last interval is +∞, +// it is definitely unreachable. Therefore, we define the right interval as the open interval. +// For a valid interval, the value on the right is greater than the value on the left, +// in other words, max must be greater than min. +type ResourceModelRange struct { + // Name is the name for the resource that you want to categorize. + // +optional + Name ResourceName `json:"name,omitempty"` + + // Min is the minimum amount of this resource represented by resource name. + // +optional + Min resource.Quantity `json:"min,omitempty"` + + // Max is the maximum amount of this resource represented by resource name. + // Special Instructions, for the last ResourceModelRange, which no matter what Max value you pass, + // the meaning is infinite. Because for the last item, + // any ResourceModelRange's quota larger than Min will be classified to the last one. + // Of course, the value of the Max field is always greater than the value of the Min field. + // It should be true in any case. + // +optional + Max resource.Quantity `json:"max,omitempty"` } const ( @@ -215,14 +331,32 @@ type ResourceSummary struct { // Total amount of allocatable resources on all nodes. // +optional Allocatable corev1.ResourceList `json:"allocatable,omitempty"` + // Allocating represents the resources of a cluster that are pending for scheduling. // Total amount of required resources of all Pods that are waiting for scheduling. // +optional Allocating corev1.ResourceList `json:"allocating,omitempty"` + // Allocated represents the resources of a cluster that have been scheduled. // Total amount of required resources of all Pods that have been scheduled to nodes. // +optional Allocated corev1.ResourceList `json:"allocated,omitempty"` + + // AllocatableModelings represents the statistical resource modeling. + // +optional + AllocatableModelings []AllocatableModeling `json:"allocatableModelings,omitempty"` +} + +// AllocatableModeling represents the number of nodes in which allocatable resources in a specific resource model grade. +// E.g. AllocatableModeling{Grade: 2, Count: 10} means 10 nodes belong to resource model in grade 2. +type AllocatableModeling struct { + // Grade is the index of ResourceModel. + // +optional + Grade int `json:"grade,omitempty"` + + // Count is the number of nodes that own the resources delineated by this modeling. + // +optional + Count int `json:"count,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/cluster/v1alpha1/zz_generated.conversion.go b/pkg/apis/cluster/v1alpha1/zz_generated.conversion.go index 86cd65413519..1bef1cb79b7f 100644 --- a/pkg/apis/cluster/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/cluster/v1alpha1/zz_generated.conversion.go @@ -43,6 +43,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*AllocatableModeling)(nil), (*cluster.AllocatableModeling)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_AllocatableModeling_To_cluster_AllocatableModeling(a.(*AllocatableModeling), b.(*cluster.AllocatableModeling), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*cluster.AllocatableModeling)(nil), (*AllocatableModeling)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_cluster_AllocatableModeling_To_v1alpha1_AllocatableModeling(a.(*cluster.AllocatableModeling), b.(*AllocatableModeling), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*Cluster)(nil), (*cluster.Cluster)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_Cluster_To_cluster_Cluster(a.(*Cluster), b.(*cluster.Cluster), scope) }); err != nil { @@ -113,6 +123,26 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*ResourceModel)(nil), (*cluster.ResourceModel)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ResourceModel_To_cluster_ResourceModel(a.(*ResourceModel), b.(*cluster.ResourceModel), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*cluster.ResourceModel)(nil), (*ResourceModel)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_cluster_ResourceModel_To_v1alpha1_ResourceModel(a.(*cluster.ResourceModel), b.(*ResourceModel), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ResourceModelRange)(nil), (*cluster.ResourceModelRange)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ResourceModelRange_To_cluster_ResourceModelRange(a.(*ResourceModelRange), b.(*cluster.ResourceModelRange), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*cluster.ResourceModelRange)(nil), (*ResourceModelRange)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_cluster_ResourceModelRange_To_v1alpha1_ResourceModelRange(a.(*cluster.ResourceModelRange), b.(*ResourceModelRange), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*ResourceSummary)(nil), (*cluster.ResourceSummary)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_ResourceSummary_To_cluster_ResourceSummary(a.(*ResourceSummary), b.(*cluster.ResourceSummary), scope) }); err != nil { @@ -175,6 +205,28 @@ func Convert_cluster_APIResource_To_v1alpha1_APIResource(in *cluster.APIResource return autoConvert_cluster_APIResource_To_v1alpha1_APIResource(in, out, s) } +func autoConvert_v1alpha1_AllocatableModeling_To_cluster_AllocatableModeling(in *AllocatableModeling, out *cluster.AllocatableModeling, s conversion.Scope) error { + out.Grade = in.Grade + out.Count = in.Count + return nil +} + +// Convert_v1alpha1_AllocatableModeling_To_cluster_AllocatableModeling is an autogenerated conversion function. +func Convert_v1alpha1_AllocatableModeling_To_cluster_AllocatableModeling(in *AllocatableModeling, out *cluster.AllocatableModeling, s conversion.Scope) error { + return autoConvert_v1alpha1_AllocatableModeling_To_cluster_AllocatableModeling(in, out, s) +} + +func autoConvert_cluster_AllocatableModeling_To_v1alpha1_AllocatableModeling(in *cluster.AllocatableModeling, out *AllocatableModeling, s conversion.Scope) error { + out.Grade = in.Grade + out.Count = in.Count + return nil +} + +// Convert_cluster_AllocatableModeling_To_v1alpha1_AllocatableModeling is an autogenerated conversion function. +func Convert_cluster_AllocatableModeling_To_v1alpha1_AllocatableModeling(in *cluster.AllocatableModeling, out *AllocatableModeling, s conversion.Scope) error { + return autoConvert_cluster_AllocatableModeling_To_v1alpha1_AllocatableModeling(in, out, s) +} + func autoConvert_v1alpha1_Cluster_To_cluster_Cluster(in *Cluster, out *cluster.Cluster, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha1_ClusterSpec_To_cluster_ClusterSpec(&in.Spec, &out.Spec, s); err != nil { @@ -280,6 +332,7 @@ func autoConvert_v1alpha1_ClusterSpec_To_cluster_ClusterSpec(in *ClusterSpec, ou out.Region = in.Region out.Zone = in.Zone out.Taints = *(*[]v1.Taint)(unsafe.Pointer(&in.Taints)) + out.ResourceModels = *(*[]cluster.ResourceModel)(unsafe.Pointer(&in.ResourceModels)) return nil } @@ -301,6 +354,7 @@ func autoConvert_cluster_ClusterSpec_To_v1alpha1_ClusterSpec(in *cluster.Cluster out.Region = in.Region out.Zone = in.Zone out.Taints = *(*[]v1.Taint)(unsafe.Pointer(&in.Taints)) + out.ResourceModels = *(*[]ResourceModel)(unsafe.Pointer(&in.ResourceModels)) return nil } @@ -381,10 +435,57 @@ func Convert_cluster_NodeSummary_To_v1alpha1_NodeSummary(in *cluster.NodeSummary return autoConvert_cluster_NodeSummary_To_v1alpha1_NodeSummary(in, out, s) } +func autoConvert_v1alpha1_ResourceModel_To_cluster_ResourceModel(in *ResourceModel, out *cluster.ResourceModel, s conversion.Scope) error { + out.Grade = in.Grade + out.Ranges = *(*[]cluster.ResourceModelRange)(unsafe.Pointer(&in.Ranges)) + return nil +} + +// Convert_v1alpha1_ResourceModel_To_cluster_ResourceModel is an autogenerated conversion function. +func Convert_v1alpha1_ResourceModel_To_cluster_ResourceModel(in *ResourceModel, out *cluster.ResourceModel, s conversion.Scope) error { + return autoConvert_v1alpha1_ResourceModel_To_cluster_ResourceModel(in, out, s) +} + +func autoConvert_cluster_ResourceModel_To_v1alpha1_ResourceModel(in *cluster.ResourceModel, out *ResourceModel, s conversion.Scope) error { + out.Grade = in.Grade + out.Ranges = *(*[]ResourceModelRange)(unsafe.Pointer(&in.Ranges)) + return nil +} + +// Convert_cluster_ResourceModel_To_v1alpha1_ResourceModel is an autogenerated conversion function. +func Convert_cluster_ResourceModel_To_v1alpha1_ResourceModel(in *cluster.ResourceModel, out *ResourceModel, s conversion.Scope) error { + return autoConvert_cluster_ResourceModel_To_v1alpha1_ResourceModel(in, out, s) +} + +func autoConvert_v1alpha1_ResourceModelRange_To_cluster_ResourceModelRange(in *ResourceModelRange, out *cluster.ResourceModelRange, s conversion.Scope) error { + out.Name = cluster.ResourceName(in.Name) + out.Min = in.Min + out.Max = in.Max + return nil +} + +// Convert_v1alpha1_ResourceModelRange_To_cluster_ResourceModelRange is an autogenerated conversion function. +func Convert_v1alpha1_ResourceModelRange_To_cluster_ResourceModelRange(in *ResourceModelRange, out *cluster.ResourceModelRange, s conversion.Scope) error { + return autoConvert_v1alpha1_ResourceModelRange_To_cluster_ResourceModelRange(in, out, s) +} + +func autoConvert_cluster_ResourceModelRange_To_v1alpha1_ResourceModelRange(in *cluster.ResourceModelRange, out *ResourceModelRange, s conversion.Scope) error { + out.Name = ResourceName(in.Name) + out.Min = in.Min + out.Max = in.Max + return nil +} + +// Convert_cluster_ResourceModelRange_To_v1alpha1_ResourceModelRange is an autogenerated conversion function. +func Convert_cluster_ResourceModelRange_To_v1alpha1_ResourceModelRange(in *cluster.ResourceModelRange, out *ResourceModelRange, s conversion.Scope) error { + return autoConvert_cluster_ResourceModelRange_To_v1alpha1_ResourceModelRange(in, out, s) +} + func autoConvert_v1alpha1_ResourceSummary_To_cluster_ResourceSummary(in *ResourceSummary, out *cluster.ResourceSummary, s conversion.Scope) error { out.Allocatable = *(*v1.ResourceList)(unsafe.Pointer(&in.Allocatable)) out.Allocating = *(*v1.ResourceList)(unsafe.Pointer(&in.Allocating)) out.Allocated = *(*v1.ResourceList)(unsafe.Pointer(&in.Allocated)) + out.AllocatableModelings = *(*[]cluster.AllocatableModeling)(unsafe.Pointer(&in.AllocatableModelings)) return nil } @@ -397,6 +498,7 @@ func autoConvert_cluster_ResourceSummary_To_v1alpha1_ResourceSummary(in *cluster out.Allocatable = *(*v1.ResourceList)(unsafe.Pointer(&in.Allocatable)) out.Allocating = *(*v1.ResourceList)(unsafe.Pointer(&in.Allocating)) out.Allocated = *(*v1.ResourceList)(unsafe.Pointer(&in.Allocated)) + out.AllocatableModelings = *(*[]AllocatableModeling)(unsafe.Pointer(&in.AllocatableModelings)) return nil } diff --git a/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go index a0094ef3269c..05c2cc09230c 100644 --- a/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go @@ -48,6 +48,22 @@ func (in *APIResource) DeepCopy() *APIResource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AllocatableModeling) DeepCopyInto(out *AllocatableModeling) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllocatableModeling. +func (in *AllocatableModeling) DeepCopy() *AllocatableModeling { + if in == nil { + return nil + } + out := new(AllocatableModeling) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Cluster) DeepCopyInto(out *Cluster) { *out = *in @@ -161,6 +177,13 @@ func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.ResourceModels != nil { + in, out := &in.ResourceModels, &out.ResourceModels + *out = make([]ResourceModel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -246,6 +269,47 @@ func (in *NodeSummary) DeepCopy() *NodeSummary { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceModel) DeepCopyInto(out *ResourceModel) { + *out = *in + if in.Ranges != nil { + in, out := &in.Ranges, &out.Ranges + *out = make([]ResourceModelRange, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceModel. +func (in *ResourceModel) DeepCopy() *ResourceModel { + if in == nil { + return nil + } + out := new(ResourceModel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceModelRange) DeepCopyInto(out *ResourceModelRange) { + *out = *in + out.Min = in.Min.DeepCopy() + out.Max = in.Max.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceModelRange. +func (in *ResourceModelRange) DeepCopy() *ResourceModelRange { + if in == nil { + return nil + } + out := new(ResourceModelRange) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceSummary) DeepCopyInto(out *ResourceSummary) { *out = *in @@ -270,6 +334,11 @@ func (in *ResourceSummary) DeepCopyInto(out *ResourceSummary) { (*out)[key] = val.DeepCopy() } } + if in.AllocatableModelings != nil { + in, out := &in.AllocatableModelings, &out.AllocatableModelings + *out = make([]AllocatableModeling, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/apis/cluster/zz_generated.deepcopy.go b/pkg/apis/cluster/zz_generated.deepcopy.go index 727a154e611f..fab6e65584c0 100644 --- a/pkg/apis/cluster/zz_generated.deepcopy.go +++ b/pkg/apis/cluster/zz_generated.deepcopy.go @@ -48,6 +48,22 @@ func (in *APIResource) DeepCopy() *APIResource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AllocatableModeling) DeepCopyInto(out *AllocatableModeling) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllocatableModeling. +func (in *AllocatableModeling) DeepCopy() *AllocatableModeling { + if in == nil { + return nil + } + out := new(AllocatableModeling) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Cluster) DeepCopyInto(out *Cluster) { *out = *in @@ -161,6 +177,13 @@ func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.ResourceModels != nil { + in, out := &in.ResourceModels, &out.ResourceModels + *out = make([]ResourceModel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -246,6 +269,47 @@ func (in *NodeSummary) DeepCopy() *NodeSummary { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceModel) DeepCopyInto(out *ResourceModel) { + *out = *in + if in.Ranges != nil { + in, out := &in.Ranges, &out.Ranges + *out = make([]ResourceModelRange, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceModel. +func (in *ResourceModel) DeepCopy() *ResourceModel { + if in == nil { + return nil + } + out := new(ResourceModel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceModelRange) DeepCopyInto(out *ResourceModelRange) { + *out = *in + out.Min = in.Min.DeepCopy() + out.Max = in.Max.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceModelRange. +func (in *ResourceModelRange) DeepCopy() *ResourceModelRange { + if in == nil { + return nil + } + out := new(ResourceModelRange) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceSummary) DeepCopyInto(out *ResourceSummary) { *out = *in @@ -270,6 +334,11 @@ func (in *ResourceSummary) DeepCopyInto(out *ResourceSummary) { (*out)[key] = val.DeepCopy() } } + if in.AllocatableModelings != nil { + in, out := &in.AllocatableModelings, &out.AllocatableModelings + *out = make([]AllocatableModeling, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 67496c412a3a..3febee7ac4b7 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -19,6 +19,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA return map[string]common.OpenAPIDefinition{ "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.APIEnablement": schema_pkg_apis_cluster_v1alpha1_APIEnablement(ref), "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.APIResource": schema_pkg_apis_cluster_v1alpha1_APIResource(ref), + "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.AllocatableModeling": schema_pkg_apis_cluster_v1alpha1_AllocatableModeling(ref), "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.Cluster": schema_pkg_apis_cluster_v1alpha1_Cluster(ref), "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ClusterList": schema_pkg_apis_cluster_v1alpha1_ClusterList(ref), "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ClusterProxyOptions": schema_pkg_apis_cluster_v1alpha1_ClusterProxyOptions(ref), @@ -26,6 +27,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ClusterStatus": schema_pkg_apis_cluster_v1alpha1_ClusterStatus(ref), "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.LocalSecretReference": schema_pkg_apis_cluster_v1alpha1_LocalSecretReference(ref), "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.NodeSummary": schema_pkg_apis_cluster_v1alpha1_NodeSummary(ref), + "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ResourceModel": schema_pkg_apis_cluster_v1alpha1_ResourceModel(ref), + "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ResourceModelRange": schema_pkg_apis_cluster_v1alpha1_ResourceModelRange(ref), "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ResourceSummary": schema_pkg_apis_cluster_v1alpha1_ResourceSummary(ref), "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1.DependentObjectReference": schema_pkg_apis_config_v1alpha1_DependentObjectReference(ref), "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1.RequestStatus": schema_pkg_apis_config_v1alpha1_RequestStatus(ref), @@ -502,6 +505,33 @@ func schema_pkg_apis_cluster_v1alpha1_APIResource(ref common.ReferenceCallback) } } +func schema_pkg_apis_cluster_v1alpha1_AllocatableModeling(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "AllocatableModeling represents the number of nodes in which allocatable resources in a specific resource model grade. E.g. AllocatableModeling{Grade: 2, Count: 10} means 10 nodes belong to resource model in grade 2.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "grade": { + SchemaProps: spec.SchemaProps{ + Description: "Grade is the index of ResourceModel.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "count": { + SchemaProps: spec.SchemaProps{ + Description: "Count is the number of nodes that own the resources delineated by this modeling.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_cluster_v1alpha1_Cluster(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -742,12 +772,26 @@ func schema_pkg_apis_cluster_v1alpha1_ClusterSpec(ref common.ReferenceCallback) }, }, }, + "resourceModels": { + SchemaProps: spec.SchemaProps{ + Description: "ResourceModels is the list of resource modeling in this cluster. Each modeling quota can be customized by the user. Modeling name must be one of the following: cpu, memory, storage, ephemeral-storage. If the user does not define the modeling name and modeling quota, it will be the default model. The default model grade from 0 to 8. When grade = 0 or grade = 1, the default model's cpu quota and memory quota is a fix value. When grade greater than or equal to 2, each default model's cpu quota is [2^(grade-1), 2^grade), 2 <= grade <= 7 Each default model's memory quota is [2^(grade + 2), 2^(grade + 3)), 2 <= grade <= 7 E.g. grade 0 likes this: - grade: 0\n ranges:\n - name: \"cpu\"\n min: 0 C\n max: 1 C\n - name: \"memory\"\n min: 0 GB\n max: 4 GB\n\n- grade: 1\n ranges:\n - name: \"cpu\"\n min: 1 C\n max: 2 C\n - name: \"memory\"\n min: 4 GB\n max: 16 GB\n\n- grade: 2\n ranges:\n - name: \"cpu\"\n min: 2 C\n max: 4 C\n - name: \"memory\"\n min: 16 GB\n max: 32 GB\n\n- grade: 7\n range:\n - name: \"cpu\"\n min: 64 C\n max: 128 C\n - name: \"memory\"\n min: 512 GB\n max: 1024 GB\n\ngrade 8, the last one likes below. No matter what Max value you pass, the meaning of Max value in this grade is infinite. You can pass any number greater than Min value. - grade: 8\n range:\n - name: \"cpu\"\n min: 128 C\n max: MAXINT\n - name: \"memory\"\n min: 1024 GB\n max: MAXINT", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ResourceModel"), + }, + }, + }, + }, + }, }, Required: []string{"syncMode"}, }, }, Dependencies: []string{ - "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.LocalSecretReference", "k8s.io/api/core/v1.Taint"}, + "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.LocalSecretReference", "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ResourceModel", "k8s.io/api/core/v1.Taint"}, } } @@ -870,6 +914,78 @@ func schema_pkg_apis_cluster_v1alpha1_NodeSummary(ref common.ReferenceCallback) } } +func schema_pkg_apis_cluster_v1alpha1_ResourceModel(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ResourceModel describes the modeling that you want to statistics.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "grade": { + SchemaProps: spec.SchemaProps{ + Description: "Grade is the index for the resource modeling.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "ranges": { + SchemaProps: spec.SchemaProps{ + Description: "Ranges describes the resource quota ranges.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ResourceModelRange"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.ResourceModelRange"}, + } +} + +func schema_pkg_apis_cluster_v1alpha1_ResourceModelRange(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ResourceModelRange describes the detail of each modeling quota that ranges from min to max. Please pay attention, by default, the value of min can be inclusive, and the value of max cannot be inclusive. E.g. in an interval, min = 2, max =10 is set, which means the interval [2,10). This rule ensure that all intervals have the same meaning. If the last interval is +∞, it is definitely unreachable. Therefore, we define the right interval as the open interval. For a valid interval, the value on the right is greater than the value on the left, in other words, max must be greater than min.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the name for the resource that you want to categorize.", + Type: []string{"string"}, + Format: "", + }, + }, + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Min is the minimum amount of this resource represented by resource name.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Max is the maximum amount of this resource represented by resource name. Special Instructions, for the last ResourceModelRange, which no matter what Max value you pass, the meaning is infinite. Because for the last item, any ResourceModelRange's quota larger than Min will be classified to the last one. Of course, the value of the Max field is always greater than the value of the Min field. It should be true in any case.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + func schema_pkg_apis_cluster_v1alpha1_ResourceSummary(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -922,11 +1038,25 @@ func schema_pkg_apis_cluster_v1alpha1_ResourceSummary(ref common.ReferenceCallba }, }, }, + "allocatableModelings": { + SchemaProps: spec.SchemaProps{ + Description: "AllocatableModelings represents the statistical resource modeling.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.AllocatableModeling"), + }, + }, + }, + }, + }, }, }, }, Dependencies: []string{ - "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1.AllocatableModeling", "k8s.io/apimachinery/pkg/api/resource.Quantity"}, } }