Compare commits
10 Commits
81fc83be09
...
2794a5777d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2794a5777d | ||
|
|
09211ce7a3 | ||
|
|
bfb287ab01 | ||
|
|
46c5ff9770 | ||
|
|
00284095b0 | ||
|
|
9db20f4577 | ||
|
|
3bd4b68925 | ||
|
|
614c05b283 | ||
|
|
c0400d7c75 | ||
|
|
a7162fa72f |
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
# Image URL to use all building/pushing image targets
|
||||
IMG ?= jkaninda/goma-operator:0.1.0-rc.2
|
||||
IMG ?= jkaninda/goma-operator:0.1.0-rc.5
|
||||
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
|
||||
ENVTEST_K8S_VERSION = 1.31.0
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ A Kubernetes operator for managing Goma Gateway.
|
||||
- [Docker Hub](https://hub.docker.com/r/jkaninda/goma-operator)
|
||||
- [Github](https://github.com/jkaninda/goma-operator)
|
||||
|
||||
### Documentation is found at <https://jkaninda.github.io/goma-gateway/install/kuberntes-advanced.html>
|
||||
### Documentation is found at <https://jkaninda.github.io/goma-gateway/operator-manual/installation.html>
|
||||
|
||||
|
||||
### 1. Kubernetes installation
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -5,4 +5,4 @@ kind: Kustomization
|
||||
images:
|
||||
- name: controller
|
||||
newName: jkaninda/goma-operator
|
||||
newTag: 0.1.0-rc.2
|
||||
newTag: 0.1.0-rc.5
|
||||
|
||||
161
dist/install.yaml
vendored
161
dist/install.yaml
vendored
@@ -1286,95 +1286,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.
|
||||
@@ -1788,7 +1777,7 @@ spec:
|
||||
- --health-probe-bind-address=:8081
|
||||
command:
|
||||
- /manager
|
||||
image: jkaninda/goma-operator:0.1.0-rc.2
|
||||
image: jkaninda/goma-operator:0.1.0-rc.5
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
|
||||
1
go.mod
1
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
|
||||
|
||||
2
go.sum
2
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=
|
||||
|
||||
@@ -41,7 +41,7 @@ func createUpdateDeployment(r GatewayReconciler, ctx context.Context, req ctrl.R
|
||||
})
|
||||
if len(gateway.Spec.Server.TlsSecretName) != 0 {
|
||||
volumes = append(volumes, corev1.Volume{
|
||||
Name: req.Name,
|
||||
Name: "certs",
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
Secret: &corev1.SecretVolumeSource{
|
||||
SecretName: gateway.Spec.Server.TlsSecretName,
|
||||
@@ -49,7 +49,7 @@ func createUpdateDeployment(r GatewayReconciler, ctx context.Context, req ctrl.R
|
||||
},
|
||||
})
|
||||
volumeMounts = append(volumeMounts, corev1.VolumeMount{
|
||||
Name: req.Name,
|
||||
Name: "certs",
|
||||
ReadOnly: true,
|
||||
MountPath: CertsPath,
|
||||
})
|
||||
@@ -100,7 +100,7 @@ func createUpdateDeployment(r GatewayReconciler, ctx context.Context, req ctrl.R
|
||||
},
|
||||
},
|
||||
ReadinessProbe: &corev1.Probe{
|
||||
InitialDelaySeconds: 5,
|
||||
InitialDelaySeconds: 15,
|
||||
PeriodSeconds: 10,
|
||||
ProbeHandler: corev1.ProbeHandler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
@@ -110,7 +110,7 @@ func createUpdateDeployment(r GatewayReconciler, ctx context.Context, req ctrl.R
|
||||
},
|
||||
},
|
||||
LivenessProbe: &corev1.Probe{
|
||||
InitialDelaySeconds: 15,
|
||||
InitialDelaySeconds: 30,
|
||||
PeriodSeconds: 30,
|
||||
ProbeHandler: corev1.ProbeHandler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
@@ -203,7 +203,7 @@ func equalDeploymentSpec(existing, desired v1.DeploymentSpec, autoScalingEnabled
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (r *RouteReconciler) RestartDeployment(ctx context.Context, req ctrl.Request, gateway gomaprojv1beta1.Gateway) error {
|
||||
func restartDeployment(r client.Client, ctx context.Context, req ctrl.Request, gateway *gomaprojv1beta1.Gateway) error {
|
||||
logger := log.FromContext(ctx)
|
||||
// Fetch the Deployment
|
||||
var deployment v1.Deployment
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -151,6 +152,11 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
|
||||
addCondition(&gateway.Status, "ConfigMapReady", metav1.ConditionFalse, "ConfigMapReady", "Failed to update ConfigMap for Gateway")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
if err = restartDeployment(r.Client, ctx, req, gateway); err != nil {
|
||||
logger.Error(err, "Failed to restart Deployment")
|
||||
return ctrl.Result{}, err
|
||||
|
||||
}
|
||||
logger.Info("Updated ConfigMap", "ConfigMap.Name", configMap.Name)
|
||||
}
|
||||
|
||||
@@ -194,11 +200,6 @@ func (r *GatewayReconciler) updateStatus(ctx context.Context, gateway *gomaprojv
|
||||
return r.Client.Status().Update(ctx, gateway)
|
||||
}
|
||||
|
||||
// Helper function to return a pointer to an int32
|
||||
func int32Ptr(i int32) *int32 {
|
||||
return &i
|
||||
}
|
||||
|
||||
func addCondition(status *gomaprojv1beta1.GatewayStatus, condType string, statusType metav1.ConditionStatus, reason, message string) {
|
||||
for i, existingCondition := range status.Conditions {
|
||||
if existingCondition.Type == condType {
|
||||
@@ -291,8 +292,10 @@ func (r *GatewayReconciler) finalize(ctx context.Context, gateway *gomaprojv1bet
|
||||
|
||||
// SetupWithManager sets up the controller with the Manager.
|
||||
func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
pred := predicate.GenerationChangedPredicate{}
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&gomaprojv1beta1.Gateway{}).
|
||||
WithEventFilter(pred).
|
||||
Owns(&corev1.ConfigMap{}). // Watch ConfigMaps created by the controller
|
||||
Owns(&v1.Deployment{}). // Watch Deployments created by the controller
|
||||
Owns(&corev1.Service{}). // Watch Services created by the controller
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/jinzhu/copier"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
@@ -20,12 +21,14 @@ 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
|
||||
gomaConfig.Gateway.SSLCertFile = TLSCertFile
|
||||
gomaConfig.Gateway.TlsCertFile = TLSCertFile
|
||||
gomaConfig.Gateway.TlsKeyFile = TLSKeyFile
|
||||
}
|
||||
|
||||
labelSelector := client.MatchingLabels{}
|
||||
@@ -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 {
|
||||
@@ -62,15 +69,18 @@ func gatewayConfig(r GatewayReconciler, ctx context.Context, req ctrl.Request, g
|
||||
}
|
||||
return *gomaConfig
|
||||
}
|
||||
func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Request, gateway gomaprojv1beta1.Gateway) error {
|
||||
func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Request, gateway gomaprojv1beta1.Gateway) (bool, error) {
|
||||
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
|
||||
gomaConfig.Gateway.SSLCertFile = TLSCertFile
|
||||
gomaConfig.Gateway.TlsCertFile = TLSCertFile
|
||||
gomaConfig.Gateway.TlsKeyFile = TLSKeyFile
|
||||
}
|
||||
labelSelector := client.MatchingLabels{}
|
||||
var middlewareNames []string
|
||||
@@ -78,22 +88,28 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques
|
||||
var routes gomaprojv1beta1.RouteList
|
||||
if err := r.List(ctx, &routes, labelSelector, client.InNamespace(req.Namespace)); err != nil {
|
||||
logger.Error(err, "Failed to list Routes")
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
var middlewares gomaprojv1beta1.MiddlewareList
|
||||
if err := r.List(ctx, &middlewares, labelSelector, client.InNamespace(req.Namespace)); err != nil {
|
||||
logger.Error(err, "Failed to list Middlewares")
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
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 {
|
||||
if route.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
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 {
|
||||
@@ -108,7 +124,7 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques
|
||||
yamlContent, err := yaml.Marshal(&gomaConfig)
|
||||
if err != nil {
|
||||
logger.Error(err, "Unable to marshal YAML")
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
// Define the desired ConfigMap
|
||||
configMap := &corev1.ConfigMap{
|
||||
@@ -129,18 +145,18 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques
|
||||
err = r.Get(ctx, types.NamespacedName{Name: configMap.Name, Namespace: configMap.Namespace}, &existingConfigMap)
|
||||
if err != nil && client.IgnoreNotFound(err) != nil {
|
||||
logger.Error(err, "Failed to get ConfigMap")
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err != nil && client.IgnoreNotFound(err) == nil {
|
||||
// Create the ConfigMap if it doesn't exist
|
||||
if err = controllerutil.SetControllerReference(&gateway, configMap, r.Scheme); err != nil {
|
||||
logger.Error(err, "Failed to set controller reference")
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if err = r.Create(ctx, configMap); err != nil {
|
||||
logger.Error(err, "Failed to create ConfigMap")
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
logger.Info("Created ConfigMap", "ConfigMap.Name", configMap.Name)
|
||||
} else {
|
||||
@@ -149,13 +165,13 @@ func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Reques
|
||||
existingConfigMap.Data = configMap.Data
|
||||
if err = r.Update(ctx, &existingConfigMap); err != nil {
|
||||
logger.Error(err, "Failed to update ConfigMap")
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
logger.Info("Updated ConfigMap", "ConfigMap.Name", configMap.Name)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
@@ -215,3 +231,8 @@ func mapMid(middleware gomaprojv1beta1.Middleware) *Middleware {
|
||||
}
|
||||
return mid
|
||||
}
|
||||
|
||||
// Helper function to return a pointer to an int32
|
||||
func int32Ptr(i int32) *int32 {
|
||||
return &i
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
gomaprojv1beta1 "github.com/jkaninda/goma-operator/api/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -55,8 +56,8 @@ type RouteReconciler struct {
|
||||
func (r *RouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
logger := log.FromContext(ctx)
|
||||
// Fetch the custom resource
|
||||
var route gomaprojv1beta1.Route
|
||||
if err := r.Get(ctx, req.NamespacedName, &route); err != nil {
|
||||
route := &gomaprojv1beta1.Route{}
|
||||
if err := r.Get(ctx, req.NamespacedName, route); err != nil {
|
||||
logger.Error(err, "Unable to fetch CustomResource")
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
@@ -65,15 +66,48 @@ func (r *RouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
|
||||
logger.Error(err, "Failed to fetch Gateway")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
err := updateGatewayConfig(*r, ctx, req, gateway)
|
||||
|
||||
// Check if the object is being deleted and if so, handle it
|
||||
if route.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
if !controllerutil.ContainsFinalizer(route, FinalizerName) {
|
||||
controllerutil.AddFinalizer(route, FinalizerName)
|
||||
err := r.Update(ctx, route)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if controllerutil.ContainsFinalizer(route, FinalizerName) {
|
||||
// Once finalization is done, remove the finalizer
|
||||
ok, err := updateGatewayConfig(*r, ctx, req, gateway)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
if ok {
|
||||
if err = restartDeployment(r.Client, ctx, req, &gateway); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
// Remove the finalizer
|
||||
controllerutil.RemoveFinalizer(route, FinalizerName)
|
||||
err = r.Update(ctx, route)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
ok, err := updateGatewayConfig(*r, ctx, req, gateway)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
//
|
||||
if err = r.RestartDeployment(ctx, req, gateway); err != nil {
|
||||
logger.Error(err, "Failed to restart Deployment")
|
||||
return ctrl.Result{}, err
|
||||
if ok {
|
||||
if err = restartDeployment(r.Client, ctx, req, &gateway); err != nil {
|
||||
logger.Error(err, "Failed to restart Deployment")
|
||||
return ctrl.Result{}, err
|
||||
|
||||
}
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -4,10 +4,10 @@ import gomaprojv1beta1 "github.com/jkaninda/goma-operator/api/v1beta1"
|
||||
|
||||
// Gateway contains Goma Proxy Gateway's configs
|
||||
type Gateway struct {
|
||||
// SSLCertFile SSL Certificate file
|
||||
SSLCertFile string `yaml:"sslCertFile"`
|
||||
// SSLKeyFile SSL Private key file
|
||||
SSLKeyFile string `yaml:"sslKeyFile"`
|
||||
// TlsCertFile SSL Certificate file
|
||||
TlsCertFile string `yaml:"tlsCertFile"`
|
||||
// TlsKeyFile SSL Private key file
|
||||
TlsKeyFile string `yaml:"tlsKeyFile"`
|
||||
// Redis contains redis database details
|
||||
Redis gomaprojv1beta1.Redis `yaml:"redis"`
|
||||
// WriteTimeout defines proxy write timeout
|
||||
@@ -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"`
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const (
|
||||
RateLimit = "rateLimit"
|
||||
BelongsTo = "goma-gateway"
|
||||
GatewayConfigVersion = "1.0"
|
||||
FinalizerName = "finalizer.gomaproj.jonaskaninda.com"
|
||||
FinalizerName = "gomaproj.github.io/resources.finalizer"
|
||||
ConfigName = "goma.yml"
|
||||
TLSCertFile = "/etc/goma/certs/tls.crt"
|
||||
TLSKeyFile = "/etc/goma/certs/tls.key"
|
||||
|
||||
Reference in New Issue
Block a user