diff --git a/api/v1beta1/kuadrant_types.go b/api/v1beta1/kuadrant_types.go index 979727cf8..0c608cd88 100644 --- a/api/v1beta1/kuadrant_types.go +++ b/api/v1beta1/kuadrant_types.go @@ -19,6 +19,8 @@ package v1beta1 import ( "github.com/go-logr/logr" "github.com/google/go-cmp/cmp" + limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/kuadrant/kuadrant-operator/pkg/common" @@ -29,6 +31,26 @@ import ( // KuadrantSpec defines the desired state of Kuadrant type KuadrantSpec struct { + // +optional + Limitador *LimitadorSpec `json:"limitador,omitempty"` +} + +type LimitadorSpec struct { + + // +optional + Affinity *corev1.Affinity `json:"affinity,omitempty"` + + // +optional + Replicas *int `json:"replicas,omitempty"` + + // +optional + ResourceRequirements *corev1.ResourceRequirements `json:"resourceRequirements,omitempty"` + + // +optional + PodDisruptionBudget *limitadorv1alpha1.PodDisruptionBudgetType `json:"pdb,omitempty"` + + // +optional + Storage *limitadorv1alpha1.Storage `json:"storage,omitempty"` } // KuadrantStatus defines the observed state of Kuadrant diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index ce406a60e..fd8dba47c 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -21,7 +21,9 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/kuadrant/limitador-operator/api/v1alpha1" + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -30,7 +32,7 @@ func (in *Kuadrant) DeepCopyInto(out *Kuadrant) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) } @@ -87,6 +89,11 @@ func (in *KuadrantList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KuadrantSpec) DeepCopyInto(out *KuadrantSpec) { *out = *in + if in.Limitador != nil { + in, out := &in.Limitador, &out.Limitador + *out = new(LimitadorSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KuadrantSpec. @@ -104,7 +111,7 @@ func (in *KuadrantStatus) DeepCopyInto(out *KuadrantStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) + *out = make([]metav1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -120,3 +127,43 @@ func (in *KuadrantStatus) DeepCopy() *KuadrantStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LimitadorSpec) DeepCopyInto(out *LimitadorSpec) { + *out = *in + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(v1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int) + **out = **in + } + if in.ResourceRequirements != nil { + in, out := &in.ResourceRequirements, &out.ResourceRequirements + *out = new(v1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } + if in.PodDisruptionBudget != nil { + in, out := &in.PodDisruptionBudget, &out.PodDisruptionBudget + *out = new(v1alpha1.PodDisruptionBudgetType) + (*in).DeepCopyInto(*out) + } + if in.Storage != nil { + in, out := &in.Storage, &out.Storage + *out = new(v1alpha1.Storage) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitadorSpec. +func (in *LimitadorSpec) DeepCopy() *LimitadorSpec { + if in == nil { + return nil + } + out := new(LimitadorSpec) + in.DeepCopyInto(out) + return out +} diff --git a/bundle/manifests/kuadrant.io_kuadrants.yaml b/bundle/manifests/kuadrant.io_kuadrants.yaml index f07547080..41fed6db1 100644 --- a/bundle/manifests/kuadrant.io_kuadrants.yaml +++ b/bundle/manifests/kuadrant.io_kuadrants.yaml @@ -44,6 +44,1042 @@ spec: type: object spec: description: KuadrantSpec defines the desired state of Kuadrant + properties: + limitador: + properties: + affinity: + description: Affinity is a group of affinity scheduling rules. + 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. + 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. + 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. + 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. + 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 + pdb: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: An eviction is allowed if at most "maxUnavailable" + limitador pods are unavailable after the eviction, i.e. + even in absence of the evicted pod. For example, one can + prevent all voluntary evictions by specifying 0. This is + a mutually exclusive setting with "minAvailable". + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: An eviction is allowed if at least "minAvailable" + limitador pods will still be available after the eviction, + i.e. even in the absence of the evicted pod. So for example + you can prevent all voluntary evictions by specifying "100%". + x-kubernetes-int-or-string: true + type: object + replicas: + type: integer + resourceRequirements: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + 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. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + storage: + description: Storage contains the options for Limitador counters + database or in-memory data storage + properties: + disk: + properties: + optimize: + description: DiskOptimizeType defines the valid options + for "optimize" option of the disk persistence type + enum: + - throughput + - disk + type: string + persistentVolumeClaim: + properties: + resources: + description: Resources represents the minimum resources + the volume should have. Ignored when VolumeName + field is set + properties: + requests: + anyOf: + - type: integer + - type: string + description: 'Storage Resource requests to be + used on the PersistentVolumeClaim. To learn + more about resource requests see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - requests + type: object + storageClassName: + type: string + volumeName: + description: VolumeName is the binding reference to + the PersistentVolume backing this claim. + type: string + type: object + type: object + redis: + properties: + configSecretRef: + description: LocalObjectReference contains enough information + to let you locate the referenced object inside the same + namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: object + redis-cached: + properties: + configSecretRef: + description: LocalObjectReference contains enough information + to let you locate the referenced object inside the same + namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + options: + properties: + flush-period: + description: 'FlushPeriod for counters in milliseconds + [default: 1000]' + type: integer + max-cached: + description: 'MaxCached refers to the maximum amount + of counters cached [default: 10000]' + type: integer + ratio: + description: 'Ratio to apply to the TTL from Redis + on cached counters [default: 10]' + type: integer + ttl: + description: 'TTL for cached counters in milliseconds + [default: 5000]' + type: integer + type: object + type: object + type: object + type: object type: object status: description: KuadrantStatus defines the observed state of Kuadrant diff --git a/config/crd/bases/kuadrant.io_kuadrants.yaml b/config/crd/bases/kuadrant.io_kuadrants.yaml index 08b353a76..db0a88fe4 100644 --- a/config/crd/bases/kuadrant.io_kuadrants.yaml +++ b/config/crd/bases/kuadrant.io_kuadrants.yaml @@ -42,6 +42,1042 @@ spec: type: object spec: description: KuadrantSpec defines the desired state of Kuadrant + properties: + limitador: + properties: + affinity: + description: Affinity is a group of affinity scheduling rules. + 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. + 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. + 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. + 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. + 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 + pdb: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: An eviction is allowed if at most "maxUnavailable" + limitador pods are unavailable after the eviction, i.e. + even in absence of the evicted pod. For example, one can + prevent all voluntary evictions by specifying 0. This is + a mutually exclusive setting with "minAvailable". + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: An eviction is allowed if at least "minAvailable" + limitador pods will still be available after the eviction, + i.e. even in the absence of the evicted pod. So for example + you can prevent all voluntary evictions by specifying "100%". + x-kubernetes-int-or-string: true + type: object + replicas: + type: integer + resourceRequirements: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + 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. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + storage: + description: Storage contains the options for Limitador counters + database or in-memory data storage + properties: + disk: + properties: + optimize: + description: DiskOptimizeType defines the valid options + for "optimize" option of the disk persistence type + enum: + - throughput + - disk + type: string + persistentVolumeClaim: + properties: + resources: + description: Resources represents the minimum resources + the volume should have. Ignored when VolumeName + field is set + properties: + requests: + anyOf: + - type: integer + - type: string + description: 'Storage Resource requests to be + used on the PersistentVolumeClaim. To learn + more about resource requests see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - requests + type: object + storageClassName: + type: string + volumeName: + description: VolumeName is the binding reference to + the PersistentVolume backing this claim. + type: string + type: object + type: object + redis: + properties: + configSecretRef: + description: LocalObjectReference contains enough information + to let you locate the referenced object inside the same + namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: object + redis-cached: + properties: + configSecretRef: + description: LocalObjectReference contains enough information + to let you locate the referenced object inside the same + namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + options: + properties: + flush-period: + description: 'FlushPeriod for counters in milliseconds + [default: 1000]' + type: integer + max-cached: + description: 'MaxCached refers to the maximum amount + of counters cached [default: 10000]' + type: integer + ratio: + description: 'Ratio to apply to the TTL from Redis + on cached counters [default: 10]' + type: integer + ttl: + description: 'TTL for cached counters in milliseconds + [default: 5000]' + type: integer + type: object + type: object + type: object + type: object type: object status: description: KuadrantStatus defines the observed state of Kuadrant diff --git a/controllers/gateway_kuadrant_controller_test.go b/controllers/gateway_kuadrant_controller_test.go index 374395856..bf10dce01 100644 --- a/controllers/gateway_kuadrant_controller_test.go +++ b/controllers/gateway_kuadrant_controller_test.go @@ -69,19 +69,21 @@ var _ = Describe("Kuadrant Gateway controller", func() { }) Context("Two kuadrant instances", func() { + var secondNamespace string BeforeEach(func() { + CreateNamespace(&secondNamespace) newKuadrantName := "second" newKuadrant := &kuadrantv1beta1.Kuadrant{ TypeMeta: metav1.TypeMeta{APIVersion: "v1beta1", Kind: "Kuadrant"}, - ObjectMeta: metav1.ObjectMeta{Name: newKuadrantName, Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: newKuadrantName, Namespace: secondNamespace}, } err := testClient().Create(context.Background(), newKuadrant) Expect(err).ToNot(HaveOccurred()) Eventually(func() bool { kuadrant := &kuadrantv1beta1.Kuadrant{} - err := k8sClient.Get(context.Background(), client.ObjectKey{Name: newKuadrantName, Namespace: testNamespace}, kuadrant) + err := k8sClient.Get(context.Background(), client.ObjectKey{Name: newKuadrantName, Namespace: secondNamespace}, kuadrant) if err != nil { return false } @@ -92,6 +94,8 @@ var _ = Describe("Kuadrant Gateway controller", func() { }, time.Minute, 5*time.Second).Should(BeTrue()) }) + AfterEach(DeleteNamespaceCallback(&secondNamespace)) + It("new gateway should not be annotated", func() { gateway := testBuildBasicGateway(gwName, testNamespace) err := k8sClient.Create(context.Background(), gateway) diff --git a/controllers/helper_test.go b/controllers/helper_test.go index dd7b8583f..910a5596f 100644 --- a/controllers/helper_test.go +++ b/controllers/helper_test.go @@ -62,10 +62,7 @@ func CreateNamespace(namespace *string) { existingNamespace := &v1.Namespace{} Eventually(func() bool { err := testClient().Get(context.Background(), types.NamespacedName{Name: generatedTestNamespace}, existingNamespace) - if err != nil { - return false - } - return true + return err == nil }, time.Minute, 5*time.Second).Should(BeTrue()) *namespace = existingNamespace.Name diff --git a/controllers/kuadrant_controller.go b/controllers/kuadrant_controller.go index b43adcdc0..17a0e5162 100644 --- a/controllers/kuadrant_controller.go +++ b/controllers/kuadrant_controller.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" + "github.com/kuadrant/kuadrant-operator/pkg/kuadranttools" corev1 "k8s.io/api/core/v1" "k8s.io/utils/env" @@ -469,27 +470,54 @@ func (r *KuadrantReconciler) removeAnnotationFromGateways(ctx context.Context, k } func (r *KuadrantReconciler) reconcileLimitador(ctx context.Context, kObj *kuadrantv1beta1.Kuadrant) error { - limitador := &limitadorv1alpha1.Limitador{ - TypeMeta: metav1.TypeMeta{ - Kind: "Limitador", - APIVersion: "limitador.kuadrant.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: common.LimitadorName, - Namespace: kObj.Namespace, - }, - Spec: limitadorv1alpha1.LimitadorSpec{ - RateLimitHeaders: &[]limitadorv1alpha1.RateLimitHeadersType{limitadorv1alpha1.RateLimitHeadersTypeDraft03}[0], - Telemetry: &[]limitadorv1alpha1.Telemetry{limitadorv1alpha1.TelemetryExhaustive}[0], - }, + limitadorKey := client.ObjectKey{Name: common.LimitadorName, Namespace: kObj.Namespace} + limitador := &limitadorv1alpha1.Limitador{} + err := r.Client().Get(ctx, limitadorKey, limitador) + if err != nil { + if apierrors.IsNotFound(err) { + limitador = &limitadorv1alpha1.Limitador{ + TypeMeta: metav1.TypeMeta{ + Kind: "Limitador", + APIVersion: "limitador.kuadrant.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: common.LimitadorName, + Namespace: kObj.Namespace, + }, + Spec: limitadorv1alpha1.LimitadorSpec{ + RateLimitHeaders: &[]limitadorv1alpha1.RateLimitHeadersType{limitadorv1alpha1.RateLimitHeadersTypeDraft03}[0], + Telemetry: &[]limitadorv1alpha1.Telemetry{limitadorv1alpha1.TelemetryExhaustive}[0], + }, + } + } else { + return err + } + } + + if kObj.Spec.Limitador != nil { + if kObj.Spec.Limitador.Affinity != nil { + limitador.Spec.Affinity = kObj.Spec.Limitador.Affinity + } + if kObj.Spec.Limitador.PodDisruptionBudget != nil { + limitador.Spec.PodDisruptionBudget = kObj.Spec.Limitador.PodDisruptionBudget + } + if kObj.Spec.Limitador.Replicas != nil { + limitador.Spec.Replicas = kObj.Spec.Limitador.Replicas + } + if kObj.Spec.Limitador.ResourceRequirements != nil { + limitador.Spec.ResourceRequirements = kObj.Spec.Limitador.ResourceRequirements + } + if kObj.Spec.Limitador.Storage != nil { + limitador.Spec.Storage = kObj.Spec.Limitador.Storage + } } - err := r.SetOwnerReference(kObj, limitador) + err = r.SetOwnerReference(kObj, limitador) if err != nil { return err } - return r.ReconcileResource(ctx, &limitadorv1alpha1.Limitador{}, limitador, reconcilers.CreateOnlyMutator) + return r.ReconcileResource(ctx, &limitadorv1alpha1.Limitador{}, limitador, kuadranttools.LimitadorMutator) } func (r *KuadrantReconciler) reconcileAuthorino(ctx context.Context, kObj *kuadrantv1beta1.Kuadrant) error { diff --git a/doc/reference/kuadrant.md b/doc/reference/kuadrant.md new file mode 100644 index 000000000..4bf74d8ce --- /dev/null +++ b/doc/reference/kuadrant.md @@ -0,0 +1,94 @@ +# The Kuadrant Custom Resource Definition (CRD) + +## kuadrant + +
+ Note on Limitador +The Kuadrant operator creates a Limitador CR named `limitador` in the same namespace as the Kuadrant CR. If there is a pre-existing Limitador CR of the same name the kuadrant operator will take ownership of that Limitador CR. +
+ +| **Field** | **Type** | **Required** | **Description** | +|-----------|-----------------------------------|:------------:|-------------------------------------------------| +| `spec` | [KuadrantSpec](#kuadrantspec) | No | The specification for Kuadrant custom resource. | +| `status` | [KuadrantStatus](#kuadrantstatus) | No | The status for the custom resources. | + +## KuadrantSpec + +| **Field** | **Type** | **Required** | **Description** | +|-------------|-------------------------|:------------:|----------------------------------| +| `limitador` | [Limitador](#limitador) | No | Configure limitador deployments. | + +### Limitador + +| **Field** | **Type** | **Required** | **Description** | +|------------------------|------------------------------------------------------------------------------------|:------------:|----------------------------------------------------| +| `affinity` | [Affinity](https://pkg.go.dev/k8s.io/api/core/v1#Affinity) | No | Describes the scheduling rules for limitador pods. | +| `replicas` | Number | No | Sets the number of limitador replicas to deploy. | +| `resourceRequirements` | [ResourceRequirements](https://pkg.go.dev/k8s.io/api/core/v1#ResourceRequirements) | No | Set the resource requirements for limitador pods. | +| `pdb` | [PodDisruptionBudgetType](#poddisruptionbudgettype) | No | Configure allowed pod disruption budget fields. | +| `storage` | [Storage](#storage) | No | Define backend storage option for limitador. | + +### PodDisruptionBudgetType + +| **Field** | **Type** | **Required** | **Description** | +|------------------|----------|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `maxUnavailable` | Number | No | An eviction is allowed if at most "maxUnavailable" limitador pods are unavailable after the eviction, i.e. even in absence of the evicted pod. For example, one can prevent all voluntary evictions by specifying 0. This is a mutually exclusive setting with "minAvailable". | +| `minAvailable` | Number | No | An eviction is allowed if at least "minAvailable" limitador pods will still be available after the eviction, i.e. even in the absence of the evicted pod. So for example you can prevent all voluntary evictions by specifying "100%". | + +### Storage + +| **Field** | **Type** | **Required** | **Description** | +|----------------|-----------------------------|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `redis` | [Redis](#redis) | No | Uses Redis to store limitador counters. | +| `redis-cached` | [RedisCached](#redisCached) | No | Uses Redis to store limitador counters, with an in-memory cache | +| `disk` | [Disk](#disk) | No | Counters are held on disk (persistent). Kubernetes [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) will be used to store counters. | + +#### Redis + +| **Field** | **Type** | **Required** | **Description** | +|-------------------|------------------------------------------------------------------------------------|:------------:|-----------------------------------------------------------------| +| `configSecretRef` | [LocalObjectReference](https://pkg.go.dev/k8s.io/api/core/v1#LocalObjectReference) | No | ConfigSecretRef refers to the secret holding the URL for Redis. | + +#### RedisCached + +| **Field** | **Type** | **Required** | **Description** | +|-------------------|------------------------------------------------------------------------------------|:------------:|-----------------------------------------------------------------| +| `configSecretRef` | [LocalObjectReference](https://pkg.go.dev/k8s.io/api/core/v1#LocalObjectReference) | No | ConfigSecretRef refers to the secret holding the URL for Redis. | +| `options` | [Options](#options) | No | Configures a number of caching options for limitador. | + +##### Options + +| **Field** | **Type** | **Required** | **Description** | +|----------------|----------|:------------:|----------------------------------------------------------------------------| +| `ttl` | Number | No | TTL for cached counters in milliseconds [default: 5000] | +| `ratio` | Number | No | Ratio to apply to the TTL from Redis on cached counters [default: 10] | +| `flush-period` | Number | No | FlushPeriod for counters in milliseconds [default: 1000] | +| `max-cached` | Number | No | MaxCached refers to the maximum amount of counters cached [default: 10000] | + +#### Disk + +| **Field** | **Type** | **Required** | **Description** | +|-------------------------|-----------------------------------|:------------:|-----------------------------------------------------------------------------------------------| +| `persistentVolumeClaim` | [PVCGenericSpec](#pvcgenericspec) | No | Configure resources for PVC. | +| `Optimize` | String | No | Defines optimization option of the disk persistence type. Valid options: "throughput", "disk" | + +##### PVCGenericSpec + +| **Field** | **Type** | **Required** | **Description** | +|--------------------|-------------------------------------------------------------------|:------------:|-------------------------------------------------------------------------------| +| `storageClassName` | String | No | Storage class name | +| `resources` | [PersistentVolumeClaimResources](#persistentvolumeclaimresources) | No | Resources represent the minimum resources the volume should have | +| `volumeName` | String | No | VolumeName is the binding reference to the PersistentVolume backing the claim | + +###### PersistentVolumeClaimResources + +| **Field** | **Type** | **Required** | **Description** | +|------------|--------------------------------------------------------------------------------------|:------------:|---------------------------------------------------------------------| +| `requests` | [Quantity](https://pkg.go.dev/k8s.io/apimachinery@v0.28.4/pkg/api/resource#Quantity) | Yes | Storage resources requests to be used on the persisitentVolumeClaim | + +## KuadrantStatus + +| **Field** | **Type** | **Description** | +|----------------------|----------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| +| `observedGeneration` | String | Number of the last observed generation of the resource. Use it to check if the status info is up to date with latest resource spec. | +| `conditions` | [][ConditionSpec](https://pkg.go.dev/k8s.io/apimachinery@v0.28.4/pkg/apis/meta/v1#Condition) | List of conditions that define that status of the resource. | diff --git a/pkg/kuadranttools/limitador_tools.go b/pkg/kuadranttools/limitador_tools.go new file mode 100644 index 000000000..4710cc2ec --- /dev/null +++ b/pkg/kuadranttools/limitador_tools.go @@ -0,0 +1,53 @@ +package kuadranttools + +import ( + "fmt" + "reflect" + + "github.com/kuadrant/kuadrant-operator/api/v1beta1" + limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func LimitadorMutator(existingObj, desiredObj client.Object) (bool, error) { + update := false + existing, ok := existingObj.(*limitadorv1alpha1.Limitador) + if !ok { + return false, fmt.Errorf("existingObj %T is not a *limitadorv1alpha1.Limitador", existingObj) + } + desired, ok := desiredObj.(*limitadorv1alpha1.Limitador) + if !ok { + return false, fmt.Errorf("desireObj %T is not a *limitadorv1alpha1.Limitador", desiredObj) + } + + if !reflect.DeepEqual(existing.OwnerReferences, desired.OwnerReferences) { + update = true + existing.OwnerReferences = desired.OwnerReferences + } + + existingSpec := limitadorSpecSubSet(existing.Spec) + desiredSpec := limitadorSpecSubSet(desired.Spec) + + if !reflect.DeepEqual(existingSpec, desiredSpec) { + update = true + existing.Spec.Affinity = desired.Spec.Affinity + existing.Spec.PodDisruptionBudget = desired.Spec.PodDisruptionBudget + existing.Spec.Replicas = desired.Spec.Replicas + existing.Spec.ResourceRequirements = desired.Spec.ResourceRequirements + existing.Spec.Storage = desired.Spec.Storage + } + + return update, nil +} + +func limitadorSpecSubSet(spec limitadorv1alpha1.LimitadorSpec) v1beta1.LimitadorSpec { + out := v1beta1.LimitadorSpec{} + + out.Affinity = spec.Affinity + out.PodDisruptionBudget = spec.PodDisruptionBudget + out.Replicas = spec.Replicas + out.ResourceRequirements = spec.ResourceRequirements + out.Storage = spec.Storage + + return out +} diff --git a/pkg/kuadranttools/limitador_tools_test.go b/pkg/kuadranttools/limitador_tools_test.go new file mode 100644 index 000000000..bd531f49a --- /dev/null +++ b/pkg/kuadranttools/limitador_tools_test.go @@ -0,0 +1,198 @@ +//go:build unit + +package kuadranttools + +import ( + "reflect" + "strings" + "testing" + + "k8s.io/utils/ptr" + + "github.com/kuadrant/kuadrant-operator/api/v1beta1" + limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestLimitadorMutator(t *testing.T) { + type args struct { + existingObj client.Object + desiredObj client.Object + } + tests := []struct { + name string + args args + want bool + wantErr bool + errorContains string + }{ + { + name: "existingObj is not a limitador type", + wantErr: true, + errorContains: "existingObj", + }, + { + name: "desiredObj is not a limitador type", + args: args{ + existingObj: &limitadorv1alpha1.Limitador{}, + }, + wantErr: true, + errorContains: "desireObj", + }, + { + name: "No update required", + args: args{ + existingObj: &limitadorv1alpha1.Limitador{}, + desiredObj: &limitadorv1alpha1.Limitador{}, + }, + want: false, + }, + { + name: "Update required", + args: args{ + existingObj: &limitadorv1alpha1.Limitador{ + Spec: limitadorv1alpha1.LimitadorSpec{ + Replicas: ptr.To(3), + }, + }, + desiredObj: &limitadorv1alpha1.Limitador{ + Spec: limitadorv1alpha1.LimitadorSpec{ + Replicas: ptr.To(1), + }, + }, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := LimitadorMutator(tt.args.existingObj, tt.args.desiredObj) + if (err != nil) != tt.wantErr { + t.Errorf("LimitadorMutator() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if err != nil && tt.wantErr { + if !strings.Contains(err.Error(), tt.errorContains) { + t.Errorf("LimitadorMutator() error = %v, should contain %v", err, tt.errorContains) + } + } + if got != tt.want { + t.Errorf("LimitadorMutator() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_limitadorSpecSubSet(t *testing.T) { + type args struct { + spec limitadorv1alpha1.LimitadorSpec + } + tests := []struct { + name string + args args + want v1beta1.LimitadorSpec + }{ + { + name: "Empty spec passed", + args: args{spec: limitadorv1alpha1.LimitadorSpec{}}, + want: v1beta1.LimitadorSpec{}, + }, + { + name: "Full spec passed", + args: args{spec: limitadorv1alpha1.LimitadorSpec{ + Affinity: &corev1.Affinity{ + PodAffinity: &corev1.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ + { + Weight: 100, + PodAffinityTerm: corev1.PodAffinityTerm{LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "limitador", + }, + }}, + }, + }, + }, + }, + Replicas: ptr.To(3), + Storage: &limitadorv1alpha1.Storage{ + Redis: &limitadorv1alpha1.Redis{ + ConfigSecretRef: &corev1.LocalObjectReference{ + Name: "secret_config", + }, + }, + }, + PodDisruptionBudget: &limitadorv1alpha1.PodDisruptionBudgetType{ + MinAvailable: &intstr.IntOrString{ + IntVal: 1, + }, + }, + ResourceRequirements: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{}, + Requests: corev1.ResourceList{}, + }, + }}, + want: v1beta1.LimitadorSpec{ + Affinity: &corev1.Affinity{ + PodAffinity: &corev1.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ + { + Weight: 100, + PodAffinityTerm: corev1.PodAffinityTerm{LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "limitador", + }, + }}, + }, + }, + }, + }, + Replicas: ptr.To(3), + Storage: &limitadorv1alpha1.Storage{ + Redis: &limitadorv1alpha1.Redis{ + ConfigSecretRef: &corev1.LocalObjectReference{ + Name: "secret_config", + }, + }, + }, + PodDisruptionBudget: &limitadorv1alpha1.PodDisruptionBudgetType{ + MinAvailable: &intstr.IntOrString{ + IntVal: 1, + }, + }, + ResourceRequirements: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{}, + Requests: corev1.ResourceList{}, + }, + }, + }, + { + name: "Partial spec passed", + args: args{spec: limitadorv1alpha1.LimitadorSpec{ + Replicas: ptr.To(3), + ResourceRequirements: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{}, + Requests: corev1.ResourceList{}, + }, + }}, + want: v1beta1.LimitadorSpec{ + Replicas: ptr.To(3), + ResourceRequirements: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{}, + Requests: corev1.ResourceList{}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := limitadorSpecSubSet(tt.args.spec); !reflect.DeepEqual(got, tt.want) { + t.Errorf("limitadorSpecSubSet() = %v, want %v", got, tt.want) + } + }) + } +}