diff --git a/api/v1alpha2/istio_merge.go b/api/v1alpha2/istio_merge.go index 413ec2c6b..de80e9aa2 100644 --- a/api/v1alpha2/istio_merge.go +++ b/api/v1alpha2/istio_merge.go @@ -216,6 +216,7 @@ func (i *Istio) mergeResources(op iopv1alpha1.IstioOperator) (iopv1alpha1.IstioO if i.Spec.Components == nil { return op, nil } + if i.Spec.Components.IngressGateway != nil { if op.Spec.Components == nil { op.Spec.Components = &v1alpha1.IstioComponentSetSpec{} @@ -226,15 +227,32 @@ func (i *Istio) mergeResources(op iopv1alpha1.IstioOperator) (iopv1alpha1.IstioO if op.Spec.Components.IngressGateways[0].K8S == nil { op.Spec.Components.IngressGateways[0].K8S = &v1alpha1.KubernetesResourcesSpec{} } - if i.Spec.Components.IngressGateway.K8s != nil { err := mergeK8sConfig(op.Spec.Components.IngressGateways[0].K8S, *i.Spec.Components.IngressGateway.K8s) if err != nil { return op, err } } + } + if i.Spec.Components.EgressGateway != nil { + if op.Spec.Components == nil { + op.Spec.Components = &v1alpha1.IstioComponentSetSpec{} + } + if len(op.Spec.Components.EgressGateways) == 0 { + op.Spec.Components.EgressGateways = append(op.Spec.Components.EgressGateways, &v1alpha1.GatewaySpec{}) + } + if op.Spec.Components.EgressGateways[0].K8S == nil { + op.Spec.Components.EgressGateways[0].K8S = &v1alpha1.KubernetesResourcesSpec{} + } + if i.Spec.Components.EgressGateway.K8s != nil { + err := mergeK8sConfig(op.Spec.Components.EgressGateways[0].K8S, *i.Spec.Components.EgressGateway.K8s) + if err != nil { + return op, err + } + } } + if i.Spec.Components.Pilot != nil { if op.Spec.Components == nil { op.Spec.Components = &v1alpha1.IstioComponentSetSpec{} diff --git a/api/v1alpha2/istio_structs.go b/api/v1alpha2/istio_structs.go index 048e963fd..397eb59dd 100644 --- a/api/v1alpha2/istio_structs.go +++ b/api/v1alpha2/istio_structs.go @@ -32,6 +32,8 @@ type Components struct { Cni *CniComponent `json:"cni,omitempty"` // Proxy defines component configuration for Istio proxy sidecar Proxy *ProxyComponent `json:"proxy,omitempty"` + // +kubebuilder:validation:Optional + EgressGateway *EgressGateway `json:"egressGateway,omitempty"` } // KubernetesResourcesConfig is a subset of https://istio.io/latest/docs/reference/config/istio.operator.v1alpha1/#KubernetesResourcesSpec @@ -112,3 +114,11 @@ type ResourceClaims struct { // +kubebuilder:validation:Pattern=`^[0-9]+(((\.[0-9]+)?(E|P|T|G|M|k|Ei|Pi|Ti|Gi|Mi|Ki|m)?)|(e[0-9]+))$` Memory *string `json:"memory,omitempty"` } + +// EgressGateway defines configuration for Istio egressGateway +type EgressGateway struct { + // +kubebuilder:validation:Optional + K8s *KubernetesResourcesConfig `json:"k8s"` + // +kubebuilder:validation:Optional + Enabled *bool `json:"enabled,omitempty"` +} diff --git a/api/v1alpha2/merge_test.go b/api/v1alpha2/merge_test.go index 64ccd02ca..cf799a72d 100644 --- a/api/v1alpha2/merge_test.go +++ b/api/v1alpha2/merge_test.go @@ -526,6 +526,82 @@ var _ = Describe("Merge", func() { }) }) + Context("EgressGateway", func() { + Context("When Istio CR has 500m configured for CPU and 500Mi for memory limits", func() { + It("should set CPU limits to 500m and 500Mi for memory in IOP", func() { + //given + iop := iopv1alpha1.IstioOperator{ + Spec: &operatorv1alpha1.IstioOperatorSpec{}, + } + cpuLimit := "500m" + memoryLimit := "500Mi" + enabled := true + + istioCR := Istio{Spec: IstioSpec{Components: &Components{ + EgressGateway: &EgressGateway{ + Enabled: &enabled, + K8s: &KubernetesResourcesConfig{ + Resources: &Resources{ + Limits: &ResourceClaims{ + Cpu: &cpuLimit, + Memory: &memoryLimit, + }, + }, + }, + }}}} + + // when + out, err := istioCR.MergeInto(iop) + + // then + Expect(err).ShouldNot(HaveOccurred()) + + iopCpuLimit := out.Spec.Components.EgressGateways[0].K8S.Resources.Limits["cpu"] + Expect(iopCpuLimit).To(Equal(cpuLimit)) + + iopMemoryLimit := out.Spec.Components.EgressGateways[0].K8S.Resources.Limits["memory"] + Expect(iopMemoryLimit).To(Equal(iopMemoryLimit)) + }) + }) + + Context("When Istio CR has 500m configured for CPU and 500Mi for memory requests", func() { + It("should set CPU requests to 500m and 500Mi for memory in IOP", func() { + //given + iop := iopv1alpha1.IstioOperator{ + Spec: &operatorv1alpha1.IstioOperatorSpec{}, + } + cpuRequests := "500m" + memoryRequests := "500Mi" + enabled := true + + istioCR := Istio{Spec: IstioSpec{Components: &Components{ + EgressGateway: &EgressGateway{ + Enabled: &enabled, + K8s: &KubernetesResourcesConfig{ + Resources: &Resources{ + Requests: &ResourceClaims{ + Cpu: &cpuRequests, + Memory: &memoryRequests, + }, + }, + }, + }}}} + + // when + out, err := istioCR.MergeInto(iop) + + // then + Expect(err).ShouldNot(HaveOccurred()) + + iopCpuRequests := out.Spec.Components.EgressGateways[0].K8S.Resources.Requests["cpu"] + Expect(iopCpuRequests).To(Equal(cpuRequests)) + + iopMemoryRequests := out.Spec.Components.EgressGateways[0].K8S.Resources.Requests["memory"] + Expect(iopMemoryRequests).To(Equal(memoryRequests)) + }) + }) + }) + Context("Strategy", func() { It("should update RollingUpdate when it is present in Istio CR", func() { //given diff --git a/api/v1alpha2/zz_generated.deepcopy.go b/api/v1alpha2/zz_generated.deepcopy.go index 3b0e8b6fd..581d91e9b 100644 --- a/api/v1alpha2/zz_generated.deepcopy.go +++ b/api/v1alpha2/zz_generated.deepcopy.go @@ -115,6 +115,11 @@ func (in *Components) DeepCopyInto(out *Components) { *out = new(ProxyComponent) (*in).DeepCopyInto(*out) } + if in.EgressGateway != nil { + in, out := &in.EgressGateway, &out.EgressGateway + *out = new(EgressGateway) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Components. @@ -163,6 +168,31 @@ func (in *Config) DeepCopy() *Config { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EgressGateway) DeepCopyInto(out *EgressGateway) { + *out = *in + if in.K8s != nil { + in, out := &in.K8s, &out.K8s + *out = new(KubernetesResourcesConfig) + (*in).DeepCopyInto(*out) + } + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressGateway. +func (in *EgressGateway) DeepCopy() *EgressGateway { + if in == nil { + return nil + } + out := new(EgressGateway) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Experimental) DeepCopyInto(out *Experimental) { *out = *in diff --git a/config/crd/bases/operator.kyma-project.io_istios.yaml b/config/crd/bases/operator.kyma-project.io_istios.yaml index d7c436b4d..b0de3706e 100644 --- a/config/crd/bases/operator.kyma-project.io_istios.yaml +++ b/config/crd/bases/operator.kyma-project.io_istios.yaml @@ -1022,6 +1022,86 @@ spec: required: - k8s type: object + egressGateway: + description: EgressGateway defines configuration for Istio egressGateway + properties: + enabled: + type: boolean + k8s: + description: KubernetesResourcesConfig is a subset of https://istio.io/latest/docs/reference/config/istio.operator.v1alpha1/#KubernetesResourcesSpec + properties: + hpaSpec: + description: HPASpec defines configuration for HorizontalPodAutoscaler + properties: + maxReplicas: + format: int32 + maximum: 2147483647 + minimum: 0 + type: integer + minReplicas: + format: int32 + maximum: 2147483647 + minimum: 0 + type: integer + type: object + resources: + description: 'Resources define Kubernetes resources configuration: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + limits: + properties: + cpu: + pattern: ^([0-9]+m?|[0-9]\.[0-9]{1,3})$ + type: string + memory: + pattern: ^[0-9]+(((\.[0-9]+)?(E|P|T|G|M|k|Ei|Pi|Ti|Gi|Mi|Ki|m)?)|(e[0-9]+))$ + type: string + type: object + requests: + properties: + cpu: + pattern: ^([0-9]+m?|[0-9]\.[0-9]{1,3})$ + type: string + memory: + pattern: ^[0-9]+(((\.[0-9]+)?(E|P|T|G|M|k|Ei|Pi|Ti|Gi|Mi|Ki|m)?)|(e[0-9]+))$ + type: string + type: object + type: object + strategy: + description: Strategy defines rolling update strategy + properties: + rollingUpdate: + description: 'RollingUpdate defines configuration + for rolling updates: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-update-deployment' + properties: + maxSurge: + anyOf: + - type: integer + - type: string + pattern: ^[0-9]+%?$ + x-kubernetes-int-or-string: true + x-kubernetes-validations: + - message: must not be negative, more than 2147483647 + or an empty string + rule: '(type(self) == int ? self >= 0 && self + <= 2147483647: self.size() >= 0)' + maxUnavailable: + anyOf: + - type: integer + - type: string + pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ + x-kubernetes-int-or-string: true + x-kubernetes-validations: + - message: must not be negative, more than 2147483647 + or an empty string + rule: '(type(self) == int ? self >= 0 && self + <= 2147483647: self.size() >= 0)' + type: object + required: + - rollingUpdate + type: object + type: object + type: object ingressGateway: description: IngressGateway defines component configurations for Istio Ingress Gateway