From 0725795afcab80309057dccf62a87b531b1692b2 Mon Sep 17 00:00:00 2001 From: chathuranga95 Date: Tue, 14 May 2024 12:50:13 +0530 Subject: [PATCH] Fix intelligent routing availability after deleting and re-creating an API --- .../discovery/xds/semantic_versioning.go | 150 +++--------------- .../pkg/semanticversion/semantic_version.go | 20 --- 2 files changed, 19 insertions(+), 151 deletions(-) diff --git a/adapter/internal/discovery/xds/semantic_versioning.go b/adapter/internal/discovery/xds/semantic_versioning.go index 1187cc1060..f4ed25ea14 100644 --- a/adapter/internal/discovery/xds/semantic_versioning.go +++ b/adapter/internal/discovery/xds/semantic_versioning.go @@ -36,22 +36,7 @@ func GetVersionMatchRegex(version string) string { func GetMajorMinorVersionRangeRegex(semVersion semantic_version.SemVersion) string { majorVersion := strconv.Itoa(semVersion.Major) minorVersion := strconv.Itoa(semVersion.Minor) - if semVersion.Patch == nil { - return "v" + majorVersion + "(?:\\." + minorVersion + ")?" - } - patchVersion := strconv.Itoa(*semVersion.Patch) - return "v" + majorVersion + "(?:\\." + minorVersion + "(?:\\." + patchVersion + ")?)?" -} - -// GetMinorVersionRangeRegex generates minor version compatible range regex for the given version -func GetMinorVersionRangeRegex(semVersion semantic_version.SemVersion) string { - if semVersion.Patch == nil { - return GetVersionMatchRegex(semVersion.Version) - } - majorVersion := strconv.Itoa(semVersion.Major) - minorVersion := strconv.Itoa(semVersion.Minor) - patchVersion := strconv.Itoa(*semVersion.Patch) - return "v" + majorVersion + "\\." + minorVersion + "(?:\\." + patchVersion + ")?" + return "v" + majorVersion + "(?:\\." + minorVersion + ")?" } // GetMajorVersionRange generates major version range for the given version @@ -59,11 +44,6 @@ func GetMajorVersionRange(semVersion semantic_version.SemVersion) string { return "v" + strconv.Itoa(semVersion.Major) } -// GetMinorVersionRange generates minor version range for the given version -func GetMinorVersionRange(semVersion semantic_version.SemVersion) string { - return "v" + strconv.Itoa(semVersion.Major) + "." + strconv.Itoa(semVersion.Minor) -} - func updateRoutingRulesOnAPIUpdate(organizationID, apiIdentifier, apiName, apiVersion, vHost string) { apiSemVersion, err := semantic_version.ValidateAndGetVersionComponents(apiVersion, apiName) // If the version validation is not success, we just proceed without intelligent version @@ -73,39 +53,28 @@ func updateRoutingRulesOnAPIUpdate(organizationID, apiIdentifier, apiName, apiVe } apiRangeIdentifier := GenerateIdentifierForAPIWithoutVersion(vHost, apiName) - // Check the major and minor version ranges of the current API + // Check the major version range of the current API existingMajorRangeLatestSemVersion, isMajorRangeRegexAvailable := orgIDLatestAPIVersionMap[organizationID][apiRangeIdentifier][GetMajorVersionRange(*apiSemVersion)] - existingMinorRangeLatestSemVersion, isMinorRangeRegexAvailable := - orgIDLatestAPIVersionMap[organizationID][apiRangeIdentifier][GetMinorVersionRange(*apiSemVersion)] - // Check whether the current API is the latest version in the major and minor version ranges + // Check whether the current API is the latest version in the major version range isLatestMajorVersion := !isMajorRangeRegexAvailable || existingMajorRangeLatestSemVersion.Compare(*apiSemVersion) - isLatestMinorVersion := !isMinorRangeRegexAvailable || existingMinorRangeLatestSemVersion.Compare(*apiSemVersion) - // Remove the existing regexes from the path specifier when latest major and/or minor version is available - if (isMajorRangeRegexAvailable || isMinorRangeRegexAvailable) && (isLatestMajorVersion || isLatestMinorVersion) { + // Remove the existing regexes from the path specifier when latest major version is available + if isMajorRangeRegexAvailable && isLatestMajorVersion { // Organization's all apis for apiUUID, swagger := range orgIDAPIMgwSwaggerMap[organizationID] { // API's all versions in the same vHost if swagger.GetTitle() == apiName && swagger.GetVHost() == vHost { - if (isMajorRangeRegexAvailable && swagger.GetVersion() == existingMajorRangeLatestSemVersion.Version) || - (isMinorRangeRegexAvailable && swagger.GetVersion() == existingMinorRangeLatestSemVersion.Version) { + if swagger.GetVersion() == existingMajorRangeLatestSemVersion.Version { for _, route := range orgIDOpenAPIRoutesMap[organizationID][apiUUID] { regex := route.GetMatch().GetSafeRegex().GetRegex() regexRewritePattern := route.GetRoute().GetRegexRewrite().GetPattern().GetRegex() - existingMinorRangeLatestVersionRegex := GetVersionMatchRegex(existingMinorRangeLatestSemVersion.Version) existingMajorRangeLatestVersionRegex := GetVersionMatchRegex(existingMajorRangeLatestSemVersion.Version) - if isMinorRangeRegexAvailable && swagger.GetVersion() == existingMinorRangeLatestSemVersion.Version && isLatestMinorVersion { - regex = strings.Replace(regex, GetMinorVersionRangeRegex(existingMinorRangeLatestSemVersion), existingMinorRangeLatestVersionRegex, 1) - regex = strings.Replace(regex, GetMajorMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), existingMajorRangeLatestVersionRegex, 1) - regexRewritePattern = strings.Replace(regexRewritePattern, GetMinorVersionRangeRegex(existingMinorRangeLatestSemVersion), existingMinorRangeLatestVersionRegex, 1) - regexRewritePattern = strings.Replace(regexRewritePattern, GetMajorMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), existingMajorRangeLatestVersionRegex, 1) - } - if isMajorRangeRegexAvailable && swagger.GetVersion() == existingMajorRangeLatestSemVersion.Version && isLatestMajorVersion { - regex = strings.Replace(regex, GetMajorMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), GetMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), 1) - regexRewritePattern = strings.Replace(regexRewritePattern, GetMajorMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), GetMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), 1) - } + + regex = strings.Replace(regex, GetMajorMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), existingMajorRangeLatestVersionRegex, 1) + regexRewritePattern = strings.Replace(regexRewritePattern, GetMajorMinorVersionRangeRegex(existingMajorRangeLatestSemVersion), existingMajorRangeLatestVersionRegex, 1) + pathSpecifier := &routev3.RouteMatch_SafeRegex{ SafeRegex: &envoy_type_matcherv3.RegexMatcher{ Regex: regex, @@ -121,10 +90,9 @@ func updateRoutingRulesOnAPIUpdate(organizationID, apiIdentifier, apiName, apiVe } } - if isLatestMajorVersion || isLatestMinorVersion { - // Update local memory map with the latest version ranges + if isLatestMajorVersion { + // Update local memory map with the latest version range majorVersionRange := GetMajorVersionRange(*apiSemVersion) - minorVersionRange := GetMinorVersionRange(*apiSemVersion) if _, orgExists := orgIDLatestAPIVersionMap[organizationID]; !orgExists { orgIDLatestAPIVersionMap[organizationID] = make(map[string]map[string]semantic_version.SemVersion) } @@ -132,24 +100,17 @@ func updateRoutingRulesOnAPIUpdate(organizationID, apiIdentifier, apiName, apiVe orgIDLatestAPIVersionMap[organizationID][apiRangeIdentifier] = make(map[string]semantic_version.SemVersion) } latestVersions := orgIDLatestAPIVersionMap[organizationID][apiRangeIdentifier] - latestVersions[minorVersionRange] = *apiSemVersion - if isLatestMajorVersion { - latestVersions[majorVersionRange] = *apiSemVersion - } + latestVersions[majorVersionRange] = *apiSemVersion - // Add the major and/or minor version range matching regexes to the path specifier when - // latest major and/or minor version is available + // Add the major version range matching regexes to the path specifier when latest major version is available for _, route := range orgIDOpenAPIRoutesMap[organizationID][apiIdentifier] { regex := route.GetMatch().GetSafeRegex().GetRegex() regexRewritePattern := route.GetRoute().GetRegexRewrite().GetPattern().GetRegex() apiVersionRegex := GetVersionMatchRegex(apiVersion) - if isLatestMajorVersion { - regex = strings.Replace(regex, apiVersionRegex, GetMajorMinorVersionRangeRegex(*apiSemVersion), 1) - regexRewritePattern = strings.Replace(regexRewritePattern, apiVersionRegex, GetMajorMinorVersionRangeRegex(*apiSemVersion), 1) - } else if isLatestMinorVersion { - regex = strings.Replace(regex, apiVersionRegex, GetMinorVersionRangeRegex(*apiSemVersion), 1) - regexRewritePattern = strings.Replace(regexRewritePattern, apiVersionRegex, GetMinorVersionRangeRegex(*apiSemVersion), 1) - } + + regex = strings.Replace(regex, apiVersionRegex, GetMajorMinorVersionRangeRegex(*apiSemVersion), 1) + regexRewritePattern = strings.Replace(regexRewritePattern, apiVersionRegex, GetMajorMinorVersionRangeRegex(*apiSemVersion), 1) + pathSpecifier := &routev3.RouteMatch_SafeRegex{ SafeRegex: &envoy_type_matcherv3.RegexMatcher{ Regex: regex, @@ -185,11 +146,10 @@ func updateRoutingRulesOnAPIDelete(organizationID, apiIdentifier string, api mgw Version: "", Major: deletingAPISemVersion.Major, Minor: 0, - Patch: nil, } for currentAPIIdentifier, swagger := range orgIDAPIMgwSwaggerMap[organizationID] { // Iterate all the API versions other than the deleting API itself - if swagger.GetTitle() == api.GetTitle() && currentAPIIdentifier != apiIdentifier { + if swagger.GetTitle() == api.GetTitle() && currentAPIIdentifier != apiIdentifier && swagger.GetVHost() == api.GetVHost() { currentAPISemVersion, _ := semantic_version.ValidateAndGetVersionComponents(swagger.GetVersion(), swagger.GetTitle()) if currentAPISemVersion != nil { if currentAPISemVersion.Major == deletingAPISemVersion.Major { @@ -207,19 +167,6 @@ func updateRoutingRulesOnAPIDelete(organizationID, apiIdentifier string, api mgw regex := route.GetMatch().GetSafeRegex().GetRegex() regexRewritePattern := route.GetRoute().GetRegexRewrite().GetPattern().GetRegex() newLatestMajorRangeAPIVersionRegex := GetVersionMatchRegex(newLatestMajorRangeAPI.Version) - // Remove any available minor version range regexes and apply the minor range regex - regex = strings.Replace( - regex, - GetMinorVersionRangeRegex(*newLatestMajorRangeAPI), - newLatestMajorRangeAPIVersionRegex, - 1, - ) - regexRewritePattern = strings.Replace( - regexRewritePattern, - GetMinorVersionRangeRegex(*newLatestMajorRangeAPI), - newLatestMajorRangeAPIVersionRegex, - 1, - ) regex = strings.Replace( regex, newLatestMajorRangeAPIVersionRegex, @@ -248,63 +195,4 @@ func updateRoutingRulesOnAPIDelete(organizationID, apiIdentifier string, api mgw } } } - minorVersionRange := GetMinorVersionRange(*deletingAPISemVersion) - if deletingAPIsMinorRangeLatestAPI, ok := latestAPIVersionMap[minorVersionRange]; ok { - if deletingAPIsMinorRangeLatestAPI.Version == api.GetVersion() { - newLatestMinorRangeAPI := &semantic_version.SemVersion{ - Version: "", - Major: deletingAPISemVersion.Major, - Minor: deletingAPISemVersion.Minor, - Patch: nil, - } - newLatestMinorRangeAPIIdentifier := "" - for currentAPIIdentifier, swagger := range orgIDAPIMgwSwaggerMap[organizationID] { - // Iterate all the API versions other than the deleting API itself - if swagger.GetTitle() == api.GetTitle() && currentAPIIdentifier != apiIdentifier { - currentAPISemVersion, _ := semantic_version.ValidateAndGetVersionComponents(swagger.GetVersion(), swagger.GetTitle()) - if currentAPISemVersion != nil { - if currentAPISemVersion.Major == deletingAPISemVersion.Major && - currentAPISemVersion.Minor == deletingAPISemVersion.Minor { - if newLatestMinorRangeAPI.Compare(*currentAPISemVersion) { - newLatestMinorRangeAPI = currentAPISemVersion - newLatestMinorRangeAPIIdentifier = currentAPIIdentifier - } - } - } - } - } - if newLatestMinorRangeAPIIdentifier != "" && newLatestMinorRangeAPIIdentifier != newLatestMajorRangeAPIIdentifier { - orgIDLatestAPIVersionMap[organizationID][apiRangeIdentifier][minorVersionRange] = *newLatestMinorRangeAPI - for _, route := range orgIDOpenAPIRoutesMap[organizationID][newLatestMinorRangeAPIIdentifier] { - regex := route.GetMatch().GetSafeRegex().GetRegex() - newLatestMinorRangeAPIVersionRegex := GetVersionMatchRegex(newLatestMinorRangeAPI.Version) - regex = strings.Replace( - regex, - newLatestMinorRangeAPIVersionRegex, - GetMinorVersionRangeRegex(*newLatestMinorRangeAPI), - 1, - ) - pathSpecifier := &routev3.RouteMatch_SafeRegex{ - SafeRegex: &envoy_type_matcherv3.RegexMatcher{ - Regex: regex, - }, - } - regexRewritePattern := route.GetRoute().GetRegexRewrite().GetPattern().GetRegex() - regexRewritePattern = strings.Replace( - regexRewritePattern, - newLatestMinorRangeAPIVersionRegex, - GetMinorVersionRangeRegex(*newLatestMinorRangeAPI), - 1, - ) - route.Match.PathSpecifier = pathSpecifier - action := &routev3.Route_Route{} - action = route.Action.(*routev3.Route_Route) - action.Route.RegexRewrite.Pattern.Regex = regexRewritePattern - route.Action = action - } - } else { - delete(orgIDLatestAPIVersionMap[organizationID][apiRangeIdentifier], minorVersionRange) - } - } - } } diff --git a/adapter/pkg/semanticversion/semantic_version.go b/adapter/pkg/semanticversion/semantic_version.go index 4d6016825e..e24aa69280 100644 --- a/adapter/pkg/semanticversion/semantic_version.go +++ b/adapter/pkg/semanticversion/semantic_version.go @@ -30,7 +30,6 @@ type SemVersion struct { Version string Major int Minor int - Patch *int } // ValidateAndGetVersionComponents validates version string and extracts version components @@ -65,20 +64,13 @@ func ValidateAndGetVersionComponents(version string, apiName string) (*SemVersio Version: version, Major: majorVersion, Minor: minorVersion, - Patch: nil, }, nil } - patchVersion, patchVersionConvErr := strconv.Atoi(versionComponents[2]) - if patchVersionConvErr != nil { - logger.LoggerSemanticVersion.Errorf(fmt.Sprintf("API patch version should be an integer in API: %v. API Version: %v", apiName, version), patchVersionConvErr) - return nil, errors.New("Invalid version format") - } return &SemVersion{ Version: version, Major: majorVersion, Minor: minorVersion, - Patch: &patchVersion, }, nil } @@ -94,18 +86,6 @@ func (baseVersion SemVersion) Compare(version SemVersion) bool { return true } else if baseVersion.Minor > version.Minor { return false - } else { - if baseVersion.Patch != nil && version.Patch != nil { - if *baseVersion.Patch < *version.Patch { - return true - } else if *baseVersion.Patch > *version.Patch { - return false - } - } else if baseVersion.Patch == nil && version.Patch != nil { - return true - } else if baseVersion.Patch != nil && version.Patch == nil { - return false - } } } return true