diff --git a/api/v1beta1/route_types.go b/api/v1beta1/route_types.go index 43f86b0..4550c8d 100644 --- a/api/v1beta1/route_types.go +++ b/api/v1beta1/route_types.go @@ -25,8 +25,33 @@ import ( // RouteSpec defines the desired state of Route. type RouteSpec struct { - Gateway string `json:"gateway"` - Routes []RouteConfig `json:"routes"` + // Gateway defines the name of the Gateway resource + Gateway string `json:"gateway"` + // Path defines route path + Path string `json:"path" yaml:"path"` + // Hosts Domains/hosts based request routing + Hosts []string `json:"hosts,omitempty" yaml:"hosts"` + // Rewrite rewrites route path to desired path + Rewrite string `json:"rewrite,omitempty" yaml:"rewrite"` + // Methods allowed method + Methods []string `json:"methods,omitempty" yaml:"methods"` + // Destination Defines backend URL + Destination string `json:"destination,omitempty" yaml:"destination"` + Backends []string `json:"backends,omitempty" yaml:"backends"` + InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify"` + // HealthCheck Defines the backend is health + HealthCheck RouteHealthCheck `json:"healthCheck,omitempty" yaml:"healthCheck,omitempty"` + // Cors contains the route cors headers + Cors Cors `json:"cors,omitempty" yaml:"cors"` + RateLimit int `json:"rateLimit,omitempty" yaml:"rateLimit"` + // DisableHostFording Disables host forwarding. + DisableHostFording bool `json:"disableHostFording,omitempty" yaml:"disableHostFording"` + // InterceptErrors intercepts backend errors based on the status codes + InterceptErrors []int `json:"interceptErrors,omitempty" yaml:"interceptErrors"` + // BlockCommonExploits enable, disable block common exploits + BlockCommonExploits bool `json:"blockCommonExploits,omitempty" yaml:"blockCommonExploits"` + // Middlewares Defines route middleware + Middlewares []string `json:"middlewares,omitempty" yaml:"middlewares"` } // RouteStatus defines the observed state of Route. diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index 7b7822c..51445ee 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -51,38 +51,7 @@ type Server struct { // EnableMetrics enable and disable server metrics EnableMetrics bool `json:"enableMetrics,omitempty" yaml:"enableMetrics"` } -type RouteConfig struct { - // Path defines route path - Path string `json:"path" yaml:"path"` - // Name defines route name - Name string `json:"name" yaml:"name"` - // Hosts Domains/hosts based request routing - Hosts []string `json:"hosts,omitempty" yaml:"hosts"` - // Rewrite rewrites route path to desired path - Rewrite string `json:"rewrite,omitempty" yaml:"rewrite"` - // Methods allowed method - Methods []string `json:"methods,omitempty" yaml:"methods"` - // Destination Defines backend URL - Destination string `json:"destination,omitempty" yaml:"destination"` - Backends []string `json:"backends,omitempty" yaml:"backends"` - InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify"` - // HealthCheck Defines the backend is health - HealthCheck RouteHealthCheck `json:"healthCheck,omitempty" yaml:"healthCheck,omitempty"` - // Cors contains the route cors headers - Cors Cors `json:"cors,omitempty" yaml:"cors"` - RateLimit int `json:"rateLimit,omitempty" yaml:"rateLimit"` - // DisableHostFording Disable host forwarding. - DisableHostFording bool `json:"disableHostFording,omitempty" yaml:"disableHostFording"` - // InterceptErrors intercepts backend errors based on the status codes - InterceptErrors []int `json:"interceptErrors,omitempty" yaml:"interceptErrors"` - // BlockCommonExploits enable, disable block common exploits - BlockCommonExploits bool `json:"blockCommonExploits,omitempty" yaml:"blockCommonExploits"` - // Middlewares Defines route middleware - Middlewares []string `json:"middlewares,omitempty" yaml:"middlewares"` -} -type RoutesConfig struct { - Routes []RouteConfig `json:"routes" yaml:"routes"` -} + type RouteHealthCheck struct { Path string `json:"path,omitempty" yaml:"path"` Interval string `json:"interval,omitempty" yaml:"interval"` diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 3f779c2..1de9343 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -347,48 +347,6 @@ func (in *Route) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteConfig) DeepCopyInto(out *RouteConfig) { - *out = *in - if in.Hosts != nil { - in, out := &in.Hosts, &out.Hosts - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Methods != nil { - in, out := &in.Methods, &out.Methods - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Backends != nil { - in, out := &in.Backends, &out.Backends - *out = make([]string, len(*in)) - copy(*out, *in) - } - in.HealthCheck.DeepCopyInto(&out.HealthCheck) - in.Cors.DeepCopyInto(&out.Cors) - if in.InterceptErrors != nil { - in, out := &in.InterceptErrors, &out.InterceptErrors - *out = make([]int, len(*in)) - copy(*out, *in) - } - if in.Middlewares != nil { - in, out := &in.Middlewares, &out.Middlewares - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteConfig. -func (in *RouteConfig) DeepCopy() *RouteConfig { - if in == nil { - return nil - } - out := new(RouteConfig) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RouteHealthCheck) DeepCopyInto(out *RouteHealthCheck) { *out = *in @@ -444,12 +402,32 @@ func (in *RouteList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RouteSpec) DeepCopyInto(out *RouteSpec) { *out = *in - if in.Routes != nil { - in, out := &in.Routes, &out.Routes - *out = make([]RouteConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.Hosts != nil { + in, out := &in.Hosts, &out.Hosts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Methods != nil { + in, out := &in.Methods, &out.Methods + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Backends != nil { + in, out := &in.Backends, &out.Backends + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.HealthCheck.DeepCopyInto(&out.HealthCheck) + in.Cors.DeepCopyInto(&out.Cors) + if in.InterceptErrors != nil { + in, out := &in.InterceptErrors, &out.InterceptErrors + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.Middlewares != nil { + in, out := &in.Middlewares, &out.Middlewares + *out = make([]string, len(*in)) + copy(*out, *in) } } @@ -478,28 +456,6 @@ func (in *RouteStatus) DeepCopy() *RouteStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoutesConfig) DeepCopyInto(out *RoutesConfig) { - *out = *in - if in.Routes != nil { - in, out := &in.Routes, &out.Routes - *out = make([]RouteConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoutesConfig. -func (in *RoutesConfig) DeepCopy() *RoutesConfig { - if in == nil { - return nil - } - out := new(RoutesConfig) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Server) DeepCopyInto(out *Server) { *out = *in diff --git a/config/crd/bases/gomaproj.github.io_routes.yaml b/config/crd/bases/gomaproj.github.io_routes.yaml index d897594..734b9cd 100644 --- a/config/crd/bases/gomaproj.github.io_routes.yaml +++ b/config/crd/bases/gomaproj.github.io_routes.yaml @@ -39,95 +39,84 @@ spec: spec: description: RouteSpec defines the desired state of Route. properties: - gateway: - type: string - routes: + backends: items: - properties: - backends: - items: - type: string - type: array - blockCommonExploits: - description: BlockCommonExploits enable, disable block common - exploits - type: boolean - cors: - description: Cors contains the route cors headers - properties: - headers: - additionalProperties: - type: string - description: Headers contains custom headers - type: object - origins: - description: Cors contains Allowed origins, - items: - type: string - type: array - type: object - destination: - description: Destination Defines backend URL - type: string - disableHostFording: - description: DisableHostFording Disable host forwarding. - type: boolean - healthCheck: - description: HealthCheck Defines the backend is health - properties: - healthyStatuses: - items: - type: integer - type: array - interval: - type: string - path: - type: string - timeout: - type: string - type: object - hosts: - description: Hosts Domains/hosts based request routing - items: - type: string - type: array - insecureSkipVerify: - type: boolean - interceptErrors: - description: InterceptErrors intercepts backend errors based - on the status codes - items: - type: integer - type: array - methods: - description: Methods allowed method - items: - type: string - type: array - middlewares: - description: Middlewares Defines route middleware - items: - type: string - type: array - name: - description: Name defines route name - type: string - path: - description: Path defines route path - type: string - rateLimit: - type: integer - rewrite: - description: Rewrite rewrites route path to desired path - type: string - required: - - name - - path - type: object + type: string type: array + blockCommonExploits: + description: BlockCommonExploits enable, disable block common exploits + type: boolean + cors: + description: Cors contains the route cors headers + properties: + headers: + additionalProperties: + type: string + description: Headers contains custom headers + type: object + origins: + description: Cors contains Allowed origins, + items: + type: string + type: array + type: object + destination: + description: Destination Defines backend URL + type: string + disableHostFording: + description: DisableHostFording Disables host forwarding. + type: boolean + gateway: + description: Gateway defines the name of the Gateway resource + type: string + healthCheck: + description: HealthCheck Defines the backend is health + properties: + healthyStatuses: + items: + type: integer + type: array + interval: + type: string + path: + type: string + timeout: + type: string + type: object + hosts: + description: Hosts Domains/hosts based request routing + items: + type: string + type: array + insecureSkipVerify: + type: boolean + interceptErrors: + description: InterceptErrors intercepts backend errors based on the + status codes + items: + type: integer + type: array + methods: + description: Methods allowed method + items: + type: string + type: array + middlewares: + description: Middlewares Defines route middleware + items: + type: string + type: array + path: + description: Path defines route path + type: string + rateLimit: + type: integer + rewrite: + description: Rewrite rewrites route path to desired path + type: string required: - gateway - - routes + - path type: object status: description: RouteStatus defines the observed state of Route. diff --git a/go.mod b/go.mod index e1ab7bb..6d33aef 100644 --- a/go.mod +++ b/go.mod @@ -44,6 +44,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/imdario/mergo v0.3.6 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jinzhu/copier v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/go.sum b/go.sum index 0958667..514d9c8 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,8 @@ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= diff --git a/internal/controller/deployment.go b/internal/controller/deployment.go index b59a33f..19bcaf8 100644 --- a/internal/controller/deployment.go +++ b/internal/controller/deployment.go @@ -100,8 +100,8 @@ func createUpdateDeployment(r GatewayReconciler, ctx context.Context, req ctrl.R }, }, ReadinessProbe: &corev1.Probe{ - InitialDelaySeconds: 20, - PeriodSeconds: 20, + InitialDelaySeconds: 15, + PeriodSeconds: 10, ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/readyz", diff --git a/internal/controller/helpers.go b/internal/controller/helpers.go index 5d2097a..67214e4 100644 --- a/internal/controller/helpers.go +++ b/internal/controller/helpers.go @@ -2,6 +2,7 @@ package controller import ( "context" + "github.com/jinzhu/copier" "slices" "strings" @@ -20,8 +21,10 @@ func gatewayConfig(r GatewayReconciler, ctx context.Context, req ctrl.Request, g logger := log.FromContext(ctx) gomaConfig := &GatewayConfig{} gomaConfig.Version = GatewayConfigVersion - gomaConfig.Gateway = mapToGateway(gateway.Spec) - + err := copier.Copy(&gomaConfig.Gateway, &gateway.Spec.Server) + if err != nil { + logger.Error(err, "failed to copy gateway spec") + } // attach cert files if len(gateway.Spec.Server.TlsSecretName) != 0 { gomaConfig.Gateway.SSLKeyFile = TLSKeyFile @@ -44,12 +47,16 @@ func gatewayConfig(r GatewayReconciler, ctx context.Context, req ctrl.Request, g for _, route := range routes.Items { logger.Info("Found Route", "Name", route.Name) if route.Spec.Gateway == gateway.Name { - gomaConfig.Gateway.Routes = append(gomaConfig.Gateway.Routes, route.Spec.Routes...) - for _, rt := range route.Spec.Routes { - middlewareNames = append(middlewareNames, rt.Middlewares...) - + logger.Info("Found Route", "Name", route.Name) + rt := Route{} + err := copier.Copy(&rt, &route.Spec) + if err != nil { + logger.Error(err, "Failed to deep copy Route", "Name", route.Name) + return *gomaConfig } - + rt.Name = route.Name + gomaConfig.Gateway.Routes = append(gomaConfig.Gateway.Routes, rt) + middlewareNames = append(middlewareNames, rt.Middlewares...) } } for _, mid := range middlewares.Items { @@ -66,7 +73,10 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques logger := log.FromContext(ctx) gomaConfig := &GatewayConfig{} gomaConfig.Version = GatewayConfigVersion - gomaConfig.Gateway = mapToGateway(gateway.Spec) + err := copier.Copy(&gomaConfig.Gateway, &gateway.Spec.Server) + if err != nil { + logger.Error(err, "failed to copy gateway spec") + } // attach cert files if len(gateway.Spec.Server.TlsSecretName) != 0 { gomaConfig.Gateway.SSLKeyFile = TLSKeyFile @@ -88,12 +98,15 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques for _, route := range routes.Items { logger.Info("Found Route", "Name", route.Name) if route.Spec.Gateway == gateway.Name { - gomaConfig.Gateway.Routes = append(gomaConfig.Gateway.Routes, route.Spec.Routes...) - for _, rt := range route.Spec.Routes { - middlewareNames = append(middlewareNames, rt.Middlewares...) - + rt := Route{} + err := copier.Copy(&rt, &route.Spec) + if err != nil { + logger.Error(err, "Failed to deep copy Route", "Name", route.Name) + return false, err } - + rt.Name = route.Name + gomaConfig.Gateway.Routes = append(gomaConfig.Gateway.Routes, rt) + middlewareNames = append(middlewareNames, rt.Middlewares...) } } for _, mid := range middlewares.Items { diff --git a/internal/controller/route_controller_test.go b/internal/controller/route_controller_test.go index 1971214..6644930 100644 --- a/internal/controller/route_controller_test.go +++ b/internal/controller/route_controller_test.go @@ -77,15 +77,11 @@ var _ = Describe("Route Controller", func() { }, Spec: gomaprojv1beta1.RouteSpec{ Gateway: resourceName, - Routes: []gomaprojv1beta1.RouteConfig{ - { - Path: "/", - Name: resourceName, - Rewrite: "/", - Destination: "https://example.com", - Methods: []string{"GET", "POST"}, - }, - }, + + Path: "/", + Rewrite: "/", + Destination: "https://example.com", + Methods: []string{"GET", "POST"}, }, } Expect(k8sClient.Create(ctx, resource)).To(Succeed()) diff --git a/internal/controller/types.go b/internal/controller/types.go index 029df44..b461dcd 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -28,10 +28,38 @@ type Gateway struct { DisableKeepAlive bool `yaml:"disableKeepAlive"` EnableMetrics bool `yaml:"enableMetrics"` // InterceptErrors holds the status codes to intercept the error from backend - InterceptErrors []int `yaml:"interceptErrors,omitempty"` - Routes []gomaprojv1beta1.RouteConfig `json:"routes,omitempty" yaml:"routes,omitempty"` + InterceptErrors []int `yaml:"interceptErrors,omitempty"` + Routes []Route `json:"routes,omitempty" yaml:"routes,omitempty"` +} +type Route struct { + // Path defines route path + Path string `json:"path" yaml:"path"` + // Name defines route name + Name string `json:"name" yaml:"name"` + // Hosts Domains/hosts based request routing + Hosts []string `json:"hosts,omitempty" yaml:"hosts"` + // Rewrite rewrites route path to desired path + Rewrite string `json:"rewrite,omitempty" yaml:"rewrite"` + // Methods allowed method + Methods []string `json:"methods,omitempty" yaml:"methods"` + // Destination Defines backend URL + Destination string `json:"destination,omitempty" yaml:"destination"` + Backends []string `json:"backends,omitempty" yaml:"backends"` + InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify"` + // HealthCheck Defines the backend is health + HealthCheck gomaprojv1beta1.RouteHealthCheck `json:"healthCheck,omitempty" yaml:"healthCheck,omitempty"` + // Cors contains the route cors headers + Cors gomaprojv1beta1.Cors `json:"cors,omitempty" yaml:"cors"` + RateLimit int `json:"rateLimit,omitempty" yaml:"rateLimit"` + // DisableHostFording Disable host forwarding. + DisableHostFording bool `json:"disableHostFording,omitempty" yaml:"disableHostFording"` + // InterceptErrors intercepts backend errors based on the status codes + InterceptErrors []int `json:"interceptErrors,omitempty" yaml:"interceptErrors"` + // BlockCommonExploits enable, disable block common exploits + BlockCommonExploits bool `json:"blockCommonExploits,omitempty" yaml:"blockCommonExploits"` + // Middlewares Defines route middleware + Middlewares []string `json:"middlewares,omitempty" yaml:"middlewares"` } - type Redis struct { // Addr redis hostname and port number : Addr string `yaml:"addr"` diff --git a/internal/controller/util.go b/internal/controller/util.go index a50cbd0..b0b429f 100644 --- a/internal/controller/util.go +++ b/internal/controller/util.go @@ -1,22 +1 @@ package controller - -import gomaprojv1beta1 "github.com/jkaninda/goma-operator/api/v1beta1" - -func mapToGateway(g gomaprojv1beta1.GatewaySpec) Gateway { - return Gateway{ - SSLKeyFile: "", - SSLCertFile: "", - Redis: g.Server.Redis, - WriteTimeout: g.Server.WriteTimeout, - ReadTimeout: g.Server.ReadTimeout, - IdleTimeout: g.Server.IdleTimeout, - LogLevel: g.Server.LogLevel, - Cors: g.Server.Cors, - DisableHealthCheckStatus: g.Server.DisableHealthCheckStatus, - DisableRouteHealthCheckError: g.Server.DisableHealthCheckStatus, - DisableKeepAlive: g.Server.DisableKeepAlive, - InterceptErrors: g.Server.InterceptErrors, - EnableMetrics: g.Server.EnableMetrics, - } - -}