From 7369d5eebf9fe4383fc7b96b0e8303443ce7002c Mon Sep 17 00:00:00 2001 From: Jonas Kaninda Date: Thu, 21 Nov 2024 16:52:08 +0100 Subject: [PATCH] feat: add load additional middleware from a defined directory --- Dockerfile | 7 ++++--- internal/middleware.go | 45 ++++++++++++++++++++++++++++++++++++++++ internal/route_config.go | 3 +++ internal/route_type.go | 4 ++++ internal/routes.go | 39 ++++++++++++++++++++++------------ internal/var.go | 6 ++++-- 6 files changed, 86 insertions(+), 18 deletions(-) diff --git a/Dockerfile b/Dockerfile index b30b7c0..85b76a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,15 +13,16 @@ RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-X 'github.com/jkaninda/goma-gat FROM alpine:3.20.3 ENV TZ=UTC -ARG WORKDIR="/etc/goma/" +ARG WORKDIR="/etc/goma" +ARG EXTRADIR="${WORKDIR}/extra" ARG appVersion="" ARG user="goma" LABEL author="Jonas Kaninda" LABEL version=${appVersion} LABEL github="github.com/jkaninda/goma-gateway" -RUN mkdir -p ${WORKDIR} && \ - chmod a+rw ${WORKDIR} +RUN mkdir -p ${WORKDIR} ${EXTRADIR} && \ + chmod a+rw ${WORKDIR} ${EXTRADIR} COPY --from=build /app/goma /usr/local/bin/goma RUN chmod a+x /usr/local/bin/goma && \ ln -s /usr/local/bin/goma /usr/bin/goma diff --git a/internal/middleware.go b/internal/middleware.go index b72fec4..9339cff 100644 --- a/internal/middleware.go +++ b/internal/middleware.go @@ -2,6 +2,9 @@ package pkg import ( "errors" + "fmt" + "gopkg.in/yaml.v3" + "os" "slices" "strings" ) @@ -32,3 +35,45 @@ func GetMiddleware(rule string, middlewares []Middleware) (Middleware, error) { return Middleware{}, errors.New("no middlewares found with name " + rule) } + +// loadExtraMiddlewares loads additional middlewares +func loadExtraMiddlewares(routePath string) ([]Middleware, error) { + yamlFiles, err := loadExtraFiles(routePath) + if err != nil { + return nil, fmt.Errorf("error loading extra files: %v", err) + } + var extraMiddlewares []Middleware + for _, yamlFile := range yamlFiles { + buf, err := os.ReadFile(yamlFile) + if err != nil { + return nil, fmt.Errorf("error loading extra file: %v", err) + } + ex := &ExtraMiddleware{} + err = yaml.Unmarshal(buf, ex) + if err != nil { + return nil, fmt.Errorf("in file %q: %w", ConfigFile, err) + } + extraMiddlewares = append(extraMiddlewares, ex.Middlewares...) + + } + if len(extraMiddlewares) == 0 { + return nil, fmt.Errorf("no extra middleware found") + } + return extraMiddlewares, nil +} + +// findDuplicateMiddlewareNames finds duplicated middleware name +func findDuplicateMiddlewareNames(middlewares []Middleware) []string { + // Create a map to track occurrences of names + nameMap := make(map[string]int) + var duplicates []string + + for _, mid := range middlewares { + nameMap[mid.Name]++ + // If the count is ==2, it's a duplicate + if nameMap[mid.Name] == 2 { + duplicates = append(duplicates, mid.Name) + } + } + return duplicates +} diff --git a/internal/route_config.go b/internal/route_config.go index 051a4b4..1ca3cc6 100644 --- a/internal/route_config.go +++ b/internal/route_config.go @@ -43,6 +43,9 @@ func loadExtraRoutes(routePath string) ([]Route, error) { extraRoutes = append(extraRoutes, ex.Routes...) } + if len(extraRoutes) == 0 { + return nil, fmt.Errorf("no extra routes found") + } return extraRoutes, nil } diff --git a/internal/route_type.go b/internal/route_type.go index b544eee..2781037 100644 --- a/internal/route_type.go +++ b/internal/route_type.go @@ -61,3 +61,7 @@ type ExtraRoute struct { // Routes holds proxy routes Routes []Route `yaml:"routes"` } +type ExtraMiddleware struct { + // Routes holds proxy routes + Middlewares []Middleware `yaml:"middlewares"` +} diff --git a/internal/routes.go b/internal/routes.go index 084b36e..fa84671 100644 --- a/internal/routes.go +++ b/internal/routes.go @@ -37,28 +37,41 @@ func init() { func (gatewayServer GatewayServer) Initialize() *mux.Router { gateway := gatewayServer.gateway dynamicRoutes = gateway.Routes + dynamicMiddlewares = gatewayServer.middlewares + if len(gateway.ExtraRoutes.Directory) == 0 { + gateway.ExtraRoutes.Directory = ExtraDir + } + // Load Extra Middlewares + logger.Info("Loading additional configurations...") + extraMiddlewares, err := loadExtraMiddlewares(gateway.ExtraRoutes.Directory) + if err == nil { + dynamicMiddlewares = append(dynamicMiddlewares, extraMiddlewares...) + logger.Info("Loaded %d additional middlewares", len(extraMiddlewares)) + + } // Load Extra Routes - if len(gateway.ExtraRoutes.Directory) != 0 { - logger.Info("Loading additional routes from %s", gateway.ExtraRoutes.Directory) - extraRoutes, err := loadExtraRoutes(gateway.ExtraRoutes.Directory) - if err != nil { - logger.Error("Error: %v", err.Error()) - } - if len(extraRoutes) == 0 { - logger.Info("no extra routes found in %s", gateway.ExtraRoutes.Directory) - } else { - dynamicRoutes = append(dynamicRoutes, extraRoutes...) - logger.Info("Loaded %d extra routes from %s", len(extraRoutes), gateway.ExtraRoutes.Directory) + extraRoutes, err := loadExtraRoutes(gateway.ExtraRoutes.Directory) + if err == nil { + dynamicRoutes = append(dynamicRoutes, extraRoutes...) + logger.Info("Loaded %d additional routes", len(extraRoutes)) + + } + + // find duplicated middleware name + duplicates := findDuplicateMiddlewareNames(dynamicMiddlewares) + if len(duplicates) != 0 { + for _, duplicate := range duplicates { + logger.Fatal("Duplicated middleware name: %s, the name of the middleware should be unique.", duplicate) } } // find duplicated route name - duplicates := findDuplicateRouteNames(dynamicRoutes) + duplicates = findDuplicateRouteNames(dynamicRoutes) if len(duplicates) != 0 { for _, duplicate := range duplicates { logger.Error("Duplicated route name was found: %s ", duplicate) } } - m := gatewayServer.middlewares + m := dynamicMiddlewares redisBased := false if len(gateway.Redis.Addr) != 0 { redisBased = true diff --git a/internal/var.go b/internal/var.go index 4a71ff5..7698733 100644 --- a/internal/var.go +++ b/internal/var.go @@ -1,6 +1,7 @@ package pkg -const ConfigDir = "/etc/goma/" // Default configuration file +const ConfigDir = "/etc/goma/" // Default configuration file +const ExtraDir = ConfigDir + "extra" const ConfigFile = "/etc/goma/goma.yml" // Default configuration file const accessControlAllowOrigin = "Access-Control-Allow-Origin" // Cors const gatewayName = "Goma Gateway" @@ -12,5 +13,6 @@ var ( // Round-robin counter counter uint32 // dynamicRoutes routes - dynamicRoutes []Route + dynamicRoutes []Route + dynamicMiddlewares []Middleware )