diff --git a/apis/policy/v1alpha1/clustervalidatepolicy_types.go b/apis/policy/v1alpha1/clustervalidatepolicy_types.go index 04e6295..b342307 100644 --- a/apis/policy/v1alpha1/clustervalidatepolicy_types.go +++ b/apis/policy/v1alpha1/clustervalidatepolicy_types.go @@ -152,7 +152,8 @@ type ValidateCondition struct { // ValueProcess defines operation to handle value to compare. // E.g. operation: '*' -// operationWith: 50% # or 0.5 +// +// operationWith: 50% # or 0.5 type ValueProcess struct { // Operation defines the type of operate value, and it should work with operationWith. // For example, operation is `*` and operationWith is 0.5 then in cue the value will be multiplied by 0.5. diff --git a/apis/policy/v1alpha1/groupversion_info.go b/apis/policy/v1alpha1/groupversion_info.go index 9dbfd79..b56bd03 100644 --- a/apis/policy/v1alpha1/groupversion_info.go +++ b/apis/policy/v1alpha1/groupversion_info.go @@ -15,8 +15,8 @@ limitations under the License. */ // Package v1alpha1 contains API Schema definitions for the policy v1alpha1 API group -//+kubebuilder:object:generate=true -//+groupName=policy.kcloudlabs.io +// +kubebuilder:object:generate=true +// +groupName=policy.kcloudlabs.io package v1alpha1 import ( diff --git a/apis/policy/v1alpha1/overridepolicy_types.go b/apis/policy/v1alpha1/overridepolicy_types.go index 3120f3e..5d83b00 100644 --- a/apis/policy/v1alpha1/overridepolicy_types.go +++ b/apis/policy/v1alpha1/overridepolicy_types.go @@ -87,6 +87,7 @@ type ResourceSelector struct { // - RenderCue // - Cue // - Plaintext +// - Origin type Overriders struct { // Plaintext represents override rules defined with plaintext overriders. // +optional @@ -106,6 +107,9 @@ type Overriders struct { // Don't modify the value of this field, modify Rules instead of. // +optional RenderedCue string `json:"renderedCue,omitempty"` + + // Origin represents override rule defined by K8s origin field. + Origin []OverrideRuleOrigin `json:"origin,omitempty"` } // OverrideRuleType is definition for type of single override rule template @@ -157,6 +161,112 @@ const ( FromHTTP ValueRefFrom = "http" ) +// OverrideRuleOriginType is the definition type of most fields from k8s +// +kubebuilder:validation:Enum=annotations;labels;nodeSelector;hostNetwork;schedulerName;resourceRequirements;resourceOversell;affinity;tolerations;topologySpreadConstraints +type OverrideRuleOriginType string + +const ( + // OverrideRuleOriginTypeAnnotations - `annotations` + OverrideRuleOriginTypeAnnotations OverrideRuleOriginType = "annotations" + // OverrideRuleOriginLabels - `labels` + OverrideRuleOriginLabels OverrideRuleOriginType = "labels" + // OverrideRuleOriginNodeSelector - `nodeSelector` + OverrideRuleOriginNodeSelector OverrideRuleOriginType = "nodeSelector" + // OverrideRuleOriginHostNetwork - `hostNetwork` + OverrideRuleOriginHostNetwork OverrideRuleOriginType = "hostNetwork" + // OverrideRuleOriginSchedulerName - `schedulerName` + OverrideRuleOriginSchedulerName OverrideRuleOriginType = "schedulerName" + // OverrideRuleOriginResourceRequirements - `resourceRequirements` + OverrideRuleOriginResourceRequirements OverrideRuleOriginType = "resourceRequirements" + // OverrideRuleOriginResourceOversell - `resourceOversell` + OverrideRuleOriginResourceOversell OverrideRuleOriginType = "resourceOversell" + // OverrideRuleOriginAffinity - `affinity` + OverrideRuleOriginAffinity OverrideRuleOriginType = "affinity" + // OverrideRuleOriginTolerations - `tolerations` + OverrideRuleOriginTolerations OverrideRuleOriginType = "tolerations" + // OverrideRuleOriginTopologySpreadConstraints - `topologySpreadConstraints` + OverrideRuleOriginTopologySpreadConstraints OverrideRuleOriginType = "topologySpreadConstraints" +) + +type ResourceType string + +const ( + RequestResourceType ResourceType = "requests" + LimitResourceType ResourceType = "limits" +) + +// OverrideRuleOrigin represents a set of rule definition +type OverrideRuleOrigin struct { + // Type represents current rule operate field type. + // +kubebuilder:validation:Enum=annotations;labels;nodeSelector;hostNetwork;schedulerName;resourceRequirements;resourceOversell;affinity;tolerations;topologySpreadConstraints + // +required + Type OverrideRuleOriginType `json:"type,omitempty"` + // Operation represents current operation type. + // +kubebuilder:validation:Enum=add;replace;remove + // +required + Operation OverriderOperator `json:"operation,omitempty"` + // Replace represents whether full replacement is required + // +optional + Replace bool `json:"replace,omitempty"` + // ResourceOversellRule represents the oversold ratio of a resource + // +optional + ResourceOversell map[ResourceType]map[string]Float64 `json:"resourcesOversell,omitempty"` + // ContainerCount represents which container it is, the first container is 0. + // Only affects ResourceRequirements and ResourceOversell + // Note: For the same 'OverrideRuleOrigin', only one of 'ResourceRequirements' and 'ResourceOversell' can be present. + // +optional + ContainerCount int `json:"containerCount,omitempty"` + // ResourceRequirements represents the oversold ratio of a resource + // +optional + ResourceRequirements v1.ResourceRequirements `json:"resourceRequirements,omitempty"` + // If specified, the pod's tolerations. + // +optional + Tolerations []v1.Toleration `json:"tolerations,omitempty"` + // If specified, the pod's scheduling constraints + // +optional + Affinity *v1.Affinity `json:"affinity,omitempty"` + // TopologySpreadConstraints describes how a group of pods ought to spread across topology + // domains. Scheduler will schedule pods in a way which abides by the constraints. + // This field is alpha-level and is only honored by clusters that enables the EvenPodsSpread + // feature. + // All topologySpreadConstraints are ANDed. + // +optional + // +patchMergeKey=topologyKey + // +patchStrategy=merge + // +listType=map + // +listMapKey=topologyKey + // +listMapKey=whenUnsatisfiable + TopologySpreadConstraints []v1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` + // If specified, the pod will be dispatched by specified scheduler. + // If not specified, the pod will be dispatched by default scheduler. + // +optional + SchedulerName string `json:"schedulerName,omitempty"` + // Host networking requested for this pod. Use the host's network namespace. + // If this option is set, the ports that will be used must be specified. + // Default to false. + // +k8s:conversion-gen=false + // +optional + HostNetwork bool `json:"hostNetwork,omitempty"` + // NodeSelector is a selector which must be true for the pod to fit on a node. + // Selector which must match a node's labels for the pod to be scheduled on that node. + // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + // +optional + // +mapType=atomic + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + // More info: http://kubernetes.io/docs/user-guide/annotations + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + // Map of string keys and values that can be used to organize and categorize + // (scope and select) objects. May match selectors of replication controllers + // and services. + // More info: http://kubernetes.io/docs/user-guide/labels + // +optional + Labels map[string]string `json:"labels,omitempty"` +} + // OverrideRuleTemplate represents a single template of rule definition type OverrideRuleTemplate struct { // Type represents current rule operate field type. diff --git a/apis/policy/v1alpha1/zz_generated.deepcopy.go b/apis/policy/v1alpha1/zz_generated.deepcopy.go index 3a88601..73dd9d1 100644 --- a/apis/policy/v1alpha1/zz_generated.deepcopy.go +++ b/apis/policy/v1alpha1/zz_generated.deepcopy.go @@ -423,6 +423,79 @@ func (in *OverridePolicySpec) DeepCopy() *OverridePolicySpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OverrideRuleOrigin) DeepCopyInto(out *OverrideRuleOrigin) { + *out = *in + if in.ResourceOversell != nil { + in, out := &in.ResourceOversell, &out.ResourceOversell + *out = make(map[ResourceType]map[string]Float64, len(*in)) + for key, val := range *in { + var outVal map[string]Float64 + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(map[string]Float64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + (*out)[key] = outVal + } + } + in.ResourceRequirements.DeepCopyInto(&out.ResourceRequirements) + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]corev1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(corev1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.TopologySpreadConstraints != nil { + in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints + *out = make([]corev1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverrideRuleOrigin. +func (in *OverrideRuleOrigin) DeepCopy() *OverrideRuleOrigin { + if in == nil { + return nil + } + out := new(OverrideRuleOrigin) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OverrideRuleTemplate) DeepCopyInto(out *OverrideRuleTemplate) { *out = *in @@ -489,6 +562,13 @@ func (in *Overriders) DeepCopyInto(out *Overriders) { *out = new(OverrideRuleTemplate) (*in).DeepCopyInto(*out) } + if in.Origin != nil { + in, out := &in.Origin, &out.Origin + *out = make([]OverrideRuleOrigin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Overriders. diff --git a/charts/_crds/bases/policy.kcloudlabs.io_clusteroverridepolicies.yaml b/charts/_crds/bases/policy.kcloudlabs.io_clusteroverridepolicies.yaml index 2c3e2c7..de6920d 100644 --- a/charts/_crds/bases/policy.kcloudlabs.io_clusteroverridepolicies.yaml +++ b/charts/_crds/bases/policy.kcloudlabs.io_clusteroverridepolicies.yaml @@ -52,6 +52,1360 @@ spec: description: Cue represents override rules defined with cue code. type: string + origin: + description: Origin represents override rule defined by + K8s origin field. + items: + description: OverrideRuleOrigin represents a set of rule + definition + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling + rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to + schedule pods to nodes that satisfy the + affinity expressions specified by this field, + but it may choose a node that violates one + or more of the expressions. The node that + is most preferred is the one with the greatest + sum of weights, i.e. for each node that + meets all of the scheduling requirements + (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum + by iterating through the elements of this + field and adding "weight" to the sum if + the node matches the corresponding matchExpressions; + the node(s) with the highest sum are the + most preferred. + items: + description: An empty preferred scheduling + term matches all objects with implicit + weight 0 (i.e. it's a no-op). A null preferred + scheduling term matches no objects (i.e. + is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with + matching the corresponding nodeSelectorTerm, + in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto + the node. If the affinity requirements specified + by this field cease to be met at some point + during pod execution (e.g. due to an update), + the system may or may not try to eventually + evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node + selector terms. The terms are ORed. + items: + description: A null or empty node selector + term matches no objects. The requirements + of them are ANDed. The TopologySelectorTerm + type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling + rules (e.g. co-locate this pod in the same node, + zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to + schedule pods to nodes that satisfy the + affinity expressions specified by this field, + but it may choose a node that violates one + or more of the expressions. The node that + is most preferred is the one with the greatest + sum of weights, i.e. for each node that + meets all of the scheduling requirements + (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum + by iterating through the elements of this + field and adding "weight" to the sum if + the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest + sum are the most preferred. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added + per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity + term, associated with the corresponding + weight. + properties: + labelSelector: + description: A label query over + a set of resources, in this case + pods. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over + the set of namespaces that the + term applies to. The term is applied + to the union of the namespaces + selected by this field and the + ones listed in the namespaces + field. null selector and null + or empty namespaces list means + "this pod's namespace". An empty + selector ({}) matches all namespaces. + This field is beta-level and is + only honored when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies + a static list of namespace names + that the term applies to. The + term is applied to the union of + the namespaces listed in this + field and the ones selected by + namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be + co-located (affinity) or not co-located + (anti-affinity) with the pods + matching the labelSelector in + the specified namespaces, where + co-located is defined as running + on a node whose value of the label + with key topologyKey matches that + of any node on which any of the + selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with + matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto + the node. If the affinity requirements specified + by this field cease to be met at some point + during pod execution (e.g. due to a pod + label update), the system may or may not + try to eventually evict the pod from its + node. When there are multiple elements, + the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely + those matching the labelSelector relative + to the given namespace(s)) that this pod + should be co-located (affinity) or not + co-located (anti-affinity) with, where + co-located is defined as running on a + node whose value of the label with key + matches that of any node + on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's + namespace". An empty selector ({}) + matches all namespaces. This field + is beta-level and is only honored + when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a + static list of namespace names that + the term applies to. The term is applied + to the union of the namespaces listed + in this field and the ones selected + by namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running on + a node whose value of the label with + key topologyKey matches that of any + node on which any of the selected + pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling + rules (e.g. avoid putting this pod in the same + node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to + schedule pods to nodes that satisfy the + anti-affinity expressions specified by this + field, but it may choose a node that violates + one or more of the expressions. The node + that is most preferred is the one with the + greatest sum of weights, i.e. for each node + that meets all of the scheduling requirements + (resource request, requiredDuringScheduling + anti-affinity expressions, etc.), compute + a sum by iterating through the elements + of this field and adding "weight" to the + sum if the node has pods which matches the + corresponding podAffinityTerm; the node(s) + with the highest sum are the most preferred. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added + per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity + term, associated with the corresponding + weight. + properties: + labelSelector: + description: A label query over + a set of resources, in this case + pods. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over + the set of namespaces that the + term applies to. The term is applied + to the union of the namespaces + selected by this field and the + ones listed in the namespaces + field. null selector and null + or empty namespaces list means + "this pod's namespace". An empty + selector ({}) matches all namespaces. + This field is beta-level and is + only honored when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies + a static list of namespace names + that the term applies to. The + term is applied to the union of + the namespaces listed in this + field and the ones selected by + namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be + co-located (affinity) or not co-located + (anti-affinity) with the pods + matching the labelSelector in + the specified namespaces, where + co-located is defined as running + on a node whose value of the label + with key topologyKey matches that + of any node on which any of the + selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with + matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto + the node. If the anti-affinity requirements + specified by this field cease to be met + at some point during pod execution (e.g. + due to a pod label update), the system may + or may not try to eventually evict the pod + from its node. When there are multiple elements, + the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely + those matching the labelSelector relative + to the given namespace(s)) that this pod + should be co-located (affinity) or not + co-located (anti-affinity) with, where + co-located is defined as running on a + node whose value of the label with key + matches that of any node + on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's + namespace". An empty selector ({}) + matches all namespaces. This field + is beta-level and is only honored + when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a + static list of namespace names that + the term applies to. The term is applied + to the union of the namespaces listed + in this field and the ones selected + by namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running on + a node whose value of the label with + key topologyKey matches that of any + node on which any of the selected + pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value + map stored with a resource that may be set by external + tools to store and retrieve arbitrary metadata. + They are not queryable and should be preserved when + modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations' + type: object + containerCount: + description: 'ContainerCount represents which container + it is, the first container is 0. Only affects ResourceRequirements + and ResourceOversell Note: For the same ''OverrideRuleOrigin'', + only one of ''ResourceRequirements'' and ''ResourceOversell'' + can be present.' + type: integer + hostNetwork: + description: Host networking requested for this pod. + Use the host's network namespace. If this option + is set, the ports that will be used must be specified. + Default to false. + type: boolean + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can + be used to organize and categorize (scope and select) + objects. May match selectors of replication controllers + and services. More info: http://kubernetes.io/docs/user-guide/labels' + type: object + nodeSelector: + additionalProperties: + type: string + description: 'NodeSelector is a selector which must + be true for the pod to fit on a node. Selector which + must match a node''s labels for the pod to be scheduled + on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + x-kubernetes-map-type: atomic + operation: + description: Operation represents current operation + type. + enum: + - add + - replace + - remove + type: string + replace: + description: Replace represents whether full replacement + is required + type: boolean + resourceRequirements: + description: ResourceRequirements represents the oversold + ratio of a resource + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + resourcesOversell: + additionalProperties: + additionalProperties: + description: Float64 is alias for float64 as string + type: string + type: object + description: ResourceOversellRule represents the oversold + ratio of a resource + type: object + schedulerName: + description: If specified, the pod will be dispatched + by specified scheduler. If not specified, the pod + will be dispatched by default scheduler. + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: The pod this Toleration is attached + to tolerates any taint that matches the triple + using the matching operator + . + properties: + effect: + description: Effect indicates the taint effect + to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, + PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; + this combination means to match all values + and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and + Equal. Defaults to Equal. Exists is equivalent + to wildcard for value, so that a pod can tolerate + all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the + period of time the toleration (which must + be of effect NoExecute, otherwise this field + is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint + forever (do not evict). Zero and negative + values will be treated as 0 (evict immediately) + by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration + matches to. If the operator is Exists, the + value should be empty, otherwise just a regular + string. + type: string + type: object + type: array + topologySpreadConstraints: + description: TopologySpreadConstraints describes how + a group of pods ought to spread across topology + domains. Scheduler will schedule pods in a way which + abides by the constraints. This field is alpha-level + and is only honored by clusters that enables the + EvenPodsSpread feature. All topologySpreadConstraints + are ANDed. + items: + description: TopologySpreadConstraint specifies + how to spread matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching + pods. Pods that match this label selector + are counted to determine the number of pods + in their corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + maxSkew: + description: 'MaxSkew describes the degree to + which pods may be unevenly distributed. When + `whenUnsatisfiable=DoNotSchedule`, it is the + maximum permitted difference between the number + of matching pods in the target topology and + the global minimum. For example, in a 3-zone + cluster, MaxSkew is set to 1, and pods with + the same labelSelector spread as 1/1/0: | + zone1 | zone2 | zone3 | | P | P | | + - if MaxSkew is 1, incoming pod can only be + scheduled to zone3 to become 1/1/1; scheduling + it onto zone1(zone2) would make the ActualSkew(2-0) + on zone1(zone2) violate MaxSkew(1). - if MaxSkew + is 2, incoming pod can be scheduled onto any + zone. When `whenUnsatisfiable=ScheduleAnyway`, + it is used to give higher precedence to topologies + that satisfy it. It''s a required field. Default + value is 1 and 0 is not allowed.' + format: int32 + type: integer + topologyKey: + description: TopologyKey is the key of node + labels. Nodes that have a label with this + key and identical values are considered to + be in the same topology. We consider each + as a "bucket", and try to put + balanced number of pods into each bucket. + It's a required field. + type: string + whenUnsatisfiable: + description: 'WhenUnsatisfiable indicates how + to deal with a pod if it doesn''t satisfy + the spread constraint. - DoNotSchedule (default) + tells the scheduler not to schedule it. - + ScheduleAnyway tells the scheduler to schedule + the pod in any location, but giving higher + precedence to topologies that would help reduce + the skew. A constraint is considered "Unsatisfiable" + for an incoming pod if and only if every possible + node assignment for that pod would violate + "MaxSkew" on some topology. For example, in + a 3-zone cluster, MaxSkew is set to 1, and + pods with the same labelSelector spread as + 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, + incoming pod can only be scheduled to zone2(zone3) + to become 3/2/1(3/1/2) as ActualSkew(2-1) + on zone2(zone3) satisfies MaxSkew(1). In other + words, the cluster can still be imbalanced, + but scheduler won''t make it *more* imbalanced. + It''s a required field.' + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + type: + allOf: + - enum: + - annotations + - labels + - nodeSelector + - hostNetwork + - schedulerName + - resourceRequirements + - resourceOversell + - affinity + - tolerations + - topologySpreadConstraints + - enum: + - annotations + - labels + - nodeSelector + - hostNetwork + - schedulerName + - resourceRequirements + - resourceOversell + - affinity + - tolerations + - topologySpreadConstraints + description: Type represents current rule operate + field type. + type: string + type: object + type: array plaintext: description: Plaintext represents override rules defined with plaintext overriders. diff --git a/charts/_crds/bases/policy.kcloudlabs.io_overridepolicies.yaml b/charts/_crds/bases/policy.kcloudlabs.io_overridepolicies.yaml index e880aba..eb9c515 100644 --- a/charts/_crds/bases/policy.kcloudlabs.io_overridepolicies.yaml +++ b/charts/_crds/bases/policy.kcloudlabs.io_overridepolicies.yaml @@ -52,6 +52,1360 @@ spec: description: Cue represents override rules defined with cue code. type: string + origin: + description: Origin represents override rule defined by + K8s origin field. + items: + description: OverrideRuleOrigin represents a set of rule + definition + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling + rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to + schedule pods to nodes that satisfy the + affinity expressions specified by this field, + but it may choose a node that violates one + or more of the expressions. The node that + is most preferred is the one with the greatest + sum of weights, i.e. for each node that + meets all of the scheduling requirements + (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum + by iterating through the elements of this + field and adding "weight" to the sum if + the node matches the corresponding matchExpressions; + the node(s) with the highest sum are the + most preferred. + items: + description: An empty preferred scheduling + term matches all objects with implicit + weight 0 (i.e. it's a no-op). A null preferred + scheduling term matches no objects (i.e. + is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with + matching the corresponding nodeSelectorTerm, + in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto + the node. If the affinity requirements specified + by this field cease to be met at some point + during pod execution (e.g. due to an update), + the system may or may not try to eventually + evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node + selector terms. The terms are ORed. + items: + description: A null or empty node selector + term matches no objects. The requirements + of them are ANDed. The TopologySelectorTerm + type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains + values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key + that the selector applies + to. + type: string + operator: + description: Represents a + key's relationship to a + set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string + values. If the operator + is In or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the values + array must be empty. If + the operator is Gt or Lt, + the values array must have + a single element, which + will be interpreted as an + integer. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling + rules (e.g. co-locate this pod in the same node, + zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to + schedule pods to nodes that satisfy the + affinity expressions specified by this field, + but it may choose a node that violates one + or more of the expressions. The node that + is most preferred is the one with the greatest + sum of weights, i.e. for each node that + meets all of the scheduling requirements + (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum + by iterating through the elements of this + field and adding "weight" to the sum if + the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest + sum are the most preferred. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added + per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity + term, associated with the corresponding + weight. + properties: + labelSelector: + description: A label query over + a set of resources, in this case + pods. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over + the set of namespaces that the + term applies to. The term is applied + to the union of the namespaces + selected by this field and the + ones listed in the namespaces + field. null selector and null + or empty namespaces list means + "this pod's namespace". An empty + selector ({}) matches all namespaces. + This field is beta-level and is + only honored when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies + a static list of namespace names + that the term applies to. The + term is applied to the union of + the namespaces listed in this + field and the ones selected by + namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be + co-located (affinity) or not co-located + (anti-affinity) with the pods + matching the labelSelector in + the specified namespaces, where + co-located is defined as running + on a node whose value of the label + with key topologyKey matches that + of any node on which any of the + selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with + matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto + the node. If the affinity requirements specified + by this field cease to be met at some point + during pod execution (e.g. due to a pod + label update), the system may or may not + try to eventually evict the pod from its + node. When there are multiple elements, + the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely + those matching the labelSelector relative + to the given namespace(s)) that this pod + should be co-located (affinity) or not + co-located (anti-affinity) with, where + co-located is defined as running on a + node whose value of the label with key + matches that of any node + on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's + namespace". An empty selector ({}) + matches all namespaces. This field + is beta-level and is only honored + when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a + static list of namespace names that + the term applies to. The term is applied + to the union of the namespaces listed + in this field and the ones selected + by namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running on + a node whose value of the label with + key topologyKey matches that of any + node on which any of the selected + pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling + rules (e.g. avoid putting this pod in the same + node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to + schedule pods to nodes that satisfy the + anti-affinity expressions specified by this + field, but it may choose a node that violates + one or more of the expressions. The node + that is most preferred is the one with the + greatest sum of weights, i.e. for each node + that meets all of the scheduling requirements + (resource request, requiredDuringScheduling + anti-affinity expressions, etc.), compute + a sum by iterating through the elements + of this field and adding "weight" to the + sum if the node has pods which matches the + corresponding podAffinityTerm; the node(s) + with the highest sum are the most preferred. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added + per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity + term, associated with the corresponding + weight. + properties: + labelSelector: + description: A label query over + a set of resources, in this case + pods. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over + the set of namespaces that the + term applies to. The term is applied + to the union of the namespaces + selected by this field and the + ones listed in the namespaces + field. null selector and null + or empty namespaces list means + "this pod's namespace". An empty + selector ({}) matches all namespaces. + This field is beta-level and is + only honored when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a + key, and an operator that + relates the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator + represents a key's relationship + to a set of values. + Valid operators are + In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is + an array of string values. + If the operator is In + or NotIn, the values + array must be non-empty. + If the operator is Exists + or DoesNotExist, the + values array must be + empty. This array is + replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in the + matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies + a static list of namespace names + that the term applies to. The + term is applied to the union of + the namespaces listed in this + field and the ones selected by + namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be + co-located (affinity) or not co-located + (anti-affinity) with the pods + matching the labelSelector in + the specified namespaces, where + co-located is defined as running + on a node whose value of the label + with key topologyKey matches that + of any node on which any of the + selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with + matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto + the node. If the anti-affinity requirements + specified by this field cease to be met + at some point during pod execution (e.g. + due to a pod label update), the system may + or may not try to eventually evict the pod + from its node. When there are multiple elements, + the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely + those matching the labelSelector relative + to the given namespace(s)) that this pod + should be co-located (affinity) or not + co-located (anti-affinity) with, where + co-located is defined as running on a + node whose value of the label with key + matches that of any node + on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's + namespace". An empty selector ({}) + matches all namespaces. This field + is beta-level and is only honored + when PodAffinityNamespaceSelector + feature is enabled. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a + static list of namespace names that + the term applies to. The term is applied + to the union of the namespaces listed + in this field and the ones selected + by namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running on + a node whose value of the label with + key topologyKey matches that of any + node on which any of the selected + pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value + map stored with a resource that may be set by external + tools to store and retrieve arbitrary metadata. + They are not queryable and should be preserved when + modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations' + type: object + containerCount: + description: 'ContainerCount represents which container + it is, the first container is 0. Only affects ResourceRequirements + and ResourceOversell Note: For the same ''OverrideRuleOrigin'', + only one of ''ResourceRequirements'' and ''ResourceOversell'' + can be present.' + type: integer + hostNetwork: + description: Host networking requested for this pod. + Use the host's network namespace. If this option + is set, the ports that will be used must be specified. + Default to false. + type: boolean + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can + be used to organize and categorize (scope and select) + objects. May match selectors of replication controllers + and services. More info: http://kubernetes.io/docs/user-guide/labels' + type: object + nodeSelector: + additionalProperties: + type: string + description: 'NodeSelector is a selector which must + be true for the pod to fit on a node. Selector which + must match a node''s labels for the pod to be scheduled + on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + x-kubernetes-map-type: atomic + operation: + description: Operation represents current operation + type. + enum: + - add + - replace + - remove + type: string + replace: + description: Replace represents whether full replacement + is required + type: boolean + resourceRequirements: + description: ResourceRequirements represents the oversold + ratio of a resource + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + resourcesOversell: + additionalProperties: + additionalProperties: + description: Float64 is alias for float64 as string + type: string + type: object + description: ResourceOversellRule represents the oversold + ratio of a resource + type: object + schedulerName: + description: If specified, the pod will be dispatched + by specified scheduler. If not specified, the pod + will be dispatched by default scheduler. + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: The pod this Toleration is attached + to tolerates any taint that matches the triple + using the matching operator + . + properties: + effect: + description: Effect indicates the taint effect + to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, + PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; + this combination means to match all values + and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and + Equal. Defaults to Equal. Exists is equivalent + to wildcard for value, so that a pod can tolerate + all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the + period of time the toleration (which must + be of effect NoExecute, otherwise this field + is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint + forever (do not evict). Zero and negative + values will be treated as 0 (evict immediately) + by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration + matches to. If the operator is Exists, the + value should be empty, otherwise just a regular + string. + type: string + type: object + type: array + topologySpreadConstraints: + description: TopologySpreadConstraints describes how + a group of pods ought to spread across topology + domains. Scheduler will schedule pods in a way which + abides by the constraints. This field is alpha-level + and is only honored by clusters that enables the + EvenPodsSpread feature. All topologySpreadConstraints + are ANDed. + items: + description: TopologySpreadConstraint specifies + how to spread matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching + pods. Pods that match this label selector + are counted to determine the number of pods + in their corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + maxSkew: + description: 'MaxSkew describes the degree to + which pods may be unevenly distributed. When + `whenUnsatisfiable=DoNotSchedule`, it is the + maximum permitted difference between the number + of matching pods in the target topology and + the global minimum. For example, in a 3-zone + cluster, MaxSkew is set to 1, and pods with + the same labelSelector spread as 1/1/0: | + zone1 | zone2 | zone3 | | P | P | | + - if MaxSkew is 1, incoming pod can only be + scheduled to zone3 to become 1/1/1; scheduling + it onto zone1(zone2) would make the ActualSkew(2-0) + on zone1(zone2) violate MaxSkew(1). - if MaxSkew + is 2, incoming pod can be scheduled onto any + zone. When `whenUnsatisfiable=ScheduleAnyway`, + it is used to give higher precedence to topologies + that satisfy it. It''s a required field. Default + value is 1 and 0 is not allowed.' + format: int32 + type: integer + topologyKey: + description: TopologyKey is the key of node + labels. Nodes that have a label with this + key and identical values are considered to + be in the same topology. We consider each + as a "bucket", and try to put + balanced number of pods into each bucket. + It's a required field. + type: string + whenUnsatisfiable: + description: 'WhenUnsatisfiable indicates how + to deal with a pod if it doesn''t satisfy + the spread constraint. - DoNotSchedule (default) + tells the scheduler not to schedule it. - + ScheduleAnyway tells the scheduler to schedule + the pod in any location, but giving higher + precedence to topologies that would help reduce + the skew. A constraint is considered "Unsatisfiable" + for an incoming pod if and only if every possible + node assignment for that pod would violate + "MaxSkew" on some topology. For example, in + a 3-zone cluster, MaxSkew is set to 1, and + pods with the same labelSelector spread as + 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, + incoming pod can only be scheduled to zone2(zone3) + to become 3/2/1(3/1/2) as ActualSkew(2-1) + on zone2(zone3) satisfies MaxSkew(1). In other + words, the cluster can still be imbalanced, + but scheduler won''t make it *more* imbalanced. + It''s a required field.' + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + type: + allOf: + - enum: + - annotations + - labels + - nodeSelector + - hostNetwork + - schedulerName + - resourceRequirements + - resourceOversell + - affinity + - tolerations + - topologySpreadConstraints + - enum: + - annotations + - labels + - nodeSelector + - hostNetwork + - schedulerName + - resourceRequirements + - resourceOversell + - affinity + - tolerations + - topologySpreadConstraints + description: Type represents current rule operate + field type. + type: string + type: object + type: array plaintext: description: Plaintext represents override rules defined with plaintext overriders. diff --git a/client/clientset/versioned/fake/register.go b/client/clientset/versioned/fake/register.go index 07beb05..7e3835b 100644 --- a/client/clientset/versioned/fake/register.go +++ b/client/clientset/versioned/fake/register.go @@ -36,14 +36,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/client/clientset/versioned/scheme/register.go b/client/clientset/versioned/scheme/register.go index dc9f43b..3294079 100644 --- a/client/clientset/versioned/scheme/register.go +++ b/client/clientset/versioned/scheme/register.go @@ -36,14 +36,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/utils/interrupter/overridepolicy_interrupter.go b/utils/interrupter/overridepolicy_interrupter.go index 304e75b..253193e 100644 --- a/utils/interrupter/overridepolicy_interrupter.go +++ b/utils/interrupter/overridepolicy_interrupter.go @@ -5,14 +5,19 @@ import ( "encoding/json" "fmt" "reflect" + "strings" "time" jsonpatchv2 "gomodules.xyz/jsonpatch/v2" admissionv1 "k8s.io/api/admission/v1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" + validationutil "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -112,6 +117,14 @@ func NewOverridePolicyInterrupter(interrupter PolicyInterrupter, tm tokenmanager func (o *overridePolicyInterrupter) validateOverridePolicy(objSpec *policyv1alpha1.OverridePolicySpec) error { for _, overrideRule := range objSpec.OverrideRules { + if validateOverrideRuleOrigin(overrideRule.Overriders.Origin) { + return fmt.Errorf("cop is invalid: in the same cop, there cannot be a unified containerCount in OverrideRuleOriginResourceRequirements and OverrideRuleOriginResourceOversell") + } + + if err := o.validateOverridePolicyOriginField(overrideRule); err != nil { + return err + } + if err := o.cueManager.Validate([]byte(overrideRule.Overriders.RenderedCue)); err != nil { return err } @@ -120,6 +133,19 @@ func (o *overridePolicyInterrupter) validateOverridePolicy(objSpec *policyv1alph return nil } +func (o *overridePolicyInterrupter) validateOverridePolicyOriginField(overrideRule policyv1alpha1.RuleWithOperation) error { + for i := range overrideRule.Overriders.Origin { + if len(overrideRule.Overriders.Origin[i].Tolerations) > 0 { + errs := validateTolerations(overrideRule.Overriders.Origin[i].Tolerations) + if len(errs) > 0 { + return errs.ToAggregate() + } + } + } + + return nil +} + func (o *overridePolicyInterrupter) patchOverridePolicy(policy *policyv1alpha1.OverridePolicy, operation admissionv1.Operation) ([]jsonpatchv2.JsonPatchOperation, error) { if operation == admissionv1.Delete { return nil, nil @@ -318,3 +344,112 @@ func compareCallbackMap(cur, old map[string]*tokenCallbackImpl) (update, remove return } + +func validateOverrideRuleOrigin(overriders []policyv1alpha1.OverrideRuleOrigin) bool { + var rr []int + var ro []int + for i := range overriders { + if overriders[i].Type == policyv1alpha1.OverrideRuleOriginResourceRequirements { + rr = append(rr, overriders[i].ContainerCount) + } + + if overriders[i].Type == policyv1alpha1.OverrideRuleOriginResourceOversell { + ro = append(ro, overriders[i].ContainerCount) + } + } + + rrMap := make(map[int]bool) + for _, v := range rr { + rrMap[v] = true + } + + for _, v := range ro { + if rrMap[v] { + return true + } + } + + return false +} + +func validateTolerations(tolerations []corev1.Toleration) field.ErrorList { + path := field.NewPath("spec", "affinity", "toleration") + allErrors := field.ErrorList{} + for i, toleration := range tolerations { + toleration := toleration + idxPath := path.Index(i) + // validate the toleration key + if len(toleration.Key) > 0 { + allErrors = append(allErrors, validation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...) + } + + // empty toleration key with Exists operator and empty value means match all taints + if len(toleration.Key) == 0 && toleration.Operator != corev1.TolerationOpExists { + allErrors = append(allErrors, + field.Invalid(idxPath.Child("operator"), + toleration.Operator, + "operator must be Exists when `key` is empty, which means \"match all values and all keys\"")) + } + + if toleration.TolerationSeconds != nil && toleration.Effect != corev1.TaintEffectNoExecute { + allErrors = append(allErrors, + field.Invalid(idxPath.Child("effect"), + toleration.Effect, + "effect must be 'NoExecute' when `tolerationSeconds` is set")) + } + + // validate toleration operator and value + switch toleration.Operator { + // empty operator means Equal + case corev1.TolerationOpEqual, "": + if errs := validationutil.IsValidLabelValue(toleration.Value); len(errs) != 0 { + allErrors = append(allErrors, + field.Invalid(idxPath.Child("operator"), + toleration.Value, strings.Join(errs, ";"))) + } + case corev1.TolerationOpExists: + if len(toleration.Value) > 0 { + allErrors = append(allErrors, + field.Invalid(idxPath.Child("operator"), + toleration, "value must be empty when `operator` is 'Exists'")) + } + default: + validValues := []string{string(corev1.TolerationOpEqual), string(corev1.TolerationOpExists)} + allErrors = append(allErrors, + field.NotSupported(idxPath.Child("operator"), + toleration.Operator, validValues)) + } + + // validate toleration effect, empty toleration effect means match all taint effects + if len(toleration.Effect) > 0 { + allErrors = append(allErrors, validateTaintEffect(&toleration.Effect, true, idxPath.Child("effect"))...) + } + } + + return allErrors +} + +// validateTaintEffect is used from validateTollerations and is a verbatim copy of the code +func validateTaintEffect(effect *corev1.TaintEffect, allowEmpty bool, fldPath *field.Path) field.ErrorList { + if !allowEmpty && len(*effect) == 0 { + return field.ErrorList{field.Required(fldPath, "")} + } + + allErrors := field.ErrorList{} + switch *effect { + // TODO: Replace next line with subsequent commented-out line when implement TaintEffectNoScheduleNoAdmit. + case corev1.TaintEffectNoSchedule, corev1.TaintEffectPreferNoSchedule, corev1.TaintEffectNoExecute: + // case core.TaintEffectNoSchedule, core.TaintEffectPreferNoSchedule, core.TaintEffectNoScheduleNoAdmit, + // core.TaintEffectNoExecute: + default: + validValues := []string{ + string(corev1.TaintEffectNoSchedule), + string(corev1.TaintEffectPreferNoSchedule), + string(corev1.TaintEffectNoExecute), + // TODO: Uncomment this block when implement TaintEffectNoScheduleNoAdmit. + // string(core.TaintEffectNoScheduleNoAdmit), + } + allErrors = append(allErrors, field.NotSupported(fldPath, *effect, validValues)) + } + return allErrors +} diff --git a/utils/origin/affinity.go b/utils/origin/affinity.go new file mode 100644 index 0000000..56a0af0 --- /dev/null +++ b/utils/origin/affinity.go @@ -0,0 +1,37 @@ +package origin + +import ( + "errors" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type Affinity struct { + Value *corev1.Affinity +} + +func (a *Affinity) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + if operator == policyv1alpha1.OverriderOpAdd || operator == policyv1alpha1.OverriderOpRemove { + return nil, errors.New("unsupported operator type error") + } + + k := rawObj.GetKind() + + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + } + + if k == PodKind { + op.Path = "/spec/affinity" + } else if k == DeploymentKind { + op.Path = "/spec/template/spec/affinity" + } else { + return nil, errors.New("unsupported kind type error") + } + + op.Value = a.Value + return op, nil +} diff --git a/utils/origin/annotations.go b/utils/origin/annotations.go new file mode 100644 index 0000000..90be382 --- /dev/null +++ b/utils/origin/annotations.go @@ -0,0 +1,47 @@ +package origin + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type Annotations struct { + Value map[string]string +} + +func (a *Annotations) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + currentAnnotations := rawObj.GetAnnotations() + newAnnotations := a.Value + + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + Path: "/metadata/annotations", + Value: newAnnotations, + } + + if Replace { + return op, nil + } + + switch operator { + case policyv1alpha1.OverriderOpAdd, policyv1alpha1.OverriderOpReplace: + if currentAnnotations == nil { + currentAnnotations = newAnnotations + } else { + for key, value := range newAnnotations { + currentAnnotations[key] = value + } + } + + case policyv1alpha1.OverriderOpRemove: + if currentAnnotations != nil { + for key := range newAnnotations { + delete(currentAnnotations, key) + } + } + } + + op.Value = currentAnnotations + return op, nil +} diff --git a/utils/origin/hostnetwork.go b/utils/origin/hostnetwork.go new file mode 100644 index 0000000..85888e5 --- /dev/null +++ b/utils/origin/hostnetwork.go @@ -0,0 +1,37 @@ +package origin + +import ( + "errors" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type HostNetWork struct { + Value bool +} + +func (h *HostNetWork) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + if operator == policyv1alpha1.OverriderOpAdd || operator == policyv1alpha1.OverriderOpRemove { + return nil, errors.New("unsupported operator type error") + } + + k := rawObj.GetKind() + newHostNetwork := h.Value + + op := &OverrideOption{ + Value: newHostNetwork, + Op: string(policyv1alpha1.OverriderOpReplace), + } + + if k == PodKind { + op.Path = "/spec/hostNetwork" + } else if k == DeploymentKind { + op.Path = "/spec/template/spec/hostNetwork" + } else { + return nil, errors.New("unsupported kind type error") + } + + return op, nil +} diff --git a/utils/origin/labels.go b/utils/origin/labels.go new file mode 100644 index 0000000..6153d0d --- /dev/null +++ b/utils/origin/labels.go @@ -0,0 +1,47 @@ +package origin + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type Labels struct { + Value map[string]string +} + +func (l *Labels) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + currentLabels := rawObj.GetLabels() + newLabels := l.Value + + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + Path: "/metadata/labels", + Value: newLabels, + } + + if Replace { + return op, nil + } + + switch operator { + case policyv1alpha1.OverriderOpAdd, policyv1alpha1.OverriderOpReplace: + if currentLabels == nil { + currentLabels = newLabels + } else { + for key, value := range newLabels { + currentLabels[key] = value + } + } + + case policyv1alpha1.OverriderOpRemove: + if currentLabels != nil { + for key := range newLabels { + delete(currentLabels, key) + } + } + } + + op.Value = currentLabels + return op, nil +} diff --git a/utils/origin/nodeselector.go b/utils/origin/nodeselector.go new file mode 100644 index 0000000..e1ebb07 --- /dev/null +++ b/utils/origin/nodeselector.go @@ -0,0 +1,70 @@ +package origin + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "errors" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type NodeSelector struct { + Value map[string]string +} + +func (a *NodeSelector) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + } + + k := rawObj.GetKind() + var nodeSelectorField map[string]string + var err error + + if k == PodKind { + nodeSelectorField, _, err = unstructured.NestedStringMap(rawObj.Object, "spec", "nodeSelector") + if err != nil { + return nil, fmt.Errorf("get spec.nodeSelector error: %s", err.Error()) + } + op.Path = "/spec/nodeSelector" + } else if k == DeploymentKind { + nodeSelectorField, _, err = unstructured.NestedStringMap(rawObj.Object, "spec", "template", "spec", "nodeSelector") + if err != nil { + return nil, fmt.Errorf("get spec.template.spec.nodeSelector error: %s", err.Error()) + } + op.Path = "/spec/template/spec/nodeSelector" + } else { + return nil, errors.New("unsupported kind type error") + } + + currentNodeSelector := nodeSelectorField + newNodeSelector := a.Value + + if Replace { + op.Value = newNodeSelector + return op, nil + } + + switch operator { + case policyv1alpha1.OverriderOpAdd, policyv1alpha1.OverriderOpReplace: + if currentNodeSelector == nil { + currentNodeSelector = newNodeSelector + } else { + for key, value := range newNodeSelector { + currentNodeSelector[key] = value + } + } + + case policyv1alpha1.OverriderOpRemove: + if currentNodeSelector != nil { + for key := range newNodeSelector { + delete(currentNodeSelector, key) + } + } + } + + op.Value = currentNodeSelector + return op, nil +} diff --git a/utils/origin/origin.go b/utils/origin/origin.go new file mode 100644 index 0000000..4974abc --- /dev/null +++ b/utils/origin/origin.go @@ -0,0 +1,22 @@ +package origin + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type OriginValue interface { + GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator v1alpha1.OverriderOperator) (*OverrideOption, error) +} + +type OverrideOption struct { + Op string `json:"op"` + Path string `json:"path"` + Value interface{} `json:"value"` +} + +const ( + DeploymentKind string = "Deployment" + PodKind string = "Pod" +) diff --git a/utils/origin/resourceRequirements.go b/utils/origin/resourceRequirements.go new file mode 100644 index 0000000..06ddcc4 --- /dev/null +++ b/utils/origin/resourceRequirements.go @@ -0,0 +1,39 @@ +package origin + +import ( + "errors" + "strconv" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type ResourceRequirements struct { + Value corev1.ResourceRequirements + Count int +} + +func (r *ResourceRequirements) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + if operator == policyv1alpha1.OverriderOpAdd || operator == policyv1alpha1.OverriderOpRemove { + return nil, errors.New("unsupported operator type error") + } + + k := rawObj.GetKind() + + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + } + + if k == PodKind { + op.Path = "/spec/containers/" + strconv.Itoa(r.Count) + "/resources" + } else if k == DeploymentKind { + op.Path = "/spec/template/spec/containers/" + strconv.Itoa(r.Count) + "/resources" + } else { + return nil, errors.New("unsupported kind type error") + } + + op.Value = r.Value + return op, nil +} diff --git a/utils/origin/resourceoversell.go b/utils/origin/resourceoversell.go new file mode 100644 index 0000000..9e8da0c --- /dev/null +++ b/utils/origin/resourceoversell.go @@ -0,0 +1,120 @@ +package origin + +import ( + "errors" + "fmt" + "strconv" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" + "github.com/k-cloud-labs/pkg/utils/util" +) + +type ResourceOversell struct { + Value map[policyv1alpha1.ResourceType]map[string]policyv1alpha1.Float64 + Count int +} + +func (r *ResourceOversell) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + if operator == policyv1alpha1.OverriderOpAdd || operator == policyv1alpha1.OverriderOpRemove { + return nil, errors.New("unsupported operator type error") + } + + var currentContainers []corev1.Container + k := rawObj.GetKind() + + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + } + + if k == PodKind { + op.Path = "/spec/containers/" + strconv.Itoa(r.Count) + "/resources" + pod, err := util.ConvertToPod(rawObj) + if err != nil { + return nil, fmt.Errorf("get spec.containers resources error: %s", err.Error()) + } + + if pod != nil { + currentContainers = pod.Spec.Containers + } + + if len(currentContainers) == 0 { + return nil, fmt.Errorf("containers not found in pod spec") + } + } else if k == DeploymentKind { + op.Path = "/spec/template/spec/containers/" + strconv.Itoa(r.Count) + "/resources" + deploy, err := util.ConvertToDeployment(rawObj) + if err != nil { + return nil, fmt.Errorf("get spec.template.spec.containers resources error: %s", err.Error()) + } + + if deploy != nil { + currentContainers = deploy.Spec.Template.Spec.Containers + } + + if len(currentContainers) == 0 { + return nil, fmt.Errorf("containers not found in deployment template pod spec") + } + } else { + return nil, errors.New("unsupported kind type error") + } + + if len(currentContainers) <= r.Count { + return nil, errors.New("containerCount cannot be greater than the number of containers in the pod") + } + + currentResourceList := currentContainers[r.Count].Resources + resultResourceList := currentResourceList + + if r.Value[policyv1alpha1.RequestResourceType] != nil { + for k, v := range r.Value[policyv1alpha1.RequestResourceType] { + switch corev1.ResourceName(k) { + case corev1.ResourceCPU: + q := currentResourceList.Requests[corev1.ResourceName(k)] + if q.MilliValue() == 0 { + continue + } + overSellCpuValue := float64(q.MilliValue()) * (*v.ToFloat64()) + overSellCpuQuantity := resource.NewMilliQuantity(int64(overSellCpuValue), resource.DecimalSI) + resultResourceList.Requests[corev1.ResourceName(k)] = *overSellCpuQuantity + case corev1.ResourceMemory, corev1.ResourceStorage, corev1.ResourceEphemeralStorage: + q := currentResourceList.Requests[corev1.ResourceName(k)] + if q.Value() == 0 { + continue + } + overSellStorageValue := float64(q.Value()) * (*v.ToFloat64()) + overSellStorageQuantity := resource.NewQuantity(int64(overSellStorageValue), resource.BinarySI) + resultResourceList.Requests[corev1.ResourceName(k)] = *overSellStorageQuantity + } + } + } + + if r.Value[policyv1alpha1.LimitResourceType] != nil { + for k, v := range r.Value[policyv1alpha1.LimitResourceType] { + switch corev1.ResourceName(k) { + case corev1.ResourceCPU: + q := currentResourceList.Limits[corev1.ResourceName(k)] + if q.MilliValue() == 0 { + continue + } + overSellCpuValue := float64(q.MilliValue()) * (*v.ToFloat64()) + overSellCpuQuantity := resource.NewMilliQuantity(int64(overSellCpuValue), resource.DecimalSI) + resultResourceList.Limits[corev1.ResourceName(k)] = *overSellCpuQuantity + case corev1.ResourceMemory, corev1.ResourceStorage, corev1.ResourceEphemeralStorage: + q := currentResourceList.Limits[corev1.ResourceName(k)] + if q.Value() == 0 { + continue + } + overSellStorageValue := float64(q.Value()) * (*v.ToFloat64()) + overSellStorageQuantity := resource.NewQuantity(int64(overSellStorageValue), resource.BinarySI) + resultResourceList.Limits[corev1.ResourceName(k)] = *overSellStorageQuantity + } + } + } + + op.Value = resultResourceList + return op, nil +} diff --git a/utils/origin/schedulername.go b/utils/origin/schedulername.go new file mode 100644 index 0000000..091e2e5 --- /dev/null +++ b/utils/origin/schedulername.go @@ -0,0 +1,37 @@ +package origin + +import ( + "errors" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type SchedulerName struct { + Value string +} + +func (s *SchedulerName) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + if operator == policyv1alpha1.OverriderOpAdd || operator == policyv1alpha1.OverriderOpRemove { + return nil, errors.New("unsupported operator type error") + } + + k := rawObj.GetKind() + newSchedulerName := s.Value + + op := &OverrideOption{ + Value: newSchedulerName, + Op: string(policyv1alpha1.OverriderOpReplace), + } + + if k == PodKind { + op.Path = "/spec/schedulerName" + } else if k == DeploymentKind { + op.Path = "/spec/template/spec/schedulerName" + } else { + return nil, errors.New("unsupported kind type error") + } + + return op, nil +} diff --git a/utils/origin/tolerations.go b/utils/origin/tolerations.go new file mode 100644 index 0000000..785c5f2 --- /dev/null +++ b/utils/origin/tolerations.go @@ -0,0 +1,125 @@ +package origin + +import ( + "errors" + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" + "github.com/k-cloud-labs/pkg/utils/util" +) + +type Tolerations struct { + Value []corev1.Toleration +} + +func (t *Tolerations) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + k := rawObj.GetKind() + currentTolerations := []corev1.Toleration{} + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + } + + if k == PodKind { + op.Path = "/spec/tolerations" + pod, err := util.ConvertToPod(rawObj) + if err != nil { + return nil, fmt.Errorf("get spec.tolerations error: %s", err.Error()) + } + + if pod != nil { + currentTolerations = pod.Spec.Tolerations + } + + } else if k == DeploymentKind { + op.Path = "/spec/template/spec/tolerations" + deploy, err := util.ConvertToDeployment(rawObj) + if err != nil { + return nil, fmt.Errorf("get spec.template.spec.tolerations error: %s", err.Error()) + } + if deploy != nil { + currentTolerations = deploy.Spec.Template.Spec.Tolerations + } + + } else { + return nil, errors.New("unsupported kind type error") + } + + if Replace || ((operator == policyv1alpha1.OverriderOpAdd || operator == policyv1alpha1.OverriderOpReplace) && len(currentTolerations) == 0) { + op.Value = t.Value + return op, nil + } + + if operator == policyv1alpha1.OverriderOpRemove && len(currentTolerations) == 0 { + return op, nil + } + + currentTolerationsStringMap := map[string]bool{} + for i := range currentTolerations { + currentTolerationsStringMap[tolerationToString(currentTolerations[i])] = true + } + + var newTolerations []corev1.Toleration + switch operator { + case policyv1alpha1.OverriderOpAdd, policyv1alpha1.OverriderOpReplace: + inNeedTolerationsStringMap := map[string]bool{} + for i := range t.Value { + var newToleration corev1.Toleration + tolerationString := tolerationToString(t.Value[i]) + if currentTolerationsStringMap[tolerationString] { + inNeedTolerationsStringMap[tolerationString] = true + newToleration = corev1.Toleration{ + Key: t.Value[i].Key, + Value: t.Value[i].Value, + Operator: t.Value[i].Operator, + Effect: t.Value[i].Effect, + TolerationSeconds: t.Value[i].TolerationSeconds, + } + newTolerations = append(newTolerations, newToleration) + continue + } + newTolerations = append(newTolerations, t.Value[i]) + } + + for i := range currentTolerations { + tolerationString := tolerationToString(currentTolerations[i]) + if !inNeedTolerationsStringMap[tolerationString] { + newTolerations = append(newTolerations, currentTolerations[i]) + } + } + + case policyv1alpha1.OverriderOpRemove: + needDeleteTolerationsStringMap := map[string]bool{} + for i := range t.Value { + tolerationString := tolerationToString(t.Value[i]) + if currentTolerationsStringMap[tolerationString] { + needDeleteTolerationsStringMap[tolerationString] = true + continue + } + } + + for i := range currentTolerations { + tolerationString := tolerationToString(currentTolerations[i]) + if !needDeleteTolerationsStringMap[tolerationString] { + newTolerations = append(newTolerations, currentTolerations[i]) + } + } + } + + op.Value = newTolerations + return op, nil +} + +func tolerationToString(this corev1.Toleration) string { + s := strings.Join([]string{`&Toleration{`, + `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `Operator:` + fmt.Sprintf("%v", this.Operator) + `,`, + `Value:` + fmt.Sprintf("%v", this.Value) + `,`, + `Effect:` + fmt.Sprintf("%v", this.Effect) + `,`, + `}`, + }, "") + return s +} diff --git a/utils/origin/topology_spread_constraints.go b/utils/origin/topology_spread_constraints.go new file mode 100644 index 0000000..19f1cb8 --- /dev/null +++ b/utils/origin/topology_spread_constraints.go @@ -0,0 +1,37 @@ +package origin + +import ( + "errors" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + policyv1alpha1 "github.com/k-cloud-labs/pkg/apis/policy/v1alpha1" +) + +type TopologySpreadConstraints struct { + Value []corev1.TopologySpreadConstraint +} + +func (t *TopologySpreadConstraints) GetJsonPatch(rawObj *unstructured.Unstructured, Replace bool, operator policyv1alpha1.OverriderOperator) (*OverrideOption, error) { + if operator == policyv1alpha1.OverriderOpAdd || operator == policyv1alpha1.OverriderOpRemove { + return nil, errors.New("unsupported operator type error") + } + + k := rawObj.GetKind() + + op := &OverrideOption{ + Op: string(policyv1alpha1.OverriderOpReplace), + } + + if k == PodKind { + op.Path = "/spec/topologySpreadConstraints" + } else if k == DeploymentKind { + op.Path = "/spec/template/spec/topologySpreadConstraints" + } else { + return nil, errors.New("unsupported kind type error") + } + + op.Value = t.Value + return op, nil +} diff --git a/utils/overridemanager/overridemanager.go b/utils/overridemanager/overridemanager.go index a9606c6..97a5fd8 100644 --- a/utils/overridemanager/overridemanager.go +++ b/utils/overridemanager/overridemanager.go @@ -19,6 +19,7 @@ import ( "github.com/k-cloud-labs/pkg/utils/cue" "github.com/k-cloud-labs/pkg/utils/dynamiclister" "github.com/k-cloud-labs/pkg/utils/metrics" + "github.com/k-cloud-labs/pkg/utils/origin" "github.com/k-cloud-labs/pkg/utils/util" ) @@ -271,6 +272,25 @@ func (o *overrideManagerImpl) applyPolicyOverriders(ctx context.Context, rawObj, } } + if p.overriders.Origin != nil { + traceStep(ctx, "About to get jsonPatches by origin") + patches, err := getJSONPatchesByOrigin(rawObj, p.overriders.Origin) + if err != nil { + return err + } + var resultPatches []overrideOption + for i := range patches { + resultPatches = append(resultPatches, overrideOption{ + Op: patches[i].Op, + Path: patches[i].Path, + Value: patches[i].Value, + }) + } + + traceStep(ctx, "get origin jsonPatches done") + return applyJSONPatch(rawObj, resultPatches) + } + if len(p.overriders.Plaintext) > 0 { metrics.OverridePolicyOverride(policyName, rawObj.GroupVersionKind()) } @@ -316,6 +336,46 @@ func parseJSONPatchesByPlaintext(overriders []policyv1alpha1.PlaintextOverrider) return patches } +func getJSONPatchesByOrigin(rawObj *unstructured.Unstructured, overriders []policyv1alpha1.OverrideRuleOrigin) ([]*origin.OverrideOption, error) { + patches := make([]*origin.OverrideOption, 0, len(overriders)) + for i := range overriders { + var o origin.OriginValue + switch overriders[i].Type { + case policyv1alpha1.OverrideRuleOriginTypeAnnotations: + o = &origin.Annotations{Value: overriders[i].Annotations} + case policyv1alpha1.OverrideRuleOriginLabels: + o = &origin.Labels{Value: overriders[i].Labels} + case policyv1alpha1.OverrideRuleOriginNodeSelector: + o = &origin.NodeSelector{Value: overriders[i].NodeSelector} + case policyv1alpha1.OverrideRuleOriginHostNetwork: + o = &origin.HostNetWork{Value: overriders[i].HostNetwork} + case policyv1alpha1.OverrideRuleOriginSchedulerName: + o = &origin.SchedulerName{Value: overriders[i].SchedulerName} + case policyv1alpha1.OverrideRuleOriginAffinity: + o = &origin.Affinity{Value: overriders[i].Affinity} + case policyv1alpha1.OverrideRuleOriginTolerations: + o = &origin.Tolerations{Value: overriders[i].Tolerations} + case policyv1alpha1.OverrideRuleOriginTopologySpreadConstraints: + o = &origin.TopologySpreadConstraints{Value: overriders[i].TopologySpreadConstraints} + case policyv1alpha1.OverrideRuleOriginResourceRequirements: + o = &origin.ResourceRequirements{Value: overriders[i].ResourceRequirements, Count: overriders[i].ContainerCount} + case policyv1alpha1.OverrideRuleOriginResourceOversell: + o = &origin.ResourceOversell{Value: overriders[i].ResourceOversell, Count: overriders[i].ContainerCount} + } + + patch, err := o.GetJsonPatch(rawObj, overriders[i].Replace, overriders[i].Operation) + if err != nil { + return nil, err + } + if patch != nil { + klog.V(4).InfoS("patches information:", "patch.op:", patch.Op, "patch.Path:", patch.Path, "patch.Value:", patch.Value) + patches = append(patches, patch) + } + } + + return patches, nil +} + func executeCueV2(cueStr string, parameters []cue.Parameter) ([]overrideOption, error) { result := make([]overrideOption, 0) if err := cue.CueDoAndReturn(cueStr, parameters, utils.OverrideOutputName, &result); err != nil { diff --git a/utils/templatemanager/templatemanager.go b/utils/templatemanager/templatemanager.go index 841cfc8..1b48b96 100644 --- a/utils/templatemanager/templatemanager.go +++ b/utils/templatemanager/templatemanager.go @@ -18,8 +18,9 @@ type templateManagerImpl struct { } // TemplateSource sets template source content, users can set single file path, pattern for multi files or -// body of file content. But only can set one of three fields, if there are more than one field be set then will use -// the first one only. +// +// body of file content. But only can set one of three fields, if there are more than one field be set then will use +// the first one only. type TemplateSource struct { // example: xx/xxx/*.tmpl PathPattern string