206 lines
6.2 KiB
Go
206 lines
6.2 KiB
Go
|
|
package controller
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"slices"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
gomaprojv1beta1 "github.com/jkaninda/goma-operator/api/v1beta1"
|
||
|
|
"gopkg.in/yaml.v3"
|
||
|
|
corev1 "k8s.io/api/core/v1"
|
||
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
|
|
"k8s.io/apimachinery/pkg/types"
|
||
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
||
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||
|
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||
|
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||
|
|
)
|
||
|
|
|
||
|
|
func gatewayConfig(r GatewayReconciler, ctx context.Context, req ctrl.Request, gateway *gomaprojv1beta1.Gateway) GatewayConfig {
|
||
|
|
logger := log.FromContext(ctx)
|
||
|
|
gomaConfig := &GatewayConfig{}
|
||
|
|
gomaConfig.Version = GatewayConfigVersion
|
||
|
|
gomaConfig.Gateway = mapToGateway(gateway.Spec)
|
||
|
|
labelSelector := client.MatchingLabels{}
|
||
|
|
var middlewareNames []string
|
||
|
|
// List ConfigMaps in the namespace with the matching label
|
||
|
|
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 *gomaConfig
|
||
|
|
}
|
||
|
|
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 *gomaConfig
|
||
|
|
}
|
||
|
|
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...)
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for _, mid := range middlewares.Items {
|
||
|
|
middleware := *mapMid(mid)
|
||
|
|
logger.Info("Adding Middleware", "Name", middleware.Name)
|
||
|
|
if slices.Contains(middlewareNames, middleware.Name) {
|
||
|
|
gomaConfig.Middlewares = append(gomaConfig.Middlewares, middleware)
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
return *gomaConfig
|
||
|
|
}
|
||
|
|
func updateGatewayConfig(r RouteReconciler, ctx context.Context, req ctrl.Request, gateway gomaprojv1beta1.Gateway) error {
|
||
|
|
logger := log.FromContext(ctx)
|
||
|
|
gomaConfig := &GatewayConfig{}
|
||
|
|
gomaConfig.Version = GatewayConfigVersion
|
||
|
|
gomaConfig.Gateway = mapToGateway(gateway.Spec)
|
||
|
|
labelSelector := client.MatchingLabels{}
|
||
|
|
var middlewareNames []string
|
||
|
|
// List ConfigMaps in the namespace with the matching label
|
||
|
|
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
|
||
|
|
}
|
||
|
|
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
|
||
|
|
}
|
||
|
|
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...)
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for _, mid := range middlewares.Items {
|
||
|
|
middleware := *mapMid(mid)
|
||
|
|
logger.Info("Adding Middleware", "Name", middleware.Name)
|
||
|
|
if slices.Contains(middlewareNames, middleware.Name) {
|
||
|
|
gomaConfig.Middlewares = append(gomaConfig.Middlewares, middleware)
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
yamlContent, err := yaml.Marshal(&gomaConfig)
|
||
|
|
if err != nil {
|
||
|
|
logger.Error(err, "Unable to marshal YAML")
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
// Define the desired ConfigMap
|
||
|
|
configMap := &corev1.ConfigMap{
|
||
|
|
ObjectMeta: metav1.ObjectMeta{
|
||
|
|
Name: gateway.Name,
|
||
|
|
Namespace: req.Namespace,
|
||
|
|
Labels: map[string]string{
|
||
|
|
"belongs-to": BelongsTo,
|
||
|
|
"gateway": gateway.Name,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
Data: map[string]string{
|
||
|
|
ConfigName: strings.TrimSpace(string(yamlContent)),
|
||
|
|
},
|
||
|
|
}
|
||
|
|
// Check if the ConfigMap already exists
|
||
|
|
var existingConfigMap corev1.ConfigMap
|
||
|
|
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
|
||
|
|
}
|
||
|
|
|
||
|
|
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
|
||
|
|
}
|
||
|
|
if err = r.Create(ctx, configMap); err != nil {
|
||
|
|
logger.Error(err, "Failed to create ConfigMap")
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
logger.Info("Created ConfigMap", "ConfigMap.Name", configMap.Name)
|
||
|
|
} else {
|
||
|
|
// Optional: Update the ConfigMap if needed
|
||
|
|
if !equalConfigMapData(existingConfigMap.Data, configMap.Data) {
|
||
|
|
existingConfigMap.Data = configMap.Data
|
||
|
|
if err = r.Update(ctx, &existingConfigMap); err != nil {
|
||
|
|
logger.Error(err, "Failed to update ConfigMap")
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
logger.Info("Updated ConfigMap", "ConfigMap.Name", configMap.Name)
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// Helper function to compare ConfigMap data
|
||
|
|
func equalConfigMapData(existing, desired map[string]string) bool {
|
||
|
|
if len(existing) != len(desired) {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
for key, value := range desired {
|
||
|
|
if existing[key] != value {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
// mapMid converts RawExtensionT to struct
|
||
|
|
func mapMid(middleware gomaprojv1beta1.Middleware) *Middleware {
|
||
|
|
mid := &Middleware{
|
||
|
|
Name: middleware.Name,
|
||
|
|
Type: middleware.Spec.Type,
|
||
|
|
Paths: middleware.Spec.Paths,
|
||
|
|
}
|
||
|
|
switch middleware.Spec.Type {
|
||
|
|
case BasicAuth:
|
||
|
|
var basicAuth BasicRuleMiddleware
|
||
|
|
err := ConvertRawExtensionToStruct(middleware.Spec.Rule, &basicAuth)
|
||
|
|
if err != nil {
|
||
|
|
return mid
|
||
|
|
}
|
||
|
|
mid.Rule = basicAuth
|
||
|
|
return mid
|
||
|
|
case OAuth:
|
||
|
|
var oauthRulerMiddleware OauthRulerMiddleware
|
||
|
|
err := ConvertRawExtensionToStruct(middleware.Spec.Rule, &oauthRulerMiddleware)
|
||
|
|
if err != nil {
|
||
|
|
return mid
|
||
|
|
}
|
||
|
|
mid.Rule = oauthRulerMiddleware
|
||
|
|
return mid
|
||
|
|
case JWTAuth:
|
||
|
|
var jwtAuth JWTRuleMiddleware
|
||
|
|
err := ConvertRawExtensionToStruct(middleware.Spec.Rule, &jwtAuth)
|
||
|
|
if err != nil {
|
||
|
|
return mid
|
||
|
|
}
|
||
|
|
mid.Rule = jwtAuth
|
||
|
|
return mid
|
||
|
|
case ratelimit, RateLimit:
|
||
|
|
var rateLimitRuleMiddleware RateLimitRuleMiddleware
|
||
|
|
err := ConvertRawExtensionToStruct(middleware.Spec.Rule, &rateLimitRuleMiddleware)
|
||
|
|
if err != nil {
|
||
|
|
return mid
|
||
|
|
}
|
||
|
|
mid.Rule = rateLimitRuleMiddleware
|
||
|
|
return mid
|
||
|
|
}
|
||
|
|
return mid
|
||
|
|
}
|