Skip to content

Commit

Permalink
feat: support for path based routing to other services
Browse files Browse the repository at this point in the history
  • Loading branch information
shreddedbacon committed Sep 9, 2024
1 parent 1ab7d8a commit bc8a92e
Show file tree
Hide file tree
Showing 15 changed files with 687 additions and 29 deletions.
28 changes: 26 additions & 2 deletions cmd/template_autogen_ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"reflect"
"testing"

"github.com/andreyvit/diff"
"github.com/uselagoon/build-deploy-tool/internal/helpers"
"github.com/uselagoon/build-deploy-tool/internal/lagoon"
"github.com/uselagoon/build-deploy-tool/internal/testdata"
Expand Down Expand Up @@ -507,6 +508,30 @@ func TestAutogeneratedIngressGeneration(t *testing.T) {
templatePath: "testdata/output",
want: "internal/testdata/node/autogen-templates/ingress-15",
},
{
name: "test29-autogenerated-pathroutes",
args: testdata.GetSeedData(
testdata.TestData{
ProjectName: "example-project",
EnvironmentName: "main",
Branch: "main",
LagoonYAML: "internal/testdata/basic/lagoon.pathroutes.yml",
}, true),
templatePath: "testdata/output",
want: "internal/testdata/basic/autogen-templates/test29-autogenerated-pathroutes",
},
{
name: "test29b-autogenerated-pathroutes",
args: testdata.GetSeedData(
testdata.TestData{
ProjectName: "example-project",
EnvironmentName: "main",
Branch: "main",
LagoonYAML: "internal/testdata/basic/lagoon.pathroutes-2.yml",
}, true),
templatePath: "testdata/output",
want: "internal/testdata/basic/autogen-templates/test29-autogenerated-pathroutes",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -567,8 +592,7 @@ func TestAutogeneratedIngressGeneration(t *testing.T) {
t.Errorf("couldn't read file %v: %v", tt.want, err)
}
if !reflect.DeepEqual(f1, r1) {
fmt.Println(string(f1))
t.Errorf("resulting templates do not match")
t.Errorf("AutogeneratedIngressGeneration() = \n%v", diff.LineDiff(string(r1), string(f1)))
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions cmd/template_ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"
"testing"

"github.com/andreyvit/diff"
"github.com/uselagoon/build-deploy-tool/internal/helpers"
"github.com/uselagoon/build-deploy-tool/internal/lagoon"
"github.com/uselagoon/build-deploy-tool/internal/testdata"
Expand Down Expand Up @@ -419,6 +420,18 @@ func TestTemplateRoutes(t *testing.T) {
templatePath: "testdata/output",
want: "internal/testdata/node/ingress-templates/ingress-23",
},
{
name: "test25-pathroutes",
args: testdata.GetSeedData(
testdata.TestData{
ProjectName: "example-project",
EnvironmentName: "main",
Branch: "main",
LagoonYAML: "internal/testdata/basic/lagoon.pathroutes.yml",
}, true),
templatePath: "testdata/output",
want: "internal/testdata/basic/ingress-templates/test25-pathroutes",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -480,8 +493,7 @@ func TestTemplateRoutes(t *testing.T) {
t.Errorf("couldn't read file %v: %v", tt.want, err)
}
if !reflect.DeepEqual(f1, r1) {
fmt.Println(string(f1))
t.Errorf("resulting templates do not match")
t.Errorf("IngressTemplateGeneration() = \n%v", diff.LineDiff(string(r1), string(f1)))
}
}
}
Expand Down
67 changes: 67 additions & 0 deletions internal/generator/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,40 @@ func generateAutogenRoutes(
if buildValues.LagoonYAML.Routes.Autogenerate.IngressClass != "" {
ingressClass = buildValues.LagoonYAML.Routes.Autogenerate.IngressClass
}
var pathRoutes []lagoon.PathRoute
// calculate path based routing for autogenerated routes
// check for environment specific path routes
agPathRoutes := buildValues.LagoonYAML.Environments[buildValues.Environment].AutogeneratePathRoutes
if agPathRoutes == nil {
// if none, check for global path routes
agPathRoutes = buildValues.LagoonYAML.Routes.Autogenerate.PathRoutes
}
// check the services for the path routes are valid
for _, pr := range agPathRoutes {
// check the provided "from service" exists

if pr.FromService == "" {
return fmt.Errorf("autogenerated path route has no fromService defined")
}
if pr.ToService == "" {
return fmt.Errorf("autogenerated path route has no toService defined")
}
if pr.Path == "" {
return fmt.Errorf("autogenerated path route has no path defined")
}
if err := checkServiceInServices(pr.FromService, *buildValues); err != nil {
return err
}
// if the from service matches this service
if pr.FromService == serviceOverrideName {
// check the provided "to service" exists
if err := checkServiceInServices(pr.ToService, *buildValues); err != nil {
return err
}
// if all good, add the path routes to this
pathRoutes = append(pathRoutes, pr.PathRoute)
}
}
autogenRoute := lagoon.RouteV2{
Domain: domain,
Fastly: *fastlyConfig,
Expand All @@ -189,6 +223,7 @@ func generateAutogenRoutes(
Insecure: &insecure,
AlternativeNames: alternativeNames,
RequestVerification: helpers.BoolPtr(service.AutogeneratedRoutesRequestVerification),
PathRoutes: pathRoutes,
}
autogenRoutes.Routes = append(autogenRoutes.Routes, autogenRoute)
}
Expand Down Expand Up @@ -321,5 +356,37 @@ func generateAndMerge(
if err != nil {
return *n, err
}

// check computed routes to make sure that any defined path routes have valid service backends
for _, mr := range mainRoutes.Routes {
for _, pr := range mr.PathRoutes {
// check if the provided "to service" is valid

if pr.ToService == "" {
return *n, fmt.Errorf("path route for %s has no toService defined", mr.Domain)
}
if pr.Path == "" {
return *n, fmt.Errorf("path route for %s has no path defined", mr.Domain)
}
if err := checkServiceInServices(pr.ToService, buildValues); err != nil {
return *n, err
}
}
}
return mainRoutes, nil
}

func checkServiceInServices(service string, buildValues BuildValues) error {
for _, s := range buildValues.Services {
if s.Name == service {
return nil
}
for _, sp := range s.AdditionalServicePorts {
if sp.ServiceName == service {
// matches an additional service port
return nil
}
}
}
return fmt.Errorf("%s is not a valid service reference", service)
}
168 changes: 167 additions & 1 deletion internal/generator/ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,76 @@ func Test_generateAndMerge(t *testing.T) {
Routes: nil,
},
},
{
name: "test7 - path based routes",
args: args{
buildValues: BuildValues{
Branch: "main",
IngressClass: "nginx",
Services: []ServiceValues{
{
Name: "nginx",
Type: "nginx",
AutogeneratedRoutesEnabled: false,
AutogeneratedRoutesTLSAcme: true,
},
{
Name: "node",
Type: "node",
AutogeneratedRoutesEnabled: false,
AutogeneratedRoutesTLSAcme: true,
},
},
LagoonYAML: lagoon.YAML{
DockerComposeYAML: "docker-compose.yml",
Environments: lagoon.Environments{
"main": lagoon.Environment{
Routes: []map[string][]lagoon.Route{
{
"nginx": {
{
Ingresses: map[string]lagoon.Ingress{
"a.example.com": {
PathRoutes: []lagoon.PathRoute{
{
ToService: "node",
Path: "/api/v1",
},
},
},
},
},
},
},
},
},
},
},
},
},
want: lagoon.RoutesV2{
Routes: []lagoon.RouteV2{
{
Domain: "a.example.com",
LagoonService: "nginx",
TLSAcme: helpers.BoolPtr(true),
Annotations: map[string]string{},
MonitoringPath: "/",
Insecure: helpers.StrPtr("Redirect"),
IngressClass: "nginx",
AlternativeNames: []string{},
IngressName: "a.example.com",
RequestVerification: helpers.BoolPtr(false),
PathRoutes: []lagoon.PathRoute{
{
ToService: "node",
Path: "/api/v1",
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -925,7 +995,7 @@ func Test_generateAutogenRoutes(t *testing.T) {
},
},
{
name: "test2 - autogenerated routes ingress class",
name: "test3 - autogenerated routes ingress class",
args: args{
envVars: []lagoon.EnvironmentVariable{
{
Expand Down Expand Up @@ -984,6 +1054,102 @@ func Test_generateAutogenRoutes(t *testing.T) {
},
},
},
{
name: "test4 autogen path based",
args: args{
envVars: []lagoon.EnvironmentVariable{
{
Name: "LAGOON_SYSTEM_ROUTER_PATTERN",
Value: "${service}-${project}-${environment}.example.com",
Scope: "internal_system",
},
},
buildValues: &BuildValues{
Project: "example-com",
BuildType: "branch",
Environment: "main",
EnvironmentType: "development",
Namespace: "example-com-main",
Services: []ServiceValues{
{
Name: "nginx",
Type: "nginx",
AutogeneratedRoutesEnabled: true,
AutogeneratedRoutesTLSAcme: true,
},
{
Name: "node",
Type: "node",
AutogeneratedRoutesEnabled: true,
AutogeneratedRoutesTLSAcme: true,
},
},
LagoonYAML: lagoon.YAML{
Routes: lagoon.Routes{
Autogenerate: lagoon.Autogenerate{
PathRoutes: []lagoon.AutogeneratePathRoute{
{
FromService: "nginx",
PathRoute: lagoon.PathRoute{
ToService: "node",
Path: "/api/v1",
},
},
},
},
}},
},
autogenRoutes: &lagoon.RoutesV2{},
},
want: lagoon.RoutesV2{
Routes: []lagoon.RouteV2{
{
Domain: "nginx-example-com-main.example.com",
LagoonService: "nginx",
ComposeService: "nginx",
Autogenerated: true,
TLSAcme: helpers.BoolPtr(true),
Insecure: helpers.StrPtr("Allow"),
AlternativeNames: []string{},
Labels: map[string]string{
"app.kubernetes.io/instance": "nginx",
"app.kubernetes.io/name": "autogenerated-ingress",
"lagoon.sh/autogenerated": "true",
"lagoon.sh/service": "nginx",
"lagoon.sh/service-type": "nginx",
"lagoon.sh/template": "autogenerated-ingress-0.1.0",
},
IngressName: "nginx",
RequestVerification: helpers.BoolPtr(false),
PathRoutes: []lagoon.PathRoute{
{
ToService: "node",
Path: "/api/v1",
},
},
},
{
Domain: "node-example-com-main.example.com",
LagoonService: "node",
ComposeService: "node",
Autogenerated: true,
TLSAcme: helpers.BoolPtr(true),
Insecure: helpers.StrPtr("Allow"),
AlternativeNames: []string{},
Labels: map[string]string{
"app.kubernetes.io/instance": "node",
"app.kubernetes.io/name": "autogenerated-ingress",
"lagoon.sh/autogenerated": "true",
"lagoon.sh/service": "node",
"lagoon.sh/service-type": "node",
"lagoon.sh/template": "autogenerated-ingress-0.1.0",
},
IngressName: "node",
RequestVerification: helpers.BoolPtr(false),
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
Loading

0 comments on commit bc8a92e

Please sign in to comment.