chore: change Route crd structure

This commit is contained in:
Jonas Kaninda
2024-11-29 08:04:30 +01:00
parent 614c05b283
commit 3bd4b68925
11 changed files with 195 additions and 237 deletions

View File

@@ -25,8 +25,33 @@ import (
// RouteSpec defines the desired state of Route. // RouteSpec defines the desired state of Route.
type RouteSpec struct { type RouteSpec struct {
Gateway string `json:"gateway"` // Gateway defines the name of the Gateway resource
Routes []RouteConfig `json:"routes"` 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. // RouteStatus defines the observed state of Route.

View File

@@ -51,38 +51,7 @@ type Server struct {
// EnableMetrics enable and disable server metrics // EnableMetrics enable and disable server metrics
EnableMetrics bool `json:"enableMetrics,omitempty" yaml:"enableMetrics"` 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 { type RouteHealthCheck struct {
Path string `json:"path,omitempty" yaml:"path"` Path string `json:"path,omitempty" yaml:"path"`
Interval string `json:"interval,omitempty" yaml:"interval"` Interval string `json:"interval,omitempty" yaml:"interval"`

View File

@@ -347,48 +347,6 @@ func (in *Route) DeepCopyObject() runtime.Object {
return nil 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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RouteHealthCheck) DeepCopyInto(out *RouteHealthCheck) { func (in *RouteHealthCheck) DeepCopyInto(out *RouteHealthCheck) {
*out = *in *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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RouteSpec) DeepCopyInto(out *RouteSpec) { func (in *RouteSpec) DeepCopyInto(out *RouteSpec) {
*out = *in *out = *in
if in.Routes != nil { if in.Hosts != nil {
in, out := &in.Routes, &out.Routes in, out := &in.Hosts, &out.Hosts
*out = make([]RouteConfig, len(*in)) *out = make([]string, len(*in))
for i := range *in { copy(*out, *in)
(*in)[i].DeepCopyInto(&(*out)[i]) }
} 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 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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Server) DeepCopyInto(out *Server) { func (in *Server) DeepCopyInto(out *Server) {
*out = *in *out = *in

View File

@@ -39,95 +39,84 @@ spec:
spec: spec:
description: RouteSpec defines the desired state of Route. description: RouteSpec defines the desired state of Route.
properties: properties:
gateway: backends:
type: string
routes:
items: items:
properties: type: string
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: array 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: required:
- gateway - gateway
- routes - path
type: object type: object
status: status:
description: RouteStatus defines the observed state of Route. description: RouteStatus defines the observed state of Route.

1
go.mod
View File

@@ -44,6 +44,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect github.com/imdario/mergo v0.3.6 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // 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/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect

2
go.sum
View File

@@ -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/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 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=

View File

@@ -100,8 +100,8 @@ func createUpdateDeployment(r GatewayReconciler, ctx context.Context, req ctrl.R
}, },
}, },
ReadinessProbe: &corev1.Probe{ ReadinessProbe: &corev1.Probe{
InitialDelaySeconds: 20, InitialDelaySeconds: 15,
PeriodSeconds: 20, PeriodSeconds: 10,
ProbeHandler: corev1.ProbeHandler{ ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{ HTTPGet: &corev1.HTTPGetAction{
Path: "/readyz", Path: "/readyz",

View File

@@ -2,6 +2,7 @@ package controller
import ( import (
"context" "context"
"github.com/jinzhu/copier"
"slices" "slices"
"strings" "strings"
@@ -20,8 +21,10 @@ func gatewayConfig(r GatewayReconciler, ctx context.Context, req ctrl.Request, g
logger := log.FromContext(ctx) logger := log.FromContext(ctx)
gomaConfig := &GatewayConfig{} gomaConfig := &GatewayConfig{}
gomaConfig.Version = GatewayConfigVersion 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 // attach cert files
if len(gateway.Spec.Server.TlsSecretName) != 0 { if len(gateway.Spec.Server.TlsSecretName) != 0 {
gomaConfig.Gateway.SSLKeyFile = TLSKeyFile gomaConfig.Gateway.SSLKeyFile = TLSKeyFile
@@ -44,12 +47,16 @@ func gatewayConfig(r GatewayReconciler, ctx context.Context, req ctrl.Request, g
for _, route := range routes.Items { for _, route := range routes.Items {
logger.Info("Found Route", "Name", route.Name) logger.Info("Found Route", "Name", route.Name)
if route.Spec.Gateway == gateway.Name { if route.Spec.Gateway == gateway.Name {
gomaConfig.Gateway.Routes = append(gomaConfig.Gateway.Routes, route.Spec.Routes...) logger.Info("Found Route", "Name", route.Name)
for _, rt := range route.Spec.Routes { rt := Route{}
middlewareNames = append(middlewareNames, rt.Middlewares...) 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 { for _, mid := range middlewares.Items {
@@ -66,7 +73,10 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques
logger := log.FromContext(ctx) logger := log.FromContext(ctx)
gomaConfig := &GatewayConfig{} gomaConfig := &GatewayConfig{}
gomaConfig.Version = GatewayConfigVersion 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 // attach cert files
if len(gateway.Spec.Server.TlsSecretName) != 0 { if len(gateway.Spec.Server.TlsSecretName) != 0 {
gomaConfig.Gateway.SSLKeyFile = TLSKeyFile gomaConfig.Gateway.SSLKeyFile = TLSKeyFile
@@ -88,12 +98,15 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques
for _, route := range routes.Items { for _, route := range routes.Items {
logger.Info("Found Route", "Name", route.Name) logger.Info("Found Route", "Name", route.Name)
if route.Spec.Gateway == gateway.Name { if route.Spec.Gateway == gateway.Name {
gomaConfig.Gateway.Routes = append(gomaConfig.Gateway.Routes, route.Spec.Routes...) rt := Route{}
for _, rt := range route.Spec.Routes { err := copier.Copy(&rt, &route.Spec)
middlewareNames = append(middlewareNames, rt.Middlewares...) 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 { for _, mid := range middlewares.Items {

View File

@@ -77,15 +77,11 @@ var _ = Describe("Route Controller", func() {
}, },
Spec: gomaprojv1beta1.RouteSpec{ Spec: gomaprojv1beta1.RouteSpec{
Gateway: resourceName, Gateway: resourceName,
Routes: []gomaprojv1beta1.RouteConfig{
{ Path: "/",
Path: "/", Rewrite: "/",
Name: resourceName, Destination: "https://example.com",
Rewrite: "/", Methods: []string{"GET", "POST"},
Destination: "https://example.com",
Methods: []string{"GET", "POST"},
},
},
}, },
} }
Expect(k8sClient.Create(ctx, resource)).To(Succeed()) Expect(k8sClient.Create(ctx, resource)).To(Succeed())

View File

@@ -28,10 +28,38 @@ type Gateway struct {
DisableKeepAlive bool `yaml:"disableKeepAlive"` DisableKeepAlive bool `yaml:"disableKeepAlive"`
EnableMetrics bool `yaml:"enableMetrics"` EnableMetrics bool `yaml:"enableMetrics"`
// InterceptErrors holds the status codes to intercept the error from backend // InterceptErrors holds the status codes to intercept the error from backend
InterceptErrors []int `yaml:"interceptErrors,omitempty"` InterceptErrors []int `yaml:"interceptErrors,omitempty"`
Routes []gomaprojv1beta1.RouteConfig `json:"routes,omitempty" yaml:"routes,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 { type Redis struct {
// Addr redis hostname and port number : // Addr redis hostname and port number :
Addr string `yaml:"addr"` Addr string `yaml:"addr"`

View File

@@ -1,22 +1 @@
package controller 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,
}
}