From 490040a628de3f6d166713280d33f6263728adec Mon Sep 17 00:00:00 2001 From: Kristina Pathak Date: Wed, 23 Mar 2022 13:53:43 -0700 Subject: [PATCH] added v2 endpoint configurable support (#167) * added v2 endpoint configurable support * small fixes --- CHANGELOG.md | 6 ++- deploy/packaging/scytale_spruce.yaml | 6 +++ main.go | 1 - primaryHandler.go | 60 ++++++++++++++++------------ scytale.yaml | 8 +++- 5 files changed, 53 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46202f0..fe6b2f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [v0.6.2] - Updated spec file and rpkg version macro to be able to choose when the 'v' is included in the version. [#163](https://github.com/xmidt-org/scytale/pull/163) - Reconfigured the Bascule Logger settings so that the logger isn't overwritten [#166](https://github.com/xmidt-org/scytale/pull/166) +- Added configurable v2 endpoint support. []() ## [v0.6.1] - Fixed url parsing bug where we were leaving a '/'. [#161](https://github.com/xmidt-org/scytale/pull/161) @@ -100,7 +103,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Initial creation. -[Unreleased]: https://github.com/xmidt-org/scytale/compare/v0.6.1...HEAD +[Unreleased]: https://github.com/xmidt-org/scytale/compare/v0.6.2...HEAD +[v0.6.2]: https://github.com/xmidt-org/scytale/compare/v0.6.1...v0.6.2 [v0.6.1]: https://github.com/xmidt-org/scytale/compare/v0.6.0...v0.6.1 [v0.6.0]: https://github.com/xmidt-org/scytale/compare/v0.5.0...v0.6.0 [v0.5.0]: https://github.com/xmidt-org/scytale/compare/v0.4.11...v0.5.0 diff --git a/deploy/packaging/scytale_spruce.yaml b/deploy/packaging/scytale_spruce.yaml index 1866fb3..08afadf 100644 --- a/deploy/packaging/scytale_spruce.yaml +++ b/deploy/packaging/scytale_spruce.yaml @@ -450,3 +450,9 @@ tracing: #authtoken used to make spruce work better for authAcquirer authToken: (( grab $AUTH_TOKEN || "dXNlcjpwYXNz" )) + +# previousVersionSupport allows us to support two different major versions of +# the API at the same time from the same application. When this is true, +# scytale will support both "/v2" and "/v3" endpoints. When false, only "/v3" +# endpoints will be supported. +previousVersionSupport: (( grab $PREV_VERSION_SUPPORT || true )) diff --git a/main.go b/main.go index 6cc7eae..6df8774 100644 --- a/main.go +++ b/main.go @@ -46,7 +46,6 @@ const ( DefaultKeyID = "current" applicationName = "scytale" - release = "Developer" tracingConfigKey = "tracing" ) diff --git a/primaryHandler.go b/primaryHandler.go index e51da30..7e60253 100644 --- a/primaryHandler.go +++ b/primaryHandler.go @@ -54,7 +54,10 @@ import ( ) const ( - apiBase = "/api/v3" + apiVersion = "v3" + prevAPIVersion = "v2" + apiBase = "api/" + apiVersion + apiBaseDualVersion = "api/{version:" + apiVersion + "|" + prevAPIVersion + "}" basicAuthConfigKey = "authHeader" jwtAuthConfigKey = "jwtValidator" @@ -92,7 +95,6 @@ func authChain(v *viper.Viper, logger log.Logger, registry xmetrics.Registry) (a options := []basculehttp.COption{ basculehttp.WithCLogger(getLogger), basculehttp.WithCErrorResponseFunc(listener.OnErrorResponse), - basculehttp.WithParseURLFunc(basculehttp.CreateRemovePrefixURLFunc(apiBase+"/", basculehttp.DefaultParseURLFunc)), } if len(basicAllowed) > 0 { options = append(options, basculehttp.WithTokenFactory("Basic", basculehttp.BasicTokenFactory(basicAllowed))) @@ -113,8 +115,13 @@ func authChain(v *viper.Viper, logger log.Logger, registry xmetrics.Registry) (a Leeway: jwtVal.Leeway, })) } - - authConstructor := basculehttp.NewConstructor(options...) + authConstructor := basculehttp.NewConstructor(append([]basculehttp.COption{ + basculehttp.WithParseURLFunc(basculehttp.CreateRemovePrefixURLFunc("/"+apiBase+"/", basculehttp.DefaultParseURLFunc)), + }, options...)...) + authConstructorLegacy := basculehttp.NewConstructor(append([]basculehttp.COption{ + basculehttp.WithParseURLFunc(basculehttp.CreateRemovePrefixURLFunc("/api/"+prevAPIVersion+"/", basculehttp.DefaultParseURLFunc)), + basculehttp.WithCErrorHTTPResponseFunc(basculehttp.LegacyOnErrorHTTPResponse), + }, options...)...) bearerRules := bascule.Validators{ bchecks.NonEmptyPrincipal(), @@ -157,23 +164,22 @@ func authChain(v *viper.Viper, logger log.Logger, registry xmetrics.Registry) (a basculehttp.WithEErrorResponseFunc(listener.OnErrorResponse), ) - constructors := []alice.Constructor{setLogger(logger, extractIntendedDestination), authConstructor, authEnforcer, basculehttp.NewListenerDecorator(listener)} - - return alice.New(constructors...), nil -} + authChain := alice.New(setLogger(logger), authConstructor, authEnforcer, basculehttp.NewListenerDecorator(listener)) + authChainLegacy := alice.New(setLogger(logger), authConstructorLegacy, authEnforcer, basculehttp.NewListenerDecorator(listener)) -// custom logger func that extracts the intended destination of requests -func extractIntendedDestination(kv []interface{}, request *http.Request) []interface{} { - if deviceName := request.Header.Get("X-Webpa-Device-Name"); len(deviceName) > 0 { - return append(kv, "X-Webpa-Device-Name", deviceName) - } - - if variables := mux.Vars(request); len(variables) > 0 { - if deviceID := variables["deviceID"]; len(deviceID) > 0 { - return append(kv, "deviceID", deviceID) - } - } - return kv + versionCompatibleAuth := alice.New(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(r http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + if vars != nil { + if vars["version"] == prevAPIVersion { + authChainLegacy.Then(next).ServeHTTP(r, req) + return + } + } + authChain.Then(next).ServeHTTP(r, req) + }) + }) + return versionCompatibleAuth, nil } // createEndpoints examines the configuration and produces an appropriate fanout.Endpoints, either using the configured @@ -296,10 +302,14 @@ func NewPrimaryHandler(logger log.Logger, v *viper.Viper, registry xmetrics.Regi ) } - var ( - router = mux.NewRouter() - sendSubrouter = router.Path(fmt.Sprintf("%s/device", apiBase)).Methods("POST", "PUT").Subrouter() - ) + router := mux.NewRouter() + // if we want to support the previous API version, then include it in the + // api base. + urlPrefix := fmt.Sprintf("/%s", apiBase) + if v.GetBool("previousVersionSupport") { + urlPrefix = fmt.Sprintf("/%s", apiBaseDualVersion) + } + sendSubrouter := router.Path(fmt.Sprintf("%s/device", urlPrefix)).Methods("POST", "PUT").Subrouter() otelMuxOptions := []otelmux.Option{ otelmux.WithPropagators(tracing.Propagator()), @@ -380,7 +390,7 @@ func NewPrimaryHandler(logger log.Logger, v *viper.Viper, registry xmetrics.Regi Handler(authChain.Then(sendWRPHandler)) router.Handle( - fmt.Sprintf("%s/device/{deviceID}/stat", apiBase), + fmt.Sprintf("%s/device/{deviceID}/stat", urlPrefix), authChain.Extend(fanoutChain).Then( fanout.New( endpoints, diff --git a/scytale.yaml b/scytale.yaml index 3f7f8a7..bf94390 100644 --- a/scytale.yaml +++ b/scytale.yaml @@ -473,4 +473,10 @@ tracing: # skipTraceExport: true # endpoint is where trace information should be routed. Applies to zipkin and jaegar. - # endpoint: "http://localhost:9411/api/v2/spans" \ No newline at end of file + # endpoint: "http://localhost:9411/api/v2/spans" + +# previousVersionSupport allows us to support two different major versions of +# the API at the same time from the same application. When this is true, +# scytale will support both "/v2" and "/v3" endpoints. When false, only "/v3" +# endpoints will be supported. +previousVersionSupport: true