diff --git a/api/istio_v1beta1/virtualservice_types.go b/api/istio_v1beta1/virtualservice_types.go index 0716f86..6da31fd 100644 --- a/api/istio_v1beta1/virtualservice_types.go +++ b/api/istio_v1beta1/virtualservice_types.go @@ -26,12 +26,26 @@ import ( // NOTE: This type is used only to have a VirtualService runtime.Object (Istio's is not). we are only interested in // Hosts property. This is not going to be used as CR, could be moved somewherelese +type Destination struct { + Host string `json:"host,omitempty"` + Subset string `json:"subset,omitempty"` +} + +type HTTPRouteDestination struct { + Destination *Destination `json:"destination,omitempty"` +} + +type HTTPRoute struct { + Route []*HTTPRouteDestination `json:"route,omitempty"` +} + // VirtualServiceSpec defines the desired state of VirtualService type VirtualServiceSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file Gateways []string `json:"gateways,omitempty"` Hosts []string `json:"hosts,omitempty"` + Http []*HTTPRoute `json:"http,omitempty"` } // VirtualServiceStatus defines the observed state of VirtualService diff --git a/api/istio_v1beta1/zz_generated.deepcopy.go b/api/istio_v1beta1/zz_generated.deepcopy.go index 8b3a800..3db101c 100644 --- a/api/istio_v1beta1/zz_generated.deepcopy.go +++ b/api/istio_v1beta1/zz_generated.deepcopy.go @@ -24,6 +24,21 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Destination) DeepCopyInto(out *Destination) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Destination. +func (in *Destination) DeepCopy() *Destination { + if in == nil { + return nil + } + out := new(Destination) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Gateway) DeepCopyInto(out *Gateway) { *out = *in @@ -120,6 +135,52 @@ func (in *GatewayStatus) DeepCopy() *GatewayStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) { + *out = *in + if in.Route != nil { + in, out := &in.Route, &out.Route + *out = make([]*HTTPRouteDestination, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(HTTPRouteDestination) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRoute. +func (in *HTTPRoute) DeepCopy() *HTTPRoute { + if in == nil { + return nil + } + out := new(HTTPRoute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPRouteDestination) DeepCopyInto(out *HTTPRouteDestination) { + *out = *in + if in.Destination != nil { + in, out := &in.Destination, &out.Destination + *out = new(Destination) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteDestination. +func (in *HTTPRouteDestination) DeepCopy() *HTTPRouteDestination { + if in == nil { + return nil + } + out := new(HTTPRouteDestination) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VirtualService) DeepCopyInto(out *VirtualService) { *out = *in @@ -192,6 +253,17 @@ func (in *VirtualServiceSpec) DeepCopyInto(out *VirtualServiceSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.Http != nil { + in, out := &in.Http, &out.Http + *out = make([]*HTTPRoute, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(HTTPRoute) + (*in).DeepCopyInto(*out) + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualServiceSpec. diff --git a/api/v1alpha1/ratelimit_types.go b/api/v1alpha1/ratelimit_types.go index 9990193..6b0cd8a 100644 --- a/api/v1alpha1/ratelimit_types.go +++ b/api/v1alpha1/ratelimit_types.go @@ -79,7 +79,7 @@ type RateLimitSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file TargetRef v1.ObjectReference `json:"targetRef"` - DestinationCluster string `json:"destinationCluster"` + DestinationCluster string `json:"destinationCluster,omitempty"` Rate []Rate `json:"rate"` } diff --git a/config/crd/bases/networking.istio.io_virtualservices.yaml b/config/crd/bases/networking.istio.io_virtualservices.yaml index 908096d..7795155 100644 --- a/config/crd/bases/networking.istio.io_virtualservices.yaml +++ b/config/crd/bases/networking.istio.io_virtualservices.yaml @@ -46,6 +46,23 @@ spec: items: type: string type: array + http: + items: + properties: + route: + items: + properties: + destination: + properties: + host: + type: string + subset: + type: string + type: object + type: object + type: array + type: object + type: array type: object status: description: VirtualServiceStatus defines the observed state of VirtualService diff --git a/config/crd/bases/networking.softonic.io_ratelimits.yaml b/config/crd/bases/networking.softonic.io_ratelimits.yaml index 5d166bb..747821e 100644 --- a/config/crd/bases/networking.softonic.io_ratelimits.yaml +++ b/config/crd/bases/networking.softonic.io_ratelimits.yaml @@ -105,7 +105,6 @@ spec: type: string type: object required: - - destinationCluster - rate - targetRef type: object diff --git a/controllers/actions.go b/controllers/actions.go index 04fb6b3..bc8c982 100644 --- a/controllers/actions.go +++ b/controllers/actions.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "github.com/ghodss/yaml" + "github.com/softonic/rate-limit-operator/api/istio_v1beta1" + "errors" networkingv1alpha1 "github.com/softonic/rate-limit-operator/api/v1alpha1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -49,7 +51,7 @@ func (r *RateLimitReconciler) CreateOrUpdateConfigMap(rateLimitInstance *network var err error - cm := r.generateConfigMap(rateLimitInstance, controllerNamespace, baseName) + cm, err := r.generateConfigMap(rateLimitInstance, controllerNamespace, baseName) if err != nil { klog.Infof("Cannot generate %v, Error: %v", cm, err) return err @@ -78,10 +80,12 @@ func (r *RateLimitReconciler) CreateOrUpdateConfigMap(rateLimitInstance *network } -func (r *RateLimitReconciler) generateConfigMap(rateLimitInstance *networkingv1alpha1.RateLimit, controllerNamespace string, name string) v1.ConfigMap { +func (r *RateLimitReconciler) generateConfigMap(rateLimitInstance *networkingv1alpha1.RateLimit, controllerNamespace string, name string) (v1.ConfigMap, error) { configMapData := make(map[string]string) + var err error + var output []byte descriptorOutput := networkingv1alpha1.OutputConfig{} @@ -90,6 +94,22 @@ func (r *RateLimitReconciler) generateConfigMap(rateLimitInstance *networkingv1a descriptorOutput.Domain = name + // get Destination Cluster + + nameVirtualService := rateLimitInstance.Spec.TargetRef.Name + + var value string + + if rateLimitInstance.Spec.DestinationCluster != "" { + value = rateLimitInstance.Spec.DestinationCluster + } else { + value, err = r.getDestinationClusterFromVirtualService("istio-system", nameVirtualService) + if err != nil { + klog.Infof("Cannot generate configmap as we cannot find a host destination cluster") + return v1.ConfigMap{}, err + } + } + for k, dimension := range rateLimitInstance.Spec.Rate { descriptorOutput.DescriptorsParent[k].Key = dimension.Unit descriptor := networkingv1alpha1.Descriptors{ @@ -98,7 +118,7 @@ func (r *RateLimitReconciler) generateConfigMap(rateLimitInstance *networkingv1a RequestsPerUnit: dimension.RequestPerUnit, Unit: dimension.Unit, }, - Value: rateLimitInstance.Spec.DestinationCluster, + Value: value, } descriptorOutput.DescriptorsParent[k].Descriptors = append(descriptorOutput.DescriptorsParent[k].Descriptors, descriptor) } @@ -123,7 +143,38 @@ func (r *RateLimitReconciler) generateConfigMap(rateLimitInstance *networkingv1a Data: configMapData, } - return configMap + return configMap,nil + +} + +func (r *RateLimitReconciler) getDestinationClusterFromVirtualService(namespace string, nameVirtualService string) (string, error) { + + virtualService, err := r.getVirtualService(namespace, nameVirtualService) + if err != nil { + klog.Infof("Virtualservice does not exists") + return "", err + } + + subset := "" + destination := "" + + for k,routes := range virtualService.Spec.Http { + if routes.Route[k].Destination.Host != "" { + destination = routes.Route[k].Destination.Host + subset = routes.Route[k].Destination.Subset + } + } + + if destination == "" { + return "", errors.New("cannot find any suitable destinationCluster") + } + + //outbound|80|prod|server.digitaltrends-v1.svc.cluster.local + + + destinationCluster := "outbound|80|" + subset + "|" + destination + + return destinationCluster, errors.New("cannot find any suitable destinationCluster") }