From ce950d17c60eab8c7c2a3e67c130241f96056ac2 Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Wed, 25 Oct 2023 13:49:10 -0700 Subject: [PATCH] Don't strip trailing slashes when generating service profiles (#11519) When using the `linkerd profile` command with the `--open-api` flag to generate a service profile from a swagger file, we combine each route's base path with it's relative path to get the full path used in the service profile. However, we use `path.Join` to do so, which strips trailing slashes, leaving the final path different from the intended one. We avoid using `path.Join`, instead joining the paths manually to avoid stripping trailing slashes. Signed-off-by: Alex Leong --- pkg/profiles/openapi.go | 5 +++-- pkg/profiles/openapi_test.go | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/profiles/openapi.go b/pkg/profiles/openapi.go index 877d6a570412b..dc0f9f1c67e15 100644 --- a/pkg/profiles/openapi.go +++ b/pkg/profiles/openapi.go @@ -4,8 +4,8 @@ import ( "fmt" "io" "net/http" - "path" "sort" + "strings" "github.com/go-openapi/spec" sp "github.com/linkerd/linkerd2/controller/gen/apis/serviceprofile/v1alpha2" @@ -67,9 +67,10 @@ func swaggerToServiceProfile(swagger spec.Swagger, namespace, name, clusterDomai sort.Strings(paths) } + base := strings.TrimRight(swagger.BasePath, "/") for _, relPath := range paths { item := swagger.Paths.Paths[relPath] - path := path.Join(swagger.BasePath, relPath) + path := base + "/" + strings.TrimLeft(relPath, "/") pathRegex := PathToRegex(path) if item.Delete != nil { spec := MkRouteSpec(path, pathRegex, http.MethodDelete, item.Delete) diff --git a/pkg/profiles/openapi_test.go b/pkg/profiles/openapi_test.go index 1ea3961ae186d..e25f3892827af 100644 --- a/pkg/profiles/openapi_test.go +++ b/pkg/profiles/openapi_test.go @@ -35,6 +35,11 @@ func TestSwaggerToServiceProfile(t *testing.T) { }, }, }, + "/path/with/trailing/slash/": { + PathItemProps: spec.PathItemProps{ + Get: &spec.Operation{}, + }, + }, }, }, }, @@ -68,6 +73,13 @@ func TestSwaggerToServiceProfile(t *testing.T) { IsRetryable: true, Timeout: "60s", }, + { + Name: "GET /path/with/trailing/slash/", + Condition: &sp.RequestMatch{ + PathRegex: "/path/with/trailing/slash/", + Method: "GET", + }, + }, }, }, }