From f3ac1b8e2336f924faf6440a525855cd2c6bf1e5 Mon Sep 17 00:00:00 2001 From: Viraj Gamage Date: Mon, 4 Jul 2022 14:47:11 +0530 Subject: [PATCH 1/4] Improved handling blocked APIs by not invoking /apis endpoint unless it is the startup. The JMS/ASB event's details are used to populate the necessary maps(api-metadata) APIList object is not passed to the enforcer now, instead of that EnforcerAPI's lifecycle state is used. Any API within the api metadata map should be kept only if the API is a default API or API is in blocked state. If the API becomes unblocked, it is removed from the map. During the startup also only blocked and default versioned APIs are pulled. --- adapter/internal/discovery/xds/marshaller.go | 112 +++++++---------- adapter/internal/discovery/xds/server.go | 89 +++++++++++-- adapter/internal/eventhub/subscription.go | 82 ++++++------ adapter/internal/ga/api_event_listener.go | 20 --- .../messaging/notification_listener.go | 47 +------ .../internal/oasparser/config_generator.go | 4 +- .../internal/oasparser/model/mgw_swagger.go | 3 +- adapter/pkg/eventhub/types/types.go | 9 -- .../connect/enforcer/admin/AdminUtils.java | 41 ++++-- .../admin/handlers/APIRequestHandler.java | 39 +++--- .../handlers/ApplicationRequestHandler.java | 4 +- .../connect/enforcer/api/APIFactory.java | 28 +++++ .../choreo/connect/enforcer/models/API.java | 109 +--------------- .../connect/enforcer/models/URLMapping.java | 117 ------------------ .../enforcer/models/{ => admin}/APIInfo.java | 11 +- .../enforcer/models/{ => admin}/APIList.java | 8 +- .../models/{ => admin}/ApplicationInfo.java | 2 +- .../{ => admin}/ApplicationInfoList.java | 2 +- .../enforcer/models/admin/BasicAPIInfo.java | 107 ++++++++++++++++ .../models/{ => admin}/SubscriptionInfo.java | 2 +- .../enforcer/security/KeyValidator.java | 32 +---- .../subscription/SubscriptionDataStore.java | 19 --- .../SubscriptionDataStoreImpl.java | 68 ++-------- .../withapim/EnforcerAPITestCase.java | 84 ++++++------- .../withapim/PrototypedAPITestCase.java | 96 -------------- .../test/resources/testng-cc-with-apim.xml | 11 +- router/src/main/resources/Dockerfile | 1 + router/src/main/resources/Dockerfile.ubuntu | 1 + 28 files changed, 437 insertions(+), 711 deletions(-) delete mode 100644 enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/URLMapping.java rename enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/{ => admin}/APIInfo.java (92%) rename enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/{ => admin}/APIList.java (83%) rename enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/{ => admin}/ApplicationInfo.java (97%) rename enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/{ => admin}/ApplicationInfoList.java (95%) create mode 100644 enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/BasicAPIInfo.java rename enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/{ => admin}/SubscriptionInfo.java (97%) delete mode 100644 integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/PrototypedAPITestCase.java diff --git a/adapter/internal/discovery/xds/marshaller.go b/adapter/internal/discovery/xds/marshaller.go index df6841c434..f9b6b15896 100644 --- a/adapter/internal/discovery/xds/marshaller.go +++ b/adapter/internal/discovery/xds/marshaller.go @@ -3,7 +3,6 @@ package xds import ( "encoding/json" "fmt" - "strconv" "github.com/wso2/product-microgateway/adapter/config" logger "github.com/wso2/product-microgateway/adapter/internal/loggers" @@ -14,8 +13,8 @@ import ( ) var ( - // APIListMap has the following mapping label -> apiUUID -> API (Metadata) - APIListMap map[string]map[string]*subscription.APIs + // APIMetadataMap has the following mapping apiUUID -> API (Metadata) + APIMetadataMap map[string]*subscription.APIs // SubscriptionMap contains the subscriptions recieved from API Manager Control Plane SubscriptionMap map[int32]*subscription.Subscription // ApplicationMap contains the applications recieved from API Manager Control Plane @@ -40,8 +39,6 @@ const ( DeleteEvent ) -const blockedStatus string = "BLOCKED" - // MarshalConfig will marshal a Config struct - read from the config toml - to // enfocer's CDS resource representation. func MarshalConfig(config *config.Config) *enforcer.Config { @@ -480,20 +477,15 @@ func MarshalSubscriptionPolicyEventAndReturnList(policy *types.SubscriptionPolic return marshalSubscriptionPolicyMapToList(SubscriptionPolicyMap) } -// MarshalAPIMetataAndReturnList updates the internal APIListMap and returns the XDS compatible APIList. -// apiList is the internal APIList object (For single API, this would contain a List with just one API) +// UpdateAPIMetataMapWithMultipleAPIs updates the internal APIMetadataMap and it needs to be called during the startup. +// The purpose here is to store default versioned APIs and blocked APIs. // initialAPIUUIDListMap is assigned during startup when global adapter is associated. This would be empty otherwise. -// gatewayLabel is the environment. -func MarshalAPIMetataAndReturnList(apiList *types.APIList, initialAPIUUIDListMap map[string]int, gatewayLabel string) *subscription.APIList { +func UpdateAPIMetataMapWithMultipleAPIs(apiList *types.APIList, initialAPIUUIDListMap map[string]int) { - if APIListMap == nil { - APIListMap = make(map[string]map[string]*subscription.APIs) - } - // var resourceMapForLabel map[string]*subscription.APIs - if _, ok := APIListMap[gatewayLabel]; !ok { - APIListMap[gatewayLabel] = make(map[string]*subscription.APIs) + if APIMetadataMap == nil { + APIMetadataMap = make(map[string]*subscription.APIs) } - resourceMapForLabel := APIListMap[gatewayLabel] + for _, api := range apiList.List { // initialAPIUUIDListMap is not null if the adapter is running with global adapter enabled, and it is // the first method invocation. @@ -503,44 +495,44 @@ func MarshalAPIMetataAndReturnList(apiList *types.APIList, initialAPIUUIDListMap } } newAPI := marshalAPIMetadata(&api) - resourceMapForLabel[api.UUID] = newAPI - } - return marshalAPIListMapToList(resourceMapForLabel) -} - -// DeleteAPIAndReturnList removes the API from internal maps and returns the marshalled API List. -// If the apiUUID is not found in the internal map under the provided environment, then it would return a -// nil value. Hence it is required to check if the return value is nil, prior to updating the XDS cache. -func DeleteAPIAndReturnList(apiUUID, organizationUUID string, gatewayLabel string) *subscription.APIList { - if _, ok := APIListMap[gatewayLabel]; !ok { - logger.LoggerXds.Debugf("No API Metadata is available under gateway Environment : %s", gatewayLabel) - return nil + APIMetadataMap[api.UUID] = newAPI } - delete(APIListMap[gatewayLabel], apiUUID) - return marshalAPIListMapToList(APIListMap[gatewayLabel]) } -// MarshalAPIForLifeCycleChangeEventAndReturnList updates the internal map's API instances lifecycle state only if -// stored API Instance's or input status event is a blocked event. -// If no change is applied, it would return nil. Hence the XDS cache should not be updated. -func MarshalAPIForLifeCycleChangeEventAndReturnList(apiUUID, status, gatewayLabel string) *subscription.APIList { - if _, ok := APIListMap[gatewayLabel]; !ok { - logger.LoggerXds.Debugf("No API Metadata is available under gateway Environment : %s", gatewayLabel) - return nil - } - if _, ok := APIListMap[gatewayLabel][apiUUID]; !ok { - logger.LoggerXds.Debugf("No API Metadata for API ID: %s is available under gateway Environment : %s", - apiUUID, gatewayLabel) - return nil - } - storedAPILCState := APIListMap[gatewayLabel][apiUUID].LcState - - // Because the adapter only required to update the XDS if it is related to blocked state. - if !(storedAPILCState == blockedStatus || status == blockedStatus) { - return nil - } - APIListMap[gatewayLabel][apiUUID].LcState = status - return marshalAPIListMapToList(APIListMap[gatewayLabel]) +// UpdateAPIMetataMapWithAPILCEvent updates the internal map's API instances lifecycle state only if +// stored API Instance's or input status event is a blocked event. If the API's state is changed to un-BLOCKED state, +// the record will be removed. +func UpdateAPIMetataMapWithAPILCEvent(apiUUID, status string) { + + apiEntry, apiFound := APIMetadataMap[apiUUID] + if !apiFound { + // IF API is not stored within the metadata Map and the lifecycle state is something else other BLOCKED state, those are discarded. + if status != blockedStatus { + logger.LoggerXds.Debugf("API life cycle state change event is discarded for the API : %s", apiUUID) + return + } + // IF API is not available and state is BLOCKED, needs to create a new instance and store within the Map. + logger.LoggerXds.Debugf("No API Metadata for API ID: %s is available. Hence a new record is added.", apiUUID) + APIMetadataMap[apiUUID] = &subscription.APIs{ + Uuid: apiUUID, + LcState: status, + } + logger.LoggerXds.Infof("API life cycle state change event with state %q is updated for the API : %s", + status, apiUUID) + return + } + // If the API is available in the metadata map it should be either a BLOCKED API and/or default versioned API. + // If the update for existing API entry is not "BLOCKED" then the API can be removed from the list. + // when the API is unavailable in the api metadata list received in the enforcer, it would be treated as + // an unblocked API. + // But if the API is not the default version, those records won't be stored. + if status != blockedStatus && !apiEntry.IsDefaultVersion { + delete(APIMetadataMap, apiUUID) + return + } + APIMetadataMap[apiUUID].LcState = status + logger.LoggerXds.Infof("API life cycle state change event with state %q is updated for the API : %s", + status, apiUUID) } func marshalSubscription(subscriptionInternal *types.Subscription) *subscription.Subscription { @@ -599,13 +591,6 @@ func marshalKeyMapping(keyMappingInternal *types.ApplicationKeyMapping) *subscri func marshalAPIMetadata(api *types.API) *subscription.APIs { return &subscription.APIs{ - ApiId: strconv.Itoa(api.APIID), - Name: api.Name, - Provider: api.Provider, - Version: api.Version, - Context: api.Context, - Policy: api.Policy, - ApiType: api.APIType, Uuid: api.UUID, IsDefaultVersion: api.IsDefaultVersion, LcState: api.APIStatus, @@ -642,14 +627,3 @@ func marshalSubscriptionPolicy(policy *types.SubscriptionPolicy) *subscription.S func GetApplicationKeyMappingReference(keyMapping *types.ApplicationKeyMapping) string { return keyMapping.ConsumerKey + ":" + keyMapping.KeyManager } - -// CheckIfAPIMetadataIsAlreadyAvailable returns true only if the API Metadata for the given API UUID -// is already available -func CheckIfAPIMetadataIsAlreadyAvailable(apiUUID, label string) bool { - if _, labelAvailable := APIListMap[label]; labelAvailable { - if _, apiAvailale := APIListMap[label][apiUUID]; apiAvailale { - return true - } - } - return false -} diff --git a/adapter/internal/discovery/xds/server.go b/adapter/internal/discovery/xds/server.go index 432a174263..dbb58dfa24 100644 --- a/adapter/internal/discovery/xds/server.go +++ b/adapter/internal/discovery/xds/server.go @@ -45,6 +45,7 @@ import ( "github.com/wso2/product-microgateway/adapter/internal/oasparser/model" mgw "github.com/wso2/product-microgateway/adapter/internal/oasparser/model" "github.com/wso2/product-microgateway/adapter/internal/svcdiscovery" + "github.com/wso2/product-microgateway/adapter/pkg/discovery/api/wso2/discovery/api" subscription "github.com/wso2/product-microgateway/adapter/pkg/discovery/api/wso2/discovery/subscription" throttle "github.com/wso2/product-microgateway/adapter/pkg/discovery/api/wso2/discovery/throttle" wso2_cache "github.com/wso2/product-microgateway/adapter/pkg/discovery/protocol/cache/v3" @@ -83,7 +84,7 @@ var ( orgIDOpenAPIRoutesMap map[string]map[string][]*routev3.Route // organizationID -> Vhost:API_UUID -> Envoy Routes map orgIDOpenAPIClustersMap map[string]map[string][]*clusterv3.Cluster // organizationID -> Vhost:API_UUID -> Envoy Clusters map orgIDOpenAPIEndpointsMap map[string]map[string][]*corev3.Address // organizationID -> Vhost:API_UUID -> Envoy Endpoints map - orgIDOpenAPIEnforcerApisMap map[string]map[string]types.Resource // organizationID -> Vhost:API_UUID -> API Resource map + orgIDOpenAPIEnforcerApisMap map[string]map[string]*api.Api // organizationID -> Vhost:API_UUID -> API Resource map orgIDvHostBasepathMap map[string]map[string]string // organizationID -> Vhost:basepath -> Vhost:API_UUID reverseAPINameVersionMap map[string]string @@ -119,6 +120,8 @@ const ( maxRandomInt int = 999999999 prototypedAPI string = "PROTOTYPED" apiKeyFieldSeparator string = ":" + blockedStatus string = "BLOCKED" + nonBlockedStatus string = "CREATED/PUBLISHED" ) // IDHash uses ID field as the node hash. @@ -161,7 +164,7 @@ func init() { orgIDOpenAPIRoutesMap = make(map[string]map[string][]*routev3.Route) // organizationID -> Vhost:API_UUID -> Envoy Routes map orgIDOpenAPIClustersMap = make(map[string]map[string][]*clusterv3.Cluster) // organizationID -> Vhost:API_UUID -> Envoy Clusters map orgIDOpenAPIEndpointsMap = make(map[string]map[string][]*corev3.Address) // organizationID -> Vhost:API_UUID -> Envoy Endpoints map - orgIDOpenAPIEnforcerApisMap = make(map[string]map[string]types.Resource) // organizationID -> Vhost:API_UUID -> API Resource map + orgIDOpenAPIEnforcerApisMap = make(map[string]map[string]*api.Api) // organizationID -> Vhost:API_UUID -> API Resource map orgIDvHostBasepathMap = make(map[string]map[string]string) reverseAPINameVersionMap = make(map[string]string) @@ -334,6 +337,8 @@ func UpdateAPI(vHost string, apiProject mgw.ProjectAPI, environments []string) ( apiYaml.Name, apiYaml.Version, organizationID) return nil, validationErr } + // Update the LifecycleStatus of the API. + updateLCStateOfMgwSwagger(&mgwSwagger) // -------- Finished updating mgwSwagger struct @@ -434,12 +439,10 @@ func UpdateAPI(vHost string, apiProject mgw.ProjectAPI, environments []string) ( } if _, ok := orgIDOpenAPIEnforcerApisMap[organizationID]; ok { - orgIDOpenAPIEnforcerApisMap[organizationID][apiIdentifier] = oasParser.GetEnforcerAPI(mgwSwagger, - apiProject.APILifeCycleStatus, vHost) + orgIDOpenAPIEnforcerApisMap[organizationID][apiIdentifier] = oasParser.GetEnforcerAPI(mgwSwagger, vHost) } else { - enforcerAPIMap := make(map[string]types.Resource) - enforcerAPIMap[apiIdentifier] = oasParser.GetEnforcerAPI(mgwSwagger, apiProject.APILifeCycleStatus, - vHost) + enforcerAPIMap := make(map[string]*api.Api) + enforcerAPIMap[apiIdentifier] = oasParser.GetEnforcerAPI(mgwSwagger, vHost) orgIDOpenAPIEnforcerApisMap[organizationID] = enforcerAPIMap } @@ -447,8 +450,7 @@ func UpdateAPI(vHost string, apiProject mgw.ProjectAPI, environments []string) ( revisionStatus := updateXdsCacheOnAPIAdd(oldLabels, newLabels) if revisionStatus { // send updated revision to control plane - deployedRevision = notifier.UpdateDeployedRevisions(apiYaml.ID, apiYaml.RevisionID, environments, - vHost) + deployedRevision = notifier.UpdateDeployedRevisions(apiYaml.ID, apiYaml.RevisionID, environments, vHost) } if svcdiscovery.IsServiceDiscoveryEnabled { startConsulServiceDiscovery(organizationID) //consul service discovery starting point @@ -456,6 +458,41 @@ func UpdateAPI(vHost string, apiProject mgw.ProjectAPI, environments []string) ( return deployedRevision, nil } +// UpdateAPIInEnforcerForBlockedAPIUpdate updates the state of APIMetadataMap under apiID with the lifecycle state and then +// XDS cache for enforcerAPIs is updated. +func UpdateAPIInEnforcerForBlockedAPIUpdate(apiID, organizationID, state string) { + mutexForInternalMapUpdate.Lock() + defer mutexForInternalMapUpdate.Unlock() + // First needs to update the API Metadata Map + UpdateAPIMetataMapWithAPILCEvent(apiID, state) + var apiReferenceArray []string + // Iterate through the enforcerAPIsMap and update the lifecycle status for the map. This is the map representing + // runtime-artifact for each API + if openAPIEnforcerAPIsMap, orgFound := orgIDOpenAPIEnforcerApisMap[organizationID]; orgFound { + // The reference is vhost:apiUUID. Hence it is required to iterate through all API entries as there could be multiple deployments of the same API + // under different vhosts. + for apiReference, enforcerAPI := range openAPIEnforcerAPIsMap { + if strings.HasSuffix(apiReference, ":"+apiID) && (state == blockedStatus || enforcerAPI.ApiLifeCycleState == blockedStatus) { + logger.LoggerXds.Infof("API Lifecycle status is updated for the API %s to %s state", apiReference, state) + enforcerAPI.ApiLifeCycleState = state + apiReferenceArray = append(apiReferenceArray, apiReference) + } + } + } else { + logger.LoggerXds.Infof("API Life Cycle event is not applied due to irrelevant tenant domain : %s.", organizationID) + return + } + + // For all the gateway labels containing the API, the enforcer XDS cache needs to be updated. + if openAPIEnvoyLabelMap, ok := orgIDOpenAPIEnvoyMap[organizationID]; ok { + for _, apiReference := range apiReferenceArray { + if labels, labelsFound := openAPIEnvoyLabelMap[apiReference]; labelsFound { + updateXdsCacheForEnforcerAPIsOnly(labels) + } + } + } +} + // GetAllEnvironments returns all the environments merging new environments with already deployed environments // of the given vhost of the API func GetAllEnvironments(apiUUID, vhost string, newEnvironments []string) []string { @@ -782,6 +819,12 @@ func updateXdsCacheOnAPIAdd(oldLabels []string, newLabels []string) bool { return revisionStatus } +func updateXdsCacheForEnforcerAPIsOnly(labels []string) { + for _, label := range labels { + UpdateEnforcerApis(label, generateEnforcerAPIsForLabel(label), "") + } +} + // GenerateEnvoyResoucesForLabel generates envoy resources for a given label // This method will list out all APIs mapped to the label. and generate envoy resources for all of these APIs. func GenerateEnvoyResoucesForLabel(label string) ([]types.Resource, []types.Resource, []types.Resource, @@ -850,6 +893,24 @@ func GenerateEnvoyResoucesForLabel(label string) ([]types.Resource, []types.Reso return endpoints, clusters, listeners, routeConfigs, apis } +// generateEnforcerAPIsForLabel generates ebforcerAPIs resource array for a given label. +// This is used when the envoy resources are not required to have changes but the enforcer APIs are required to (Blocked State APIs) +func generateEnforcerAPIsForLabel(label string) []types.Resource { + var apis []types.Resource + + for organizationID, entityMap := range orgIDOpenAPIEnvoyMap { + for apiKey, labels := range entityMap { + if arrayContains(labels, label) { + enforcerAPI, ok := orgIDOpenAPIEnforcerApisMap[organizationID][apiKey] + if ok { + apis = append(apis, enforcerAPI) + } + } + } + } + return apis +} + // GenerateGlobalClusters generates the globally available clusters and endpoints. func GenerateGlobalClusters(label string) { clusters, endpoints := oasParser.GetGlobalClusters() @@ -1239,3 +1300,13 @@ func UpdateEnforcerThrottleData(throttleData *throttle.ThrottleData) { enforcerThrottleData = t logger.LoggerXds.Infof("New Throttle Data cache update for the label: " + label + " version: " + fmt.Sprint(version)) } + +func updateLCStateOfMgwSwagger(mgwSwagger *model.MgwSwagger) { + // If there are any metadata stored under the APIMetadataMap and Life Cycle state is blocked, update the mgwSwagger + apiEntry, apiFound := APIMetadataMap[mgwSwagger.GetID()] + if apiFound && apiEntry.LcState == blockedStatus { + mgwSwagger.LifeCycleState = blockedStatus + return + } + mgwSwagger.LifeCycleState = nonBlockedStatus +} diff --git a/adapter/internal/eventhub/subscription.go b/adapter/internal/eventhub/subscription.go index 6811a9627a..86e517befc 100644 --- a/adapter/internal/eventhub/subscription.go +++ b/adapter/internal/eventhub/subscription.go @@ -48,6 +48,8 @@ const ( VersionParam string = "version" // GatewayLabelParam is trequired to call /apis endpoint GatewayLabelParam string = "gatewayLabel" + // ExpandParam is a specific query parameter to pull blocked APIs and default apis (for that the value should be false). + ExpandParam string = "expand" // APIUUIDParam is required to call /apis endpoint APIUUIDParam string = "apiId" // ApisEndpoint is the resource path of /apis endpoint @@ -146,49 +148,45 @@ func LoadSubscriptionData(configFile *config.Config, initialAPIUUIDListMap map[s } } - // TODO: (VirajSalaka) Calling /apis endpoint is temporarily removed. - // Take the configured labels from the adapter - // configuredEnvs := conf.ControlPlane.EnvironmentLabels + configuredEnvs := conf.ControlPlane.EnvironmentLabels // If no environments are configured, default gateway label value is assigned. - // if len(configuredEnvs) == 0 { - // configuredEnvs = append(configuredEnvs, config.DefaultGatewayName) - // } - // for _, configuredEnv := range configuredEnvs { - // queryParamMap := make(map[string]string, 1) - // queryParamMap[GatewayLabelParam] = configuredEnv - // go InvokeService(ApisEndpoint, apiList, queryParamMap, APIListChannel, 0) - // for { - // data := <-APIListChannel - // logger.LoggerSync.Debug("Receiving API information for an environment") - // if data.Payload != nil { - // logger.LoggerSync.Info("Payload data with API information recieved") - // retrieveAPIList(data, initialAPIUUIDListMap) - // break - // } else if data.ErrorCode >= 400 && data.ErrorCode < 500 { - // logger.LoggerSync.Errorf("Error occurred when retrieving Subscription information from the control plane: %v", data.Error) - // health.SetControlPlaneRestAPIStatus(false) - // } else { - // // Keep the iteration going on until a response is recieved. - // logger.LoggerSync.Errorf("Error occurred while fetching data from control plane: %v", data.Error) - // go func(d response) { - // // Retry fetching from control plane after a configured time interval - // if conf.ControlPlane.RetryInterval == 0 { - // // Assign default retry interval - // conf.ControlPlane.RetryInterval = 5 - // } - // logger.LoggerSync.Debugf("Time Duration for retrying: %v", conf.ControlPlane.RetryInterval*time.Second) - // time.Sleep(conf.ControlPlane.RetryInterval * time.Second) - // logger.LoggerSync.Infof("Retrying to fetch APIs from control plane. Time Duration for the next retry: %v", conf.ControlPlane.RetryInterval*time.Second) - // go InvokeService(ApisEndpoint, apiList, queryParamMap, APIListChannel, 0) - // }(data) - // } - // } - // } - // TODO: (VirajSalaka) APIList (/apis response) processing is temporarily blocked. - // // InitialAPIUUIDList is already processed (if available). Then onwards, that list is not required. - // go retrieveAPIListFromChannel(APIListChannel, nil) + if len(configuredEnvs) == 0 { + configuredEnvs = append(configuredEnvs, config.DefaultGatewayName) + } + for _, configuredEnv := range configuredEnvs { + queryParamMap := make(map[string]string, 1) + queryParamMap[GatewayLabelParam] = configuredEnv + queryParamMap[ExpandParam] = "false" + go InvokeService(ApisEndpoint, apiList, queryParamMap, APIListChannel, 0) + for { + data := <-APIListChannel + logger.LoggerSync.Debug("Receiving API information for an environment") + if data.Payload != nil { + logger.LoggerSync.Info("Payload data with API information recieved") + retrieveAPIList(data, initialAPIUUIDListMap) + break + } else if data.ErrorCode >= 400 && data.ErrorCode < 500 { + logger.LoggerSync.Errorf("Error occurred when retrieving Subscription information from the control plane: %v", data.Error) + health.SetControlPlaneRestAPIStatus(false) + } else { + // Keep the iteration going on until a response is recieved. + logger.LoggerSync.Errorf("Error occurred while fetching data from control plane: %v", data.Error) + go func(d response) { + // Retry fetching from control plane after a configured time interval + if conf.ControlPlane.RetryInterval == 0 { + // Assign default retry interval + conf.ControlPlane.RetryInterval = 5 + } + logger.LoggerSync.Debugf("Time Duration for retrying: %v", conf.ControlPlane.RetryInterval*time.Second) + time.Sleep(conf.ControlPlane.RetryInterval * time.Second) + logger.LoggerSync.Infof("Retrying to fetch APIs from control plane. Time Duration for the next retry: %v", conf.ControlPlane.RetryInterval*time.Second) + InvokeService(ApisEndpoint, apiList, queryParamMap, APIListChannel, 0) + }(data) + } + } + } } // InvokeService invokes the internal data resource @@ -279,9 +277,7 @@ func retrieveAPIList(response response, initialAPIUUIDListMap map[string]int) { logger.LoggerSubscription.Debugf("Received API List information for API : %s", api.UUID) } } - - xds.UpdateEnforcerAPIList(response.GatewayLabel, - xds.MarshalAPIMetataAndReturnList(apiListResponse, initialAPIUUIDListMap, response.GatewayLabel)) + xds.UpdateAPIMetataMapWithMultipleAPIs(apiListResponse, initialAPIUUIDListMap) default: logger.LoggerSubscription.Warnf("APIList Type DTO is not recieved. Unknown type %T", t) } diff --git a/adapter/internal/ga/api_event_listener.go b/adapter/internal/ga/api_event_listener.go index 2759fb8afd..f4e42eda77 100644 --- a/adapter/internal/ga/api_event_listener.go +++ b/adapter/internal/ga/api_event_listener.go @@ -35,29 +35,9 @@ func handleAPIEventsFromGA(channel chan APIEvent) { } if !event.IsDeployEvent { xds.DeleteAPIWithAPIMEvent(event.APIUUID, event.OrganizationUUID, configuredEnvs, event.RevisionUUID) - // TODO: (VirajSalaka) Temporarily removed. - // for _, env := range configuredEnvs { - // xds.DeleteAPIAndReturnList(event.APIUUID, event.OrganizationUUID, env) - // } continue } go synchronizer.FetchAPIsFromControlPlane(event.APIUUID, configuredEnvs) - - // TODO: (VirajSalaka) temporarily removed. - // for _, env := range configuredEnvs { - // if xds.CheckIfAPIMetadataIsAlreadyAvailable(event.APIUUID, env) { - // logger.LoggerGA.Debugf("APIList for API UUID: %s is not updated as it already "+ - // "exists", event.APIUUID) - // continue - // } - // queryParamMap := make(map[string]string, 2) - // queryParamMap[eh.GatewayLabelParam] = env - // queryParamMap[eh.APIUUIDParam] = event.APIUUID - // logger.LoggerGA.Infof("Invoking the apis service endpoint") - // var apiList *types.APIList - // go eh.InvokeService(eh.ApisEndpoint, apiList, queryParamMap, - // eh.APIListChannel, 0) - // } } } diff --git a/adapter/internal/messaging/notification_listener.go b/adapter/internal/messaging/notification_listener.go index a874b502a1..a98411bd76 100644 --- a/adapter/internal/messaging/notification_listener.go +++ b/adapter/internal/messaging/notification_listener.go @@ -171,42 +171,13 @@ func handleAPIEvents(data []byte, eventType string) { // to delete. Hence we could simply delete after checking against just one iteration. if strings.EqualFold(removeAPIFromGateway, apiEvent.Event.Type) { xds.DeleteAPIWithAPIMEvent(apiEvent.UUID, apiEvent.TenantDomain, apiEvent.GatewayLabels, "") - // TODO: (VirajSalaka) Temporarily Removed. - // for _, env := range apiEvent.GatewayLabels { - // xdsAPIList := xds.DeleteAPIAndReturnList(apiEvent.UUID, apiEvent.TenantDomain, env) - // if xdsAPIList != nil { - // xds.UpdateEnforcerAPIList(env, xdsAPIList) - // } - // } return } - // TODO: (VirajSalaka) Temporarily removed. - // if strings.EqualFold(deployAPIToGateway, apiEvent.Event.Type) { - // conf, _ := config.ReadConfigs() - // configuredEnvs := conf.ControlPlane.EnvironmentLabels - // if len(configuredEnvs) == 0 { - // configuredEnvs = append(configuredEnvs, config.DefaultGatewayName) - // } - // for _, configuredEnv := range configuredEnvs { - // if configuredEnv == env { - // if xds.CheckIfAPIMetadataIsAlreadyAvailable(apiEvent.UUID, env) { - // logger.LoggerInternalMsg.Debugf("API Metadata for api Id: %s is not updated as it already exists", apiEvent.UUID) - // continue - // } - // queryParamMap := make(map[string]string, 3) - // queryParamMap[eh.GatewayLabelParam] = configuredEnv - // queryParamMap[eh.ContextParam] = apiEvent.Context - // queryParamMap[eh.VersionParam] = apiEvent.Version - // var apiList *types.APIList - // go eh.InvokeService(eh.ApisEndpoint, apiList, queryParamMap, - // eh.APIListChannel, 0) - // } - // } - // } } } func handleLifeCycleEvents(data []byte) { + // TODO: (VirajSalaka) IsLaterEvent var apiEvent msg.APIEvent apiLCEventErr := json.Unmarshal([]byte(string(data)), &apiEvent) if apiLCEventErr != nil { @@ -218,20 +189,8 @@ func handleLifeCycleEvents(data []byte) { apiEvent.APIName, apiEvent.APIVersion, apiEvent.TenantDomain) return } - // conf, _ := config.ReadConfigs() - // configuredEnvs := conf.ControlPlane.EnvironmentLabels - logger.LoggerInternalMsg.Debugf("%s : %s API life cycle state change event is discarded", apiEvent.APIName, apiEvent.APIVersion) - - // TODO: (VirajSalaka) Temporarily removed as API Blocked LC state change is ignored atm. - // if len(configuredEnvs) == 0 { - // configuredEnvs = append(configuredEnvs, config.DefaultGatewayName) - // } - // for _, configuredEnv := range configuredEnvs { - // xdsAPIList := xds.MarshalAPIForLifeCycleChangeEventAndReturnList(apiEvent.UUID, apiEvent.APIStatus, configuredEnv) - // if xdsAPIList != nil { - // xds.UpdateEnforcerAPIList(configuredEnv, xdsAPIList) - // } - // } + // TODO: (VirajSalaka) Unnecessary Tenants' API Metadata are also stored. + xds.UpdateAPIInEnforcerForBlockedAPIUpdate(apiEvent.UUID, apiEvent.TenantDomain, apiEvent.APIStatus) } // handleApplicationEvents to process application related events diff --git a/adapter/internal/oasparser/config_generator.go b/adapter/internal/oasparser/config_generator.go index be6d176209..a633740ba6 100644 --- a/adapter/internal/oasparser/config_generator.go +++ b/adapter/internal/oasparser/config_generator.go @@ -116,7 +116,7 @@ func UpdateRoutesConfig(routeConfig *routev3.RouteConfiguration, vhostToRouteArr // GetEnforcerAPI retrieves the ApiDS object model for a given swagger definition // along with the vhost to deploy the API. -func GetEnforcerAPI(mgwSwagger model.MgwSwagger, lifeCycleState string, vhost string) *api.Api { +func GetEnforcerAPI(mgwSwagger model.MgwSwagger, vhost string) *api.Api { resources := []*api.Resource{} securitySchemes := []*api.SecurityScheme{} securityList := []*api.SecurityList{} @@ -196,7 +196,7 @@ func GetEnforcerAPI(mgwSwagger model.MgwSwagger, lifeCycleState string, vhost st ProductionEndpoints: generateRPCEndpointCluster(mgwSwagger.GetProdEndpoints()), SandboxEndpoints: generateRPCEndpointCluster(mgwSwagger.GetSandEndpoints()), Resources: resources, - ApiLifeCycleState: lifeCycleState, + ApiLifeCycleState: mgwSwagger.LifeCycleState, Tier: mgwSwagger.GetXWso2ThrottlingTier(), SecurityScheme: securitySchemes, Security: securityList, diff --git a/adapter/internal/oasparser/model/mgw_swagger.go b/adapter/internal/oasparser/model/mgw_swagger.go index ae0fc36367..4ac5aba73e 100644 --- a/adapter/internal/oasparser/model/mgw_swagger.go +++ b/adapter/internal/oasparser/model/mgw_swagger.go @@ -63,7 +63,8 @@ type MgwSwagger struct { OrganizationID string IsProtoTyped bool // APIProvider is required for analytics purposes as /apis call is avoided temporarily. - APIProvider string + APIProvider string + LifeCycleState string } // EndpointCluster represent an upstream cluster diff --git a/adapter/pkg/eventhub/types/types.go b/adapter/pkg/eventhub/types/types.go index eddc4317a3..47c97bbbb0 100644 --- a/adapter/pkg/eventhub/types/types.go +++ b/adapter/pkg/eventhub/types/types.go @@ -76,18 +76,9 @@ type ApplicationKeyMappingList struct { // API for struct Api type API struct { - APIID int `json:"apiId"` UUID string `json:"uuid"` - Provider string `json:"provider" json:"apiProvider"` - Name string `json:"name" json:"apiName"` - Version string `json:"version" json:"apiVersion"` - Context string `json:"context" json:"apiContext"` - Policy string `json:"policy"` - APIType string `json:"apiType"` IsDefaultVersion bool `json:"isDefaultVersion"` APIStatus string `json:"status"` - TenantID int32 `json:"tenanId,omitempty"` - TenantDomain string `json:"tenanDomain,omitempty"` TimeStamp int64 `json:"timeStamp,omitempty"` } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java index dd127257d9..d861d4fc14 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java @@ -20,11 +20,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.grpc.netty.shaded.io.netty.handler.codec.http.HttpResponseStatus; -import org.wso2.choreo.connect.enforcer.models.API; -import org.wso2.choreo.connect.enforcer.models.APIInfo; +import org.wso2.choreo.connect.enforcer.api.API; import org.wso2.choreo.connect.enforcer.models.Application; -import org.wso2.choreo.connect.enforcer.models.ApplicationInfo; -import org.wso2.choreo.connect.enforcer.models.ApplicationInfoList; import org.wso2.choreo.connect.enforcer.models.ApplicationKeyMapping; import org.wso2.choreo.connect.enforcer.models.ApplicationPolicy; import org.wso2.choreo.connect.enforcer.models.ApplicationPolicyList; @@ -32,10 +29,14 @@ import org.wso2.choreo.connect.enforcer.models.RevokedToken; import org.wso2.choreo.connect.enforcer.models.RevokedTokenList; import org.wso2.choreo.connect.enforcer.models.Subscription; -import org.wso2.choreo.connect.enforcer.models.SubscriptionInfo; import org.wso2.choreo.connect.enforcer.models.SubscriptionList; import org.wso2.choreo.connect.enforcer.models.SubscriptionPolicy; import org.wso2.choreo.connect.enforcer.models.SubscriptionPolicyList; +import org.wso2.choreo.connect.enforcer.models.admin.APIInfo; +import org.wso2.choreo.connect.enforcer.models.admin.ApplicationInfo; +import org.wso2.choreo.connect.enforcer.models.admin.ApplicationInfoList; +import org.wso2.choreo.connect.enforcer.models.admin.BasicAPIInfo; +import org.wso2.choreo.connect.enforcer.models.admin.SubscriptionInfo; import java.util.List; @@ -47,14 +48,28 @@ public class AdminUtils { public static APIInfo toAPIInfo(API api, List subscriptionInfoList) { APIInfo apiInfo = new APIInfo(); apiInfo.setSubscriptions(subscriptionInfoList); - apiInfo.setApiId(api.getApiId()); - apiInfo.setApiUUID(api.getApiUUID()); - apiInfo.setContext(api.getContext()); - apiInfo.setName(api.getApiName()); - apiInfo.setLcState(api.getLcState()); - apiInfo.setTier(api.getApiTier()); - apiInfo.setVersion(api.getApiVersion()); - apiInfo.setProvider(api.getApiProvider()); + apiInfo.setApiUUID(api.getAPIConfig().getUuid()); + apiInfo.setContext(api.getAPIConfig().getBasePath()); + apiInfo.setName(api.getAPIConfig().getName()); + apiInfo.setLcState(api.getAPIConfig().getApiLifeCycleState()); + apiInfo.setTier(api.getAPIConfig().getTier()); + apiInfo.setVersion(api.getAPIConfig().getVersion()); + apiInfo.setProvider(api.getAPIConfig().getApiProvider()); + apiInfo.setApiType(api.getAPIConfig().getApiType()); + return apiInfo; + } + + public static BasicAPIInfo toBasicAPIInfo(API api, boolean isDefaultVersion) { + BasicAPIInfo apiInfo = new BasicAPIInfo(); + apiInfo.setApiUUID(api.getAPIConfig().getUuid()); + apiInfo.setContext(api.getAPIConfig().getBasePath()); + apiInfo.setName(api.getAPIConfig().getName()); + apiInfo.setLcState(api.getAPIConfig().getApiLifeCycleState()); + apiInfo.setDefaultVersion(isDefaultVersion); + apiInfo.setApiType(api.getAPIConfig().getApiType()); + apiInfo.setVersion(api.getAPIConfig().getVersion()); + apiInfo.setProvider(api.getAPIConfig().getApiProvider()); + apiInfo.setPolicy(api.getAPIConfig().getTier()); return apiInfo; } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java index 66a09e9532..8a23616c7d 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java @@ -20,16 +20,18 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.grpc.netty.shaded.io.netty.handler.codec.http.HttpResponseStatus; import org.wso2.choreo.connect.enforcer.admin.AdminUtils; +import org.wso2.choreo.connect.enforcer.api.API; +import org.wso2.choreo.connect.enforcer.api.APIFactory; import org.wso2.choreo.connect.enforcer.constants.AdminConstants; -import org.wso2.choreo.connect.enforcer.models.API; -import org.wso2.choreo.connect.enforcer.models.APIInfo; -import org.wso2.choreo.connect.enforcer.models.APIList; import org.wso2.choreo.connect.enforcer.models.Application; -import org.wso2.choreo.connect.enforcer.models.ApplicationInfo; import org.wso2.choreo.connect.enforcer.models.ApplicationKeyMapping; import org.wso2.choreo.connect.enforcer.models.ResponsePayload; import org.wso2.choreo.connect.enforcer.models.Subscription; -import org.wso2.choreo.connect.enforcer.models.SubscriptionInfo; +import org.wso2.choreo.connect.enforcer.models.admin.APIInfo; +import org.wso2.choreo.connect.enforcer.models.admin.APIList; +import org.wso2.choreo.connect.enforcer.models.admin.ApplicationInfo; +import org.wso2.choreo.connect.enforcer.models.admin.BasicAPIInfo; +import org.wso2.choreo.connect.enforcer.models.admin.SubscriptionInfo; import java.util.ArrayList; import java.util.List; @@ -44,9 +46,8 @@ public ResponsePayload handleRequest(String[] params, String requestType) throws if (AdminConstants.API_TYPE.equals(requestType)) { return getAPIs(params); - } else { - return getAPIInfo(params); } + return getAPIInfo(params); } /** @@ -54,7 +55,7 @@ public ResponsePayload handleRequest(String[] params, String requestType) throws * * @param params Array of parameters * @return ResponsePayload with APIs as APIList object. - * */ + */ private ResponsePayload getAPIs(String[] params) throws JsonProcessingException { List apis; String name = null; @@ -82,10 +83,15 @@ private ResponsePayload getAPIs(String[] params) throws JsonProcessingException } } } - apis = super.dataStore.getMatchingAPIs(name, context, version, uuid); + apis = APIFactory.getInstance().getMatchingAPIs(name, context, version, uuid); APIList apiList = new APIList(); apiList.setCount(apis.size()); - apiList.setList(apis); + List modelAPIs = new ArrayList<>(apis.size()); + for (API api : apis) { + // TODO: (VirajSalaka) fix + modelAPIs.add(AdminUtils.toBasicAPIInfo(api, false)); + } + apiList.setList(modelAPIs); return AdminUtils.buildResponsePayload(apiList, HttpResponseStatus.OK, false); } @@ -96,7 +102,7 @@ private ResponsePayload getAPIs(String[] params) throws JsonProcessingException * * @param params API Context and API version * @return APIInfo in as a ResponsePayload object. - * @throws JsonProcessingException + * @throws JsonProcessingException If the object cannot be converted into a JSON */ private ResponsePayload getAPIInfo(String[] params) throws JsonProcessingException { APIInfo apiInfo; @@ -117,10 +123,12 @@ private ResponsePayload getAPIInfo(String[] params) throws JsonProcessingExcepti version = param.split("=")[1]; } } - API matchingAPI = super.dataStore.getMatchingAPI(context, version); - if (matchingAPI != null) { + List apis = APIFactory.getInstance().getMatchingAPIs(null, context, version, null); + String apiUUID; + if (apis.size() > 0) { + apiUUID = apis.get(0).getAPIConfig().getUuid(); List matchingSubscriptions = dataStore. - getMatchingSubscriptions(null, matchingAPI.getApiUUID(), null); + getMatchingSubscriptions(null, apiUUID, null); List subscriptionInfoList = new ArrayList<>(); // For each subscription, build the Subscription info with application and key mapping. for (Subscription subscription : matchingSubscriptions) { @@ -138,7 +146,8 @@ private ResponsePayload getAPIInfo(String[] params) throws JsonProcessingExcepti SubscriptionInfo subscriptionInfo = AdminUtils.toSubscriptionInfo(subscription, applicationInfo); subscriptionInfoList.add(subscriptionInfo); } - apiInfo = AdminUtils.toAPIInfo(matchingAPI, subscriptionInfoList); + + apiInfo = AdminUtils.toAPIInfo(apis.get(0), subscriptionInfoList); return AdminUtils.buildResponsePayload(apiInfo, HttpResponseStatus.OK, false); } else { // No api found for the provided search parameters... diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/ApplicationRequestHandler.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/ApplicationRequestHandler.java index 88e7502b46..87e38ac308 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/ApplicationRequestHandler.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/ApplicationRequestHandler.java @@ -22,10 +22,10 @@ import org.wso2.choreo.connect.enforcer.admin.AdminUtils; import org.wso2.choreo.connect.enforcer.constants.AdminConstants; import org.wso2.choreo.connect.enforcer.models.Application; -import org.wso2.choreo.connect.enforcer.models.ApplicationInfo; -import org.wso2.choreo.connect.enforcer.models.ApplicationInfoList; import org.wso2.choreo.connect.enforcer.models.ApplicationKeyMapping; import org.wso2.choreo.connect.enforcer.models.ResponsePayload; +import org.wso2.choreo.connect.enforcer.models.admin.ApplicationInfo; +import org.wso2.choreo.connect.enforcer.models.admin.ApplicationInfoList; import java.util.ArrayList; import java.util.List; diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/api/APIFactory.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/api/APIFactory.java index b762eba204..91dc0bfd97 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/api/APIFactory.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/api/APIFactory.java @@ -18,6 +18,7 @@ package org.wso2.choreo.connect.enforcer.api; import io.envoyproxy.envoy.service.auth.v3.CheckRequest; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.wso2.choreo.connect.discovery.api.Api; @@ -27,6 +28,7 @@ import org.wso2.choreo.connect.enforcer.constants.APIConstants; import org.wso2.choreo.connect.enforcer.discovery.ApiDiscoveryClient; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -143,4 +145,30 @@ private String getApiKey(API api) { private String getApiKey(String vhost, String basePath, String version) { return String.format("%s:%s:%s", vhost, basePath, version); } + + public List getMatchingAPIs (String name, String context, String version, String uuid) { + List apiList = new ArrayList<>(); + for (API api : apis.values()) { + boolean isNameMatching = true; + boolean isContextMatching = true; + boolean isVersionMatching = true; + boolean isUUIDMatching = true; + if (StringUtils.isNotEmpty(name)) { + isNameMatching = api.getAPIConfig().getName().contains(name); + } + if (StringUtils.isNotEmpty(context)) { + isContextMatching = api.getAPIConfig().getBasePath().equals(context); + } + if (StringUtils.isNotEmpty(version)) { + isVersionMatching = api.getAPIConfig().getVersion().equals(version); + } + if (StringUtils.isNotEmpty(uuid)) { + isUUIDMatching = api.getAPIConfig().getUuid().equals(uuid); + } + if (isNameMatching && isContextMatching && isVersionMatching && isUUIDMatching) { + apiList.add(api); + } + } + return apiList; + } } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java index 2c6a098e7d..cad7b0e937 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java @@ -20,117 +20,20 @@ import org.wso2.choreo.connect.enforcer.common.CacheableEntity; -import java.util.ArrayList; -import java.util.List; - /** * Entity for keeping API related information. */ public class API implements CacheableEntity { - private Integer apiId = null; - private String provider = null; - private String name = null; - private String version = null; - private String context = null; - private String policy = null; - private String apiType = null; private boolean isDefaultVersion = false; private String apiUUID = null; private String lcState = null; - private List urlMappings = new ArrayList<>(); - - - public void addResource(URLMapping resource) { - - urlMappings.add(resource); - } - - public List getResources() { - - return urlMappings; - } - - public void removeResource(URLMapping resource) { - urlMappings.remove(resource); - } - - public String getContext() { - - return context; - } - - public void setContext(String context) { - - this.context = context; - } - - public String getApiTier() { - - return policy; - } - - public void setApiTier(String apiTier) { - - this.policy = apiTier; - } - - public int getApiId() { - - return apiId; - } - - public void setApiId(int apiId) { - - this.apiId = apiId; - } - - public String getApiProvider() { - - return provider; - } - - public void setApiProvider(String apiProvider) { - - this.provider = apiProvider; - } - - public String getApiName() { - - return name; - } - - public void setApiName(String apiName) { - - this.name = apiName; - } - - public String getApiVersion() { - - return version; - } - - public void setApiVersion(String apiVersion) { - - this.version = apiVersion; - } - public String getCacheKey() { return apiUUID; } - public String getApiType() { - - return apiType; - } - - public void setApiType(String apiType) { - - this.apiType = apiType; - } - public String getLcState() { return lcState; } @@ -139,12 +42,12 @@ public void setLcState(String lcState) { this.lcState = lcState; } - @Override - public String toString() { - return "API [apiId=" + apiId + ", provider=" + provider + ", name=" + name + ", version=" + version - + ", context=" + context + ", policy=" + policy + ", apiType=" + apiType + ", urlMappings=" - + urlMappings + "]"; - } + // TODO: (VirajSalaka) +// @Override +// public String toString() { +// return "API [apiId=" + apiId + ", provider=" + provider + ", name=" + name + ", version=" + version +// + ", context=" + context + ", policy=" + policy + ", apiType=" + apiType + "]"; +// } public boolean isDefaultVersion() { return isDefaultVersion; diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/URLMapping.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/URLMapping.java deleted file mode 100644 index 3736110e0d..0000000000 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/URLMapping.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.choreo.connect.enforcer.models; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * Holds details about url mapping of API resources. - */ -public class URLMapping { - - private String throttlingPolicy; - private String authScheme; - private String httpMethod; - private String urlPattern; - private List scopes = new ArrayList<>(); - - - public String getHttpMethod() { - - return httpMethod; - } - - public void setHttpMethod(String httpMethod) { - - this.httpMethod = httpMethod; - } - - public String getThrottlingPolicy() { - - return throttlingPolicy; - } - - public void setThrottlingPolicy(String throttlingPolicy) { - - this.throttlingPolicy = throttlingPolicy; - } - - public String getAuthScheme() { - - return authScheme; - } - - public void setAuthScheme(String authScheme) { - - this.authScheme = authScheme; - } - - public String getUrlPattern() { - - return urlPattern; - } - - public void setUrlPattern(String urlPattern) { - - this.urlPattern = urlPattern; - } - - public void addScope(String scope) { - scopes.add(scope); - } - - public List getScopes() { - return scopes; - } - - @Override - public boolean equals(Object o) { - - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - URLMapping that = (URLMapping) o; - return Objects.equals(throttlingPolicy, that.throttlingPolicy) && - Objects.equals(authScheme, that.authScheme) && - Objects.equals(httpMethod, that.httpMethod) && - Objects.equals(urlPattern, that.urlPattern); - } - - @Override - public int hashCode() { - - return Objects.hash(throttlingPolicy, authScheme, httpMethod, urlPattern); - } - - @Override - public String toString() { - - return "URLMapping {" + - ", throttlingPolicy ='" + throttlingPolicy + '\'' + - ", authScheme ='" + authScheme + '\'' + - ", httpMethod ='" + httpMethod + '\'' + - ", urlPattern ='" + urlPattern + '\'' + - '}'; - } -} diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/APIInfo.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIInfo.java similarity index 92% rename from enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/APIInfo.java rename to enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIInfo.java index 7824b15e43..c92de2ce7e 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/APIInfo.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIInfo.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.choreo.connect.enforcer.models; +package org.wso2.choreo.connect.enforcer.models.admin; import java.util.List; @@ -23,7 +23,6 @@ * Model class for API Information */ public class APIInfo { - private Integer apiId = null; private String provider = null; private String name = null; private String version = null; @@ -35,14 +34,6 @@ public class APIInfo { private String lcState = null; private List subscriptions = null; - public Integer getApiId() { - return apiId; - } - - public void setApiId(Integer apiId) { - this.apiId = apiId; - } - public String getProvider() { return provider; } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/APIList.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIList.java similarity index 83% rename from enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/APIList.java rename to enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIList.java index 368474ab28..8f930b80e8 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/APIList.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIList.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.choreo.connect.enforcer.models; +package org.wso2.choreo.connect.enforcer.models.admin; import java.util.ArrayList; import java.util.List; @@ -27,7 +27,7 @@ public class APIList { private Integer count = null; - private List list = new ArrayList<>(); + private List list = new ArrayList<>(); public Integer getCount() { @@ -39,12 +39,12 @@ public void setCount(Integer count) { this.count = count; } - public List getList() { + public List getList() { return list; } - public void setList(List list) { + public void setList(List list) { this.list = list; } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/ApplicationInfo.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/ApplicationInfo.java similarity index 97% rename from enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/ApplicationInfo.java rename to enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/ApplicationInfo.java index 4178d2e0eb..40ef3e4b2e 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/ApplicationInfo.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/ApplicationInfo.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.choreo.connect.enforcer.models; +package org.wso2.choreo.connect.enforcer.models.admin; import java.util.ArrayList; import java.util.List; diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/ApplicationInfoList.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/ApplicationInfoList.java similarity index 95% rename from enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/ApplicationInfoList.java rename to enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/ApplicationInfoList.java index 380ff69f44..f45a07d767 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/ApplicationInfoList.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/ApplicationInfoList.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.choreo.connect.enforcer.models; +package org.wso2.choreo.connect.enforcer.models.admin; import java.util.ArrayList; import java.util.List; diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/BasicAPIInfo.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/BasicAPIInfo.java new file mode 100644 index 0000000000..1f8834d145 --- /dev/null +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/BasicAPIInfo.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.choreo.connect.enforcer.models.admin; + +/** + * Entity for representing API related information for Admin REST API within enforcer. + */ +public class BasicAPIInfo { + + private String provider = null; + private String name = null; + private String version = null; + private String context = null; + private String policy = null; + private String apiType = null; + private boolean isDefaultVersion = false; + private String apiUUID = null; + private String lcState = null; + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public String getPolicy() { + return policy; + } + + public void setPolicy(String policy) { + this.policy = policy; + } + + public String getApiType() { + return apiType; + } + + public void setApiType(String apiType) { + this.apiType = apiType; + } + + public boolean isDefaultVersion() { + return isDefaultVersion; + } + + public void setDefaultVersion(boolean defaultVersion) { + isDefaultVersion = defaultVersion; + } + + public String getApiUUID() { + return apiUUID; + } + + public void setApiUUID(String apiUUID) { + this.apiUUID = apiUUID; + } + + public String getLcState() { + return lcState; + } + + public void setLcState(String lcState) { + this.lcState = lcState; + } +} diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/SubscriptionInfo.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/SubscriptionInfo.java similarity index 97% rename from enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/SubscriptionInfo.java rename to enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/SubscriptionInfo.java index e7931a5e1e..8b163174c7 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/SubscriptionInfo.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/SubscriptionInfo.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.choreo.connect.enforcer.models; +package org.wso2.choreo.connect.enforcer.models.admin; import java.io.Serializable; diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/KeyValidator.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/KeyValidator.java index 0d0493cd2e..9af3723256 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/KeyValidator.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/KeyValidator.java @@ -25,6 +25,7 @@ import org.wso2.choreo.connect.enforcer.commons.model.APIConfig; import org.wso2.choreo.connect.enforcer.commons.model.ResourceConfig; import org.wso2.choreo.connect.enforcer.constants.APIConstants; +import org.wso2.choreo.connect.enforcer.constants.GeneralErrorCodeConstants; import org.wso2.choreo.connect.enforcer.dto.APIKeyValidationInfoDTO; import org.wso2.choreo.connect.enforcer.exception.EnforcerException; import org.wso2.choreo.connect.enforcer.models.ApiPolicy; @@ -33,7 +34,6 @@ import org.wso2.choreo.connect.enforcer.models.ApplicationPolicy; import org.wso2.choreo.connect.enforcer.models.Subscription; import org.wso2.choreo.connect.enforcer.models.SubscriptionPolicy; -import org.wso2.choreo.connect.enforcer.models.URLMapping; import org.wso2.choreo.connect.enforcer.subscription.SubscriptionDataHolder; import org.wso2.choreo.connect.enforcer.subscription.SubscriptionDataStore; import org.wso2.choreo.connect.enforcer.util.FilterUtils; @@ -263,12 +263,11 @@ private static void validate(APIKeyValidationInfoDTO infoDTO, SubscriptionDataSt infoDTO.setAuthorized(false); return; } - // TODO: (VirajSalaka) checking for blocked APIs implementation is temporarily removed. -// else if (APIConstants.LifecycleStatus.BLOCKED.equals(api.getLcState())) { -// infoDTO.setValidationStatus(GeneralErrorCodeConstants.API_BLOCKED_CODE); -// infoDTO.setAuthorized(false); -// return; -// } + if (APIConstants.LifecycleStatus.BLOCKED.equals(apiConfig.getApiLifeCycleState())) { + infoDTO.setValidationStatus(GeneralErrorCodeConstants.API_BLOCKED_CODE); + infoDTO.setAuthorized(false); + return; + } infoDTO.setTier(sub.getPolicyId()); infoDTO.setSubscriber(app.getSubName()); infoDTO.setApplicationId(app.getId()); @@ -331,23 +330,4 @@ private static void validate(APIKeyValidationInfoDTO infoDTO, SubscriptionDataSt infoDTO.setThrottlingDataList(list); infoDTO.setAuthorized(true); } - - private boolean isResourcePathMatching(String resourceString, URLMapping urlMapping) { - - String resource = resourceString.trim(); - String urlPattern = urlMapping.getUrlPattern().trim(); - - if (resource.equalsIgnoreCase(urlPattern)) { - return true; - } - - // If the urlPattern is only one character longer than the resource and the urlPattern ends with a '/' - if (resource.length() + 1 == urlPattern.length() && urlPattern.endsWith("/")) { - // Check if resource is equal to urlPattern if the trailing '/' of the urlPattern is ignored - String urlPatternWithoutSlash = urlPattern.substring(0, urlPattern.length() - 1); - return resource.equalsIgnoreCase(urlPatternWithoutSlash); - } - - return false; - } } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java index abf638a48a..edcd22a01a 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java @@ -139,25 +139,6 @@ void addApplicationKeyMappings( API getDefaultApiByContext(String context); - /** - * Filter the API map according to the provided parameters - * @param name API Name - * @param context API Context - * @param version API Version - * @param uuid API UUID - * @return Matching list of apis. - */ - List getMatchingAPIs(String name, String context, String version, String uuid); - - /** - * Filter the API map according to the provided parameters - * - * @param context API Context - * @param version API Version - * @return Matching list of apis. - */ - API getMatchingAPI(String context, String version); - /** * Filter the applications map based on the criteria. * @param name Application Name diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java index 6218e29bcc..613ddd47a1 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java @@ -41,9 +41,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; /** * Implementation of the subscription data store. @@ -198,13 +196,6 @@ public void addApis(List apisList) { for (APIs api : apisList) { API newApi = new API(); - newApi.setApiId(Integer.parseInt(api.getApiId())); - newApi.setApiName(api.getName()); - newApi.setApiProvider(api.getProvider()); - newApi.setApiType(api.getApiType()); - newApi.setApiVersion(api.getVersion()); - newApi.setContext(api.getContext()); - newApi.setApiTier(api.getPolicy()); newApi.setApiUUID(api.getUuid()); newApi.setLcState(api.getLcState()); newApiMap.put(newApi.getCacheKey(), newApi); @@ -376,55 +367,16 @@ public void removeApiPolicy(ApiPolicy apiPolicy) { @Override public API getDefaultApiByContext(String context) { - Set set = apiMap.keySet() - .stream() - .filter(s -> s.startsWith(context)) - .collect(Collectors.toSet()); - for (String key : set) { - API api = apiMap.get(key); - if (api.isDefaultVersion() && (api.getContext().replace("/" + api.getApiVersion(), "")).equals(context)) { - return api; - } - } - return null; - } - - @Override - public List getMatchingAPIs(String name, String context, String version, String uuid) { - List apiList = new ArrayList<>(); - for (API api : apiMap.values()) { - boolean isNameMatching = true; - boolean isContextMatching = true; - boolean isVersionMatching = true; - boolean isUUIDMatching = true; - if (StringUtils.isNotEmpty(name)) { - isNameMatching = api.getApiName().contains(name); - } - if (StringUtils.isNotEmpty(context)) { - isContextMatching = api.getContext().equals(context); - } - if (StringUtils.isNotEmpty(version)) { - isVersionMatching = api.getApiVersion().equals(version); - } - if (StringUtils.isNotEmpty(uuid)) { - isUUIDMatching = api.getApiUUID().equals(uuid); - } - if (isNameMatching && isContextMatching && isVersionMatching && isUUIDMatching) { - apiList.add(api); - } - } - return apiList; - } - - @Override - public API getMatchingAPI(String context, String version) { - for (API api : apiMap.values()) { - if (StringUtils.isNotEmpty(context) && StringUtils.isNotEmpty(version)) { - if (api.getContext().equals(context) && api.getApiVersion().equals(version)) { - return api; - } - } - } +// Set set = apiMap.keySet() +// .stream() +// .filter(s -> s.startsWith(context)) +// .collect(Collectors.toSet()); +// for (String key : set) { +// API api = apiMap.get(key); +// if (api.isDefaultVersion() && (api.getContext().replace("/" + api.getApiVersion(), "")).equals(context)) { +// return api; +// } +// } return null; } diff --git a/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/EnforcerAPITestCase.java b/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/EnforcerAPITestCase.java index 302f3efa33..a60bee5664 100644 --- a/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/EnforcerAPITestCase.java +++ b/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/EnforcerAPITestCase.java @@ -42,51 +42,51 @@ void setup() throws Exception { super.initWithSuperTenant(); } -// @Test -// public void testGetAPIInfo() throws IOException { -// String requestUrl = "https://localhost:9001/api/info?context=" + API_CONTEXT + "&version=" + API_VERSION; -// Map headers = new HashMap<>(); -// headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); -// HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); -// Assert.assertNotNull(httpResponse.getData()); -// Assert.assertTrue(httpResponse.getData().contains(API_NAME)); -// Assert.assertTrue(httpResponse.getData().contains(API_CONTEXT)); -// Assert.assertTrue(httpResponse.getData().contains(API_VERSION)); -// Assert.assertTrue(httpResponse.getData().contains(APPLICATION_NAME)); -// } + @Test + public void testGetAPIInfo() throws IOException { + String requestUrl = "https://localhost:9001/api/info?context=" + API_CONTEXT + "&version=" + API_VERSION; + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); + HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); + Assert.assertNotNull(httpResponse.getData()); + Assert.assertTrue(httpResponse.getData().contains(API_NAME)); + Assert.assertTrue(httpResponse.getData().contains(API_CONTEXT)); + Assert.assertTrue(httpResponse.getData().contains(API_VERSION)); + Assert.assertTrue(httpResponse.getData().contains(APPLICATION_NAME)); + } -// @Test -// public void testGetNonExistingAPIInfo() throws IOException { -// String requestUrl = "https://localhost:9001/api/info?context=" + NON_EXISTING_CONTEXT + "&version=" + API_VERSION; -// Map headers = new HashMap<>(); -// headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); -// HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); -// Assert.assertNotNull(httpResponse.getData()); -// Assert.assertTrue(httpResponse.getData().contains("No API information found for context " + -// NON_EXISTING_CONTEXT + " and version " + API_VERSION)); -// } + @Test + public void testGetNonExistingAPIInfo() throws IOException { + String requestUrl = "https://localhost:9001/api/info?context=" + NON_EXISTING_CONTEXT + "&version=" + API_VERSION; + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); + HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); + Assert.assertNotNull(httpResponse.getData()); + Assert.assertTrue(httpResponse.getData().contains("No API information found for context " + + NON_EXISTING_CONTEXT + " and version " + API_VERSION)); + } -// @Test -// public void testGetAllAPIs() throws IOException { -// String requestUrl = "https://localhost:9001/apis"; -// Map headers = new HashMap<>(); -// headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); -// HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); -// Assert.assertNotNull(httpResponse.getData()); -// Assert.assertTrue(httpResponse.getData().contains("count")); -// } + @Test + public void testGetAllAPIs() throws IOException { + String requestUrl = "https://localhost:9001/apis"; + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); + HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); + Assert.assertNotNull(httpResponse.getData()); + Assert.assertTrue(httpResponse.getData().contains("count")); + } -// @Test -// public void testQueryAPIs() throws IOException { -// String requestUrl = "https://localhost:9001/apis?context=" + API_CONTEXT; -// Map headers = new HashMap<>(); -// headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); -// HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); -// Assert.assertNotNull(httpResponse.getData()); -// Assert.assertTrue(httpResponse.getData().contains("\"count\":1")); -// Assert.assertTrue(httpResponse.getData().contains(API_CONTEXT)); -// Assert.assertTrue(httpResponse.getData().contains(API_NAME)); -// } + @Test + public void testQueryAPIs() throws IOException { + String requestUrl = "https://localhost:9001/apis?context=" + API_CONTEXT; + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic " + ADMIN_CREDENTIALS); + HttpResponse httpResponse = HttpClientRequest.doGet(requestUrl, headers); + Assert.assertNotNull(httpResponse.getData()); + Assert.assertTrue(httpResponse.getData().contains("\"count\":1")); + Assert.assertTrue(httpResponse.getData().contains(API_CONTEXT)); + Assert.assertTrue(httpResponse.getData().contains(API_NAME)); + } @Test public void testGetApplications() throws IOException { diff --git a/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/PrototypedAPITestCase.java b/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/PrototypedAPITestCase.java deleted file mode 100644 index 89571ad087..0000000000 --- a/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/withapim/PrototypedAPITestCase.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org). - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.choreo.connect.tests.testcases.withapim; - -import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.HttpStatus; -import com.google.gson.Gson; -import net.minidev.json.JSONObject; -import net.minidev.json.parser.JSONParser; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.wso2.am.integration.clients.publisher.api.v1.dto.APIDTO; -import org.wso2.am.integration.clients.publisher.api.v1.dto.WorkflowResponseDTO; -import org.wso2.am.integration.test.utils.bean.APILifeCycleAction; -import org.wso2.am.integration.test.utils.bean.APIRequest; -import org.wso2.carbon.automation.test.utils.http.client.HttpResponse; -import org.wso2.choreo.connect.tests.apim.ApimBaseTest; -import org.wso2.choreo.connect.tests.apim.utils.PublisherUtils; -import org.wso2.choreo.connect.tests.util.HttpsClientRequest; -import org.wso2.choreo.connect.tests.util.TestConstant; -import org.wso2.choreo.connect.tests.util.Utils; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -public class PrototypedAPITestCase extends ApimBaseTest { - private static final String SAMPLE_API_NAME = "APIMPrototypedEndpointAPI1"; - private static final String SAMPLE_API_CONTEXT = "petstore-prototype"; - private static final String SAMPLE_API_VERSION = "1.0.0"; - private String apiId; - - @BeforeClass(description = "Initialise the setup for API key tests") - void start() throws Exception { - super.initWithSuperTenant(); - String apiEndPointUrl = Utils.getDockerMockServiceURLHttp(TestConstant.MOCK_BACKEND_BASEPATH);; - String apiProvider = "admin"; - - APIRequest apiRequest = new APIRequest(SAMPLE_API_NAME, SAMPLE_API_CONTEXT, new URL(apiEndPointUrl)); - apiRequest.setVersion(SAMPLE_API_VERSION); - apiRequest.setVisibility(APIDTO.VisibilityEnum.PUBLIC.getValue()); - apiRequest.setProvider(apiProvider); - - apiId = PublisherUtils.createAPI(apiRequest, publisherRestClient); - - WorkflowResponseDTO lcChangeResponse = publisherRestClient.changeAPILifeCycleStatus( - apiId, APILifeCycleAction.DEPLOY_AS_PROTOTYPE.getAction()); - - HttpResponse response = publisherRestClient.getAPI(apiId); - Gson g = new Gson(); - APIDTO apiDto = g.fromJson(response.getData(), APIDTO.class); - String endPointString = "{\"implementation_status\":\"prototyped\",\"endpoint_type\":\"http\"," + - "\"production_endpoints\":{\"config\":null," + - "\"url\":\"" + apiEndPointUrl + "\"}," + - "\"sandbox_endpoints\":{\"config\":null,\"url\":\"" + "http://localhost" + "\"}}"; - - JSONParser parser = new JSONParser(); - JSONObject endpoint = (JSONObject) parser.parse(endPointString); - apiDto.setEndpointConfig(endpoint); - publisherRestClient.updateAPI(apiDto); - - Assert.assertTrue(lcChangeResponse.getLifecycleState().getState().equals("Prototyped"), - SAMPLE_API_NAME + " status not updated as Prototyped"); - - PublisherUtils.createAPIRevisionAndDeploy(apiId, publisherRestClient); - Utils.delay(TestConstant.DEPLOYMENT_WAIT_TIME, "Could not wait till initial setup completion."); - } - - @Test(description = "Test to check the PrototypedAPI is working") - public void invokePrototypeAPISuccessTest() throws Exception { - // Set header - Map headers = new HashMap<>(); - org.wso2.choreo.connect.tests.util.HttpResponse response = - HttpsClientRequest.doGet( - Utils.getServiceURLHttps("/petstore-prototype/1.0.0/pet/findByStatus"), headers); - - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), HttpStatus.SC_OK,"Response code mismatched"); - } -} diff --git a/integration/test-integration/src/test/resources/testng-cc-with-apim.xml b/integration/test-integration/src/test/resources/testng-cc-with-apim.xml index f27aa3b250..1845958364 100644 --- a/integration/test-integration/src/test/resources/testng-cc-with-apim.xml +++ b/integration/test-integration/src/test/resources/testng-cc-with-apim.xml @@ -41,9 +41,9 @@ - - - + + + @@ -60,7 +60,7 @@ - + @@ -77,7 +77,7 @@ - + @@ -89,7 +89,6 @@ - diff --git a/router/src/main/resources/Dockerfile b/router/src/main/resources/Dockerfile index 23976bf7dd..1b09b291fd 100644 --- a/router/src/main/resources/Dockerfile +++ b/router/src/main/resources/Dockerfile @@ -69,4 +69,5 @@ COPY maven/wasm /home/wso2/wasm COPY maven/security/truststore/ca-certificates.crt /etc/ssl/certs COPY maven/interceptor /home/wso2/interceptor COPY maven/envoy.yaml /etc/envoy/envoy.yaml + CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml --config-yaml "{admin: {address: {socket_address: {address: '${ROUTER_ADMIN_HOST}', port_value: '${ROUTER_ADMIN_PORT}'}}}, dynamic_resources: {ads_config: {api_type: GRPC, transport_api_version: V3, grpc_services: [{envoy_grpc: {cluster_name: xds_cluster}}]}, cds_config: {ads: {}, resource_api_version: V3}, lds_config: {ads: {}, resource_api_version: V3}}, node: {cluster: '${ROUTER_CLUSTER}', id: '${ROUTER_LABEL}', metadata: {instanceIdentifier : ${HOSTNAME}}}, static_resources: {clusters: [{name: xds_cluster, type: STRICT_DNS, connect_timeout: 1s, upstream_connection_options: {tcp_keepalive: {keepalive_probes: 3, keepalive_time: 300, keepalive_interval: 30}}, load_assignment: {cluster_name: xds_cluster, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ADAPTER_HOST}', port_value: '${ADAPTER_PORT}'}}}}]}]}, typed_extension_protocol_options: {envoy.extensions.upstreams.http.v3.HttpProtocolOptions: {'@type': 'type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions', explicit_http_config: {http2_protocol_options: {}}}}, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ADAPTER_CA_CERT_PATH}'}}}}}}, {name: ext-authz, type: STRICT_DNS, connect_timeout: 20s, typed_extension_protocol_options: {envoy.extensions.upstreams.http.v3.HttpProtocolOptions: {'@type': 'type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions', explicit_http_config: {http2_protocol_options: {}}}}, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ENFORCER_CA_CERT_PATH}'}}}}}, load_assignment: {cluster_name: ext-authz, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ENFORCER_HOST}', port_value: '${ENFORCER_PORT}'}}}}]}]}}, {name: access-logger, type: STRICT_DNS, connect_timeout: 200s, typed_extension_protocol_options: {envoy.extensions.upstreams.http.v3.HttpProtocolOptions: {'@type': 'type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions', explicit_http_config: {http2_protocol_options: {}}}}, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ENFORCER_CA_CERT_PATH}'}}}}}, load_assignment: {cluster_name: access-logger, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ENFORCER_ANALYTICS_HOST}', port_value: '${ENFORCER_ANALYTICS_RECEIVER_PORT}'}}}}]}]}}, {name: token_cluster, type: STRICT_DNS, connect_timeout: 20s, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ENFORCER_CA_CERT_PATH}'}}}}}, load_assignment: {cluster_name: token_cluster, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ENFORCER_HOST}', port_value: 8082}}}}]}]}}]}, layeredRuntime: {layers: [{name: deprecation, staticLayer: {re2.max_program_size.error_level: 1000}}]} }" --concurrency "${CONCURRENCY}" $TRAILING_ARGS diff --git a/router/src/main/resources/Dockerfile.ubuntu b/router/src/main/resources/Dockerfile.ubuntu index cf2d7062ca..37d56580a8 100644 --- a/router/src/main/resources/Dockerfile.ubuntu +++ b/router/src/main/resources/Dockerfile.ubuntu @@ -69,4 +69,5 @@ COPY maven/wasm /home/wso2/wasm COPY maven/security/truststore/ca-certificates.crt /etc/ssl/certs COPY maven/interceptor /home/wso2/interceptor COPY maven/envoy.yaml /etc/envoy/envoy.yaml + CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml --config-yaml "{admin: {address: {socket_address: {address: '${ROUTER_ADMIN_HOST}', port_value: '${ROUTER_ADMIN_PORT}'}}}, dynamic_resources: {ads_config: {api_type: GRPC, transport_api_version: V3, grpc_services: [{envoy_grpc: {cluster_name: xds_cluster}}]}, cds_config: {ads: {}, resource_api_version: V3}, lds_config: {ads: {}, resource_api_version: V3}}, node: {cluster: '${ROUTER_CLUSTER}', id: '${ROUTER_LABEL}', metadata: {instanceIdentifier : ${HOSTNAME}}}, static_resources: {clusters: [{name: xds_cluster, type: STRICT_DNS, connect_timeout: 1s, upstream_connection_options: {tcp_keepalive: {keepalive_probes: 3, keepalive_time: 300, keepalive_interval: 30}}, load_assignment: {cluster_name: xds_cluster, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ADAPTER_HOST}', port_value: '${ADAPTER_PORT}'}}}}]}]}, typed_extension_protocol_options: {envoy.extensions.upstreams.http.v3.HttpProtocolOptions: {'@type': 'type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions', explicit_http_config: {http2_protocol_options: {}}}}, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ADAPTER_CA_CERT_PATH}'}}}}}}, {name: ext-authz, type: STRICT_DNS, connect_timeout: 20s, typed_extension_protocol_options: {envoy.extensions.upstreams.http.v3.HttpProtocolOptions: {'@type': 'type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions', explicit_http_config: {http2_protocol_options: {}}}}, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ENFORCER_CA_CERT_PATH}'}}}}}, load_assignment: {cluster_name: ext-authz, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ENFORCER_HOST}', port_value: '${ENFORCER_PORT}'}}}}]}]}}, {name: access-logger, type: STRICT_DNS, connect_timeout: 200s, typed_extension_protocol_options: {envoy.extensions.upstreams.http.v3.HttpProtocolOptions: {'@type': 'type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions', explicit_http_config: {http2_protocol_options: {}}}}, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ENFORCER_CA_CERT_PATH}'}}}}}, load_assignment: {cluster_name: access-logger, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ENFORCER_ANALYTICS_HOST}', port_value: '${ENFORCER_ANALYTICS_RECEIVER_PORT}'}}}}]}]}}, {name: token_cluster, type: STRICT_DNS, connect_timeout: 20s, transport_socket: {name: envoy.transport_sockets.tls, typed_config: {'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext, common_tls_context: {tls_params: {tls_minimum_protocol_version: TLSv1_2, tls_maximum_protocol_version: TLSv1_2}, tls_certificates: {private_key: {filename: '${ROUTER_PRIVATE_KEY_PATH}'}, certificate_chain: {filename: '${ROUTER_PUBLIC_CERT_PATH}'}}, validation_context: {trusted_ca: {filename: '${ENFORCER_CA_CERT_PATH}'}}}}}, load_assignment: {cluster_name: token_cluster, endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: '${ENFORCER_HOST}', port_value: 8082}}}}]}]}}]}, layeredRuntime: {layers: [{name: deprecation, staticLayer: {re2.max_program_size.error_level: 1000}}]} }" --concurrency "${CONCURRENCY}" $TRAILING_ARGS From bd8939e80e0679f85d9dc3ec5b3cf692e909e6df Mon Sep 17 00:00:00 2001 From: Viraj Gamage Date: Tue, 5 Jul 2022 16:31:47 +0530 Subject: [PATCH 2/4] Remove unnecessary API List Discovery Client and APIListDTO as they remain unused --- .../discovery/ApiListDiscoveryClient.java | 200 ------------------ .../scheduler/XdsSchedulerManager.java | 8 - .../choreo/connect/enforcer/models/API.java | 68 ------ .../subscription/SubscriptionDataStore.java | 20 -- .../SubscriptionDataStoreImpl.java | 55 ----- 5 files changed, 351 deletions(-) delete mode 100644 enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/ApiListDiscoveryClient.java delete mode 100644 enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/ApiListDiscoveryClient.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/ApiListDiscoveryClient.java deleted file mode 100644 index 8f98d0e9f7..0000000000 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/ApiListDiscoveryClient.java +++ /dev/null @@ -1,200 +0,0 @@ -/* -* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ - -package org.wso2.choreo.connect.enforcer.discovery; - -import com.google.protobuf.Any; -import com.google.rpc.Status; -import io.envoyproxy.envoy.config.core.v3.Node; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; -import io.grpc.ConnectivityState; -import io.grpc.ManagedChannel; -import io.grpc.stub.StreamObserver; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.wso2.choreo.connect.discovery.service.subscription.ApiListDiscoveryServiceGrpc; -import org.wso2.choreo.connect.discovery.subscription.APIList; -import org.wso2.choreo.connect.discovery.subscription.APIs; -import org.wso2.choreo.connect.enforcer.config.ConfigHolder; -import org.wso2.choreo.connect.enforcer.constants.Constants; -import org.wso2.choreo.connect.enforcer.discovery.common.XDSCommonUtils; -import org.wso2.choreo.connect.enforcer.discovery.scheduler.XdsSchedulerManager; -import org.wso2.choreo.connect.enforcer.subscription.SubscriptionDataStoreImpl; -import org.wso2.choreo.connect.enforcer.util.GRPCUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Client to communicate with API list discovery service at the adapter. - */ -public class ApiListDiscoveryClient implements Runnable { - private static final Logger logger = LogManager.getLogger(ApiListDiscoveryClient.class); - private static ApiListDiscoveryClient instance; - private ManagedChannel channel; - private ApiListDiscoveryServiceGrpc.ApiListDiscoveryServiceStub stub; - private StreamObserver reqObserver; - private final SubscriptionDataStoreImpl subscriptionDataStore; - private final String host; - private final int port; - - /** - * This is a reference to the latest received response from the ADS. - *

- * Usage: When ack/nack a DiscoveryResponse this value is used to identify the latest received DiscoveryResponse - * which may not have been acked/nacked so far. - *

- */ - private DiscoveryResponse latestReceived; - - /** - * This is a reference to the latest acked response from the ADS. - *

- * Usage: When nack a DiscoveryResponse this value is used to find the latest successfully processed - * DiscoveryResponse. Information sent in the nack request will contain information about this response value. - *

- */ - private DiscoveryResponse latestACKed; - - /** - * Node struct for the discovery client - */ - private final Node node; - - private ApiListDiscoveryClient(String host, int port) { - this.host = host; - this.port = port; - this.subscriptionDataStore = SubscriptionDataStoreImpl.getInstance(); - initConnection(); - this.node = XDSCommonUtils.generateXDSNode(ConfigHolder.getInstance().getEnvVarConfig().getEnforcerLabel()); - this.latestACKed = DiscoveryResponse.getDefaultInstance(); - } - - private void initConnection() { - if (GRPCUtils.isReInitRequired(channel)) { - if (channel != null && !channel.isShutdown()) { - channel.shutdownNow(); - do { - try { - channel.awaitTermination(100, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - logger.error("API list discovery channel shutdown wait was interrupted", e); - } - } while (!channel.isShutdown()); - } - this.channel = GRPCUtils.createSecuredChannel(logger, host, port); - this.stub = ApiListDiscoveryServiceGrpc.newStub(channel); - } else if (channel.getState(true) == ConnectivityState.READY) { - XdsSchedulerManager.getInstance().stopAPIListDiscoveryScheduling(); - } - } - - public static ApiListDiscoveryClient getInstance() { - if (instance == null) { - String sdsHost = ConfigHolder.getInstance().getEnvVarConfig().getAdapterHost(); - int sdsPort = Integer.parseInt(ConfigHolder.getInstance().getEnvVarConfig().getAdapterXdsPort()); - instance = new ApiListDiscoveryClient(sdsHost, sdsPort); - } - return instance; - } - - public void run() { - initConnection(); - watchApiList(); - } - - public void watchApiList() { - // TODO: (Praminda) implement a deadline with retries - reqObserver = stub.streamApiList(new StreamObserver() { - @Override - public void onNext(DiscoveryResponse response) { - logger.info("API list event received with version : " + response.getVersionInfo()); - logger.debug("Received Api list discovery response " + response); - XdsSchedulerManager.getInstance().stopAPIListDiscoveryScheduling(); - latestReceived = response; - try { - List apiList = new ArrayList<>(); - for (Any res : response.getResourcesList()) { - apiList.addAll(res.unpack(APIList.class).getListList()); - } - subscriptionDataStore.addApis(apiList); - logger.info("Number of APIs received : " + apiList.size()); - ack(); - } catch (Exception e) { - // catching generic error here to wrap any grpc communication errors in the runtime - onError(e); - } - } - - @Override - public void onError(Throwable throwable) { - logger.error("Error occurred during Api list discovery", throwable); - XdsSchedulerManager.getInstance().startAPIListDiscoveryScheduling(); - nack(throwable); - } - - @Override - public void onCompleted() { - logger.info("Completed receiving Api list"); - } - }); - - try { - DiscoveryRequest req = DiscoveryRequest.newBuilder() - .setNode(node) - .setVersionInfo(latestACKed.getVersionInfo()) - .setTypeUrl(Constants.API_LIST_TYPE_URL).build(); - reqObserver.onNext(req); - logger.debug("Sent Discovery request for type url: " + Constants.API_LIST_TYPE_URL); - - } catch (Exception e) { - logger.error("Unexpected error occurred in API list discovery service", e); - reqObserver.onError(e); - } - } - - /** - * Send acknowledgement of successfully processed DiscoveryResponse from the xDS server. This is part of the xDS - * communication protocol. - */ - private void ack() { - DiscoveryRequest req = DiscoveryRequest.newBuilder() - .setNode(node) - .setVersionInfo(latestReceived.getVersionInfo()) - .setResponseNonce(latestReceived.getNonce()) - .setTypeUrl(Constants.API_LIST_TYPE_URL).build(); - reqObserver.onNext(req); - latestACKed = latestReceived; - } - - private void nack(Throwable e) { - if (latestReceived == null) { - return; - } - DiscoveryRequest req = DiscoveryRequest.newBuilder() - .setNode(node) - .setVersionInfo(latestACKed.getVersionInfo()) - .setResponseNonce(latestReceived.getNonce()) - .setTypeUrl(Constants.API_LIST_TYPE_URL) - .setErrorDetail(Status.newBuilder().setMessage(e.getMessage())) - .build(); - reqObserver.onNext(req); - } -} diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/scheduler/XdsSchedulerManager.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/scheduler/XdsSchedulerManager.java index b78ab80d65..1c6be9a4dd 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/scheduler/XdsSchedulerManager.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/discovery/scheduler/XdsSchedulerManager.java @@ -20,7 +20,6 @@ import org.wso2.choreo.connect.enforcer.config.EnvVarConfig; import org.wso2.choreo.connect.enforcer.discovery.ApiDiscoveryClient; -import org.wso2.choreo.connect.enforcer.discovery.ApiListDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.ApplicationDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.ApplicationKeyMappingDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.ApplicationPolicyDiscoveryClient; @@ -82,13 +81,6 @@ public synchronized void stopAPIDiscoveryScheduling() { } } - public synchronized void startAPIListDiscoveryScheduling() { - if (apiDiscoveryListScheduledFuture == null || apiDiscoveryListScheduledFuture.isDone()) { - apiDiscoveryListScheduledFuture = discoveryClientScheduler - .scheduleWithFixedDelay(ApiListDiscoveryClient.getInstance(), 1, retryPeriod, TimeUnit.SECONDS); - } - } - public synchronized void stopAPIListDiscoveryScheduling() { if (apiDiscoveryListScheduledFuture != null && !apiDiscoveryListScheduledFuture.isDone()) { apiDiscoveryListScheduledFuture.cancel(false); diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java deleted file mode 100644 index cad7b0e937..0000000000 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/API.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.choreo.connect.enforcer.models; - -import org.wso2.choreo.connect.enforcer.common.CacheableEntity; - -/** - * Entity for keeping API related information. - */ -public class API implements CacheableEntity { - - private boolean isDefaultVersion = false; - private String apiUUID = null; - private String lcState = null; - - public String getCacheKey() { - - return apiUUID; - } - - public String getLcState() { - return lcState; - } - - public void setLcState(String lcState) { - this.lcState = lcState; - } - - // TODO: (VirajSalaka) -// @Override -// public String toString() { -// return "API [apiId=" + apiId + ", provider=" + provider + ", name=" + name + ", version=" + version -// + ", context=" + context + ", policy=" + policy + ", apiType=" + apiType + "]"; -// } - - public boolean isDefaultVersion() { - return isDefaultVersion; - } - - public void setDefaultVersion(boolean isDefaultVersion) { - this.isDefaultVersion = isDefaultVersion; - } - - public String getApiUUID() { - return apiUUID; - } - - public void setApiUUID(String apiUUID) { - this.apiUUID = apiUUID; - } -} - diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java index edcd22a01a..0248531108 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStore.java @@ -18,8 +18,6 @@ package org.wso2.choreo.connect.enforcer.subscription; -import org.wso2.choreo.connect.discovery.subscription.APIs; -import org.wso2.choreo.connect.enforcer.models.API; import org.wso2.choreo.connect.enforcer.models.ApiPolicy; import org.wso2.choreo.connect.enforcer.models.Application; import org.wso2.choreo.connect.enforcer.models.ApplicationKeyMapping; @@ -51,14 +49,6 @@ public interface SubscriptionDataStore { */ ApplicationKeyMapping getKeyMappingByKeyAndKeyManager(String key, String keyManager); - /** - * Get API by Context and Version. - * - * @param uuid UUID of the API - * @return {@link API} entry represented by Context and Version. - */ - API getApiByContextAndVersion(String uuid); - /** * Gets Subscription by ID. * @@ -96,8 +86,6 @@ public interface SubscriptionDataStore { void addApplications(List applicationList); - void addApis(List apisList); - void addApplicationPolicies( List applicationPolicyList); @@ -111,10 +99,6 @@ void addApplicationKeyMappings( void addOrUpdateSubscription(Subscription subscription); - void addOrUpdateAPI(API api); - - void addOrUpdateAPIWithUrlTemplates(API api); - void addOrUpdateApplicationKeyMapping(ApplicationKeyMapping applicationKeyMapping); void addOrUpdateSubscriptionPolicy(SubscriptionPolicy subscriptionPolicy); @@ -125,8 +109,6 @@ void addApplicationKeyMappings( void removeApplication(Application application); - void removeAPI(API api); - void removeSubscription(Subscription subscription); void removeApplicationKeyMapping(ApplicationKeyMapping applicationKeyMapping); @@ -137,8 +119,6 @@ void addApplicationKeyMappings( void removeApiPolicy(ApiPolicy apiPolicy); - API getDefaultApiByContext(String context); - /** * Filter the applications map based on the criteria. * @param name Application Name diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java index 613ddd47a1..3b8af75691 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/subscription/SubscriptionDataStoreImpl.java @@ -21,15 +21,12 @@ import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.wso2.choreo.connect.discovery.subscription.APIs; import org.wso2.choreo.connect.enforcer.constants.APIConstants; -import org.wso2.choreo.connect.enforcer.discovery.ApiListDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.ApplicationDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.ApplicationKeyMappingDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.ApplicationPolicyDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.SubscriptionDiscoveryClient; import org.wso2.choreo.connect.enforcer.discovery.SubscriptionPolicyDiscoveryClient; -import org.wso2.choreo.connect.enforcer.models.API; import org.wso2.choreo.connect.enforcer.models.ApiPolicy; import org.wso2.choreo.connect.enforcer.models.Application; import org.wso2.choreo.connect.enforcer.models.ApplicationKeyMapping; @@ -65,7 +62,6 @@ public enum PolicyType { // Maps for keeping Subscription related details. private Map applicationKeyMappingMap; private Map applicationMap; - private Map apiMap; private Map apiPolicyMap; private Map subscriptionPolicyMap; private Map appPolicyMap; @@ -83,7 +79,6 @@ public void initializeStore() { this.applicationKeyMappingMap = new ConcurrentHashMap<>(); this.applicationMap = new ConcurrentHashMap<>(); - this.apiMap = new ConcurrentHashMap<>(); this.subscriptionPolicyMap = new ConcurrentHashMap<>(); this.appPolicyMap = new ConcurrentHashMap<>(); this.apiPolicyMap = new ConcurrentHashMap<>(); @@ -102,11 +97,6 @@ public ApplicationKeyMapping getKeyMappingByKeyAndKeyManager(String key, String return applicationKeyMappingMap.get(new ApplicationKeyMappingCacheKey(key, keyManager)); } - @Override - public API getApiByContextAndVersion(String uuid) { - return apiMap.get(uuid); - } - @Override public SubscriptionPolicy getSubscriptionPolicyByName(String policyName) { @@ -140,7 +130,6 @@ public ApiPolicy getApiPolicyByName(String policyName) { private void initializeLoadingTasks() { SubscriptionDiscoveryClient.getInstance().watchSubscriptions(); ApplicationDiscoveryClient.getInstance().watchApplications(); - ApiListDiscoveryClient.getInstance().watchApiList(); ApplicationPolicyDiscoveryClient.getInstance().watchApplicationPolicies(); SubscriptionPolicyDiscoveryClient.getInstance().watchSubscriptionPolicies(); ApplicationKeyMappingDiscoveryClient.getInstance().watchApplicationKeyMappings(); @@ -191,21 +180,6 @@ public void addApplications(List apisList) { - Map newApiMap = new ConcurrentHashMap<>(); - - for (APIs api : apisList) { - API newApi = new API(); - newApi.setApiUUID(api.getUuid()); - newApi.setLcState(api.getLcState()); - newApiMap.put(newApi.getCacheKey(), newApi); - } - if (log.isDebugEnabled()) { - log.debug("Total Apis in new cache: {}", newApiMap.size()); - } - this.apiMap = newApiMap; - } - public void addApplicationPolicies( List applicationPolicyList) { Map newAppPolicyMap = new ConcurrentHashMap<>(); @@ -297,20 +271,6 @@ public void removeSubscription(Subscription subscription) { subscriptionMap.remove(subscription.getCacheKey()); } - @Override - public void addOrUpdateAPI(API api) { - apiMap.put(api.getCacheKey(), api); - } - - @Override - public void addOrUpdateAPIWithUrlTemplates(API api) { - } - - @Override - public void removeAPI(API api) { - apiMap.remove(api.getCacheKey()); - } - @Override public void addOrUpdateApplicationKeyMapping(ApplicationKeyMapping applicationKeyMapping) { @@ -365,21 +325,6 @@ public void removeApiPolicy(ApiPolicy apiPolicy) { apiPolicyMap.remove(apiPolicy.getCacheKey()); } - @Override - public API getDefaultApiByContext(String context) { -// Set set = apiMap.keySet() -// .stream() -// .filter(s -> s.startsWith(context)) -// .collect(Collectors.toSet()); -// for (String key : set) { -// API api = apiMap.get(key); -// if (api.isDefaultVersion() && (api.getContext().replace("/" + api.getApiVersion(), "")).equals(context)) { -// return api; -// } -// } - return null; - } - @Override public List getMatchingApplications(String name, String organizationID, String uuid) { List applicationList = new ArrayList<>(); From 1d3395c1953f0754c646d65917c9e28791f2b161 Mon Sep 17 00:00:00 2001 From: Viraj Gamage Date: Tue, 5 Jul 2022 17:14:29 +0530 Subject: [PATCH 3/4] refactor : resolve review comments --- adapter/internal/discovery/xds/server.go | 4 +- .../connect/enforcer/admin/AdminUtils.java | 2 +- .../admin/handlers/APIRequestHandler.java | 2 +- .../enforcer/models/admin/APIInfo.java | 56 +------------------ 4 files changed, 5 insertions(+), 59 deletions(-) diff --git a/adapter/internal/discovery/xds/server.go b/adapter/internal/discovery/xds/server.go index dbb58dfa24..4adce3d534 100644 --- a/adapter/internal/discovery/xds/server.go +++ b/adapter/internal/discovery/xds/server.go @@ -121,7 +121,7 @@ const ( prototypedAPI string = "PROTOTYPED" apiKeyFieldSeparator string = ":" blockedStatus string = "BLOCKED" - nonBlockedStatus string = "CREATED/PUBLISHED" + publishedStatus string = "PUBLISHED" ) // IDHash uses ID field as the node hash. @@ -1308,5 +1308,5 @@ func updateLCStateOfMgwSwagger(mgwSwagger *model.MgwSwagger) { mgwSwagger.LifeCycleState = blockedStatus return } - mgwSwagger.LifeCycleState = nonBlockedStatus + mgwSwagger.LifeCycleState = publishedStatus } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java index d861d4fc14..9d60716047 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/AdminUtils.java @@ -52,7 +52,7 @@ public static APIInfo toAPIInfo(API api, List subscriptionInfo apiInfo.setContext(api.getAPIConfig().getBasePath()); apiInfo.setName(api.getAPIConfig().getName()); apiInfo.setLcState(api.getAPIConfig().getApiLifeCycleState()); - apiInfo.setTier(api.getAPIConfig().getTier()); + apiInfo.setPolicy(api.getAPIConfig().getTier()); apiInfo.setVersion(api.getAPIConfig().getVersion()); apiInfo.setProvider(api.getAPIConfig().getApiProvider()); apiInfo.setApiType(api.getAPIConfig().getApiType()); diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java index 8a23616c7d..c48808540c 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/admin/handlers/APIRequestHandler.java @@ -88,7 +88,7 @@ private ResponsePayload getAPIs(String[] params) throws JsonProcessingException apiList.setCount(apis.size()); List modelAPIs = new ArrayList<>(apis.size()); for (API api : apis) { - // TODO: (VirajSalaka) fix + // IsDefaultVersion is not populated as it is not required for the enforcer. modelAPIs.add(AdminUtils.toBasicAPIInfo(api, false)); } apiList.setList(modelAPIs); diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIInfo.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIInfo.java index c92de2ce7e..cedeb1d0a4 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIInfo.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/models/admin/APIInfo.java @@ -22,58 +22,12 @@ /** * Model class for API Information */ -public class APIInfo { - private String provider = null; - private String name = null; - private String version = null; - private String context = null; - private String tier = null; +public class APIInfo extends BasicAPIInfo { private String apiType = null; - private boolean isDefaultVersion = false; private String apiUUID = null; private String lcState = null; private List subscriptions = null; - public String getProvider() { - return provider; - } - - public void setProvider(String provider) { - this.provider = provider; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getTier() { - return tier; - } - - public void setTier(String tier) { - this.tier = tier; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getContext() { - return context; - } - - public void setContext(String context) { - this.context = context; - } - public String getApiType() { return apiType; } @@ -82,14 +36,6 @@ public void setApiType(String apiType) { this.apiType = apiType; } - public boolean isDefaultVersion() { - return isDefaultVersion; - } - - public void setDefaultVersion(boolean defaultVersion) { - isDefaultVersion = defaultVersion; - } - public String getApiUUID() { return apiUUID; } From 3e20efbecf70263abfea0925b7102515278b7449 Mon Sep 17 00:00:00 2001 From: Viraj Gamage Date: Wed, 6 Jul 2022 10:07:10 +0530 Subject: [PATCH 4/4] revert changing the lifecycle status to CREATED/PUBLISHED --- adapter/internal/discovery/xds/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adapter/internal/discovery/xds/server.go b/adapter/internal/discovery/xds/server.go index 4adce3d534..1e45492ade 100644 --- a/adapter/internal/discovery/xds/server.go +++ b/adapter/internal/discovery/xds/server.go @@ -121,7 +121,7 @@ const ( prototypedAPI string = "PROTOTYPED" apiKeyFieldSeparator string = ":" blockedStatus string = "BLOCKED" - publishedStatus string = "PUBLISHED" + nonBlockedStatus string = "CREATED/PUBLISHED" ) // IDHash uses ID field as the node hash. @@ -1308,5 +1308,5 @@ func updateLCStateOfMgwSwagger(mgwSwagger *model.MgwSwagger) { mgwSwagger.LifeCycleState = blockedStatus return } - mgwSwagger.LifeCycleState = publishedStatus + mgwSwagger.LifeCycleState = nonBlockedStatus }