diff --git a/adapter/internal/oasparser/constants/constants.go b/adapter/internal/oasparser/constants/constants.go index df863dc5a..3893d473a 100644 --- a/adapter/internal/oasparser/constants/constants.go +++ b/adapter/internal/oasparser/constants/constants.go @@ -98,6 +98,7 @@ const ( SOAP string = "SOAP" WS string = "WS" GRAPHQL string = "GraphQL" + GRPC string = "GRPC" WEBHOOK string = "WEBHOOK" SSE string = "SSE" Prototyped string = "prototyped" diff --git a/adapter/internal/oasparser/envoyconf/internal_dtos.go b/adapter/internal/oasparser/envoyconf/internal_dtos.go index 27fe51132..9e05b9810 100644 --- a/adapter/internal/oasparser/envoyconf/internal_dtos.go +++ b/adapter/internal/oasparser/envoyconf/internal_dtos.go @@ -19,7 +19,7 @@ package envoyconf import ( "github.com/wso2/apk/adapter/internal/oasparser/model" - dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" ) // routeCreateParams is the DTO used to provide information to the envoy route create function @@ -41,7 +41,7 @@ type routeCreateParams struct { isDefaultVersion bool createDefaultPath bool apiLevelRateLimitPolicy *model.RateLimitPolicy - apiProperties []dpv1alpha2.Property + apiProperties []dpv1beta1.Property environment string envType string } diff --git a/adapter/internal/oasparser/envoyconf/routes_with_clusters.go b/adapter/internal/oasparser/envoyconf/routes_with_clusters.go index acb0edb51..34cbfa17b 100644 --- a/adapter/internal/oasparser/envoyconf/routes_with_clusters.go +++ b/adapter/internal/oasparser/envoyconf/routes_with_clusters.go @@ -52,7 +52,7 @@ import ( logging "github.com/wso2/apk/adapter/internal/logging" "github.com/wso2/apk/adapter/internal/oasparser/constants" "github.com/wso2/apk/adapter/internal/oasparser/model" - dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "google.golang.org/protobuf/proto" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) @@ -197,6 +197,73 @@ func CreateRoutesWithClusters(adapterInternalAPI *model.AdapterInternalAPI, inte } return routes, clusters, endpoints, nil } + if adapterInternalAPI.GetAPIType() == constants.GRPC { + basePath := strings.TrimSuffix(adapterInternalAPI.Endpoints.Endpoints[0].Basepath, "/") + + clusterName := getClusterName(adapterInternalAPI.Endpoints.EndpointPrefix, organizationID, vHost, + adapterInternalAPI.GetTitle(), apiVersion, "") + adapterInternalAPI.Endpoints.HTTP2BackendEnabled = true + cluster, address, err := processEndpoints(clusterName, adapterInternalAPI.Endpoints, timeout, basePath) + if err != nil { + logger.LoggerOasparser.ErrorC(logging.PrintError(logging.Error2239, logging.MAJOR, + "Error while adding grpc endpoints for %s:%v. %v", apiTitle, apiVersion, err.Error())) + return nil, nil, nil, fmt.Errorf("error while adding grpc endpoints for %s:%v. %v", apiTitle, apiVersion, + err.Error()) + } + clusters = append(clusters, cluster) + endpoints = append(endpoints, address...) + + for _, resource := range adapterInternalAPI.GetResources() { + var clusterName string + resourcePath := resource.GetPath() + endpoint := resource.GetEndpoints() + endpoint.HTTP2BackendEnabled = true + basePath := strings.TrimSuffix(endpoint.Endpoints[0].Basepath, "/") + existingClusterName := getExistingClusterName(*endpoint, processedEndpoints) + + if existingClusterName == "" { + clusterName = getClusterName(endpoint.EndpointPrefix, organizationID, vHost, adapterInternalAPI.GetTitle(), apiVersion, resource.GetID()) + cluster, address, err := processEndpoints(clusterName, endpoint, timeout, basePath) + if err != nil { + logger.LoggerOasparser.ErrorC(logging.PrintError(logging.Error2239, logging.MAJOR, "Error while adding resource level endpoints for %s:%v-%v. %v", apiTitle, apiVersion, resourcePath, err.Error())) + } else { + clusters = append(clusters, cluster) + endpoints = append(endpoints, address...) + processedEndpoints[clusterName] = *endpoint + } + } else { + clusterName = existingClusterName + } + // Create resource level interceptor clusters if required + clustersI, endpointsI, operationalReqInterceptors, operationalRespInterceptorVal := createInterceptorResourceClusters(adapterInternalAPI, + interceptorCerts, vHost, organizationID, apiRequestInterceptor, apiResponseInterceptor, resource) + clusters = append(clusters, clustersI...) + endpoints = append(endpoints, endpointsI...) + routeParams := genRouteCreateParams(adapterInternalAPI, resource, vHost, basePath, clusterName, *operationalReqInterceptors, *operationalRespInterceptorVal, organizationID, + false, false) + + routeP, err := createRoutes(routeParams) + if err != nil { + logger.LoggerXds.ErrorC(logging.PrintError(logging.Error2231, logging.MAJOR, + "Error while creating routes for GRPC API %s %s for path: %s Error: %s", adapterInternalAPI.GetTitle(), + adapterInternalAPI.GetVersion(), resource.GetPath(), err.Error())) + return nil, nil, nil, fmt.Errorf("error while creating routes. %v", err) + } + routes = append(routes, routeP...) + if adapterInternalAPI.IsDefaultVersion { + defaultRoutes, errDefaultPath := createRoutes(genRouteCreateParams(adapterInternalAPI, resource, vHost, basePath, clusterName, *operationalReqInterceptors, *operationalRespInterceptorVal, organizationID, + false, true)) + if errDefaultPath != nil { + logger.LoggerXds.ErrorC(logging.PrintError(logging.Error2231, logging.MAJOR, "Error while creating routes for GRPC API %s %s for path: %s Error: %s", adapterInternalAPI.GetTitle(), adapterInternalAPI.GetVersion(), removeFirstOccurrence(resource.GetPath(), adapterInternalAPI.GetVersion()), errDefaultPath.Error())) + return nil, nil, nil, fmt.Errorf("error while creating routes. %v", errDefaultPath) + } + routes = append(routes, defaultRoutes...) + } + + } + + return routes, clusters, endpoints, nil + } for _, resource := range adapterInternalAPI.GetResources() { var clusterName string resourcePath := resource.GetPath() @@ -860,8 +927,14 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error decorator *routev3.Decorator ) if params.createDefaultPath { - xWso2Basepath = removeFirstOccurrence(xWso2Basepath, "/"+version) - resourcePath = removeFirstOccurrence(resource.GetPath(), "/"+version) + //check if basepath is separated from version by a . or / + if strings.Contains(basePath, "."+version) { + xWso2Basepath = removeFirstOccurrence(basePath, "."+version) + resourcePath = removeFirstOccurrence(resource.GetPath(), "."+version) + } else { + xWso2Basepath = removeFirstOccurrence(xWso2Basepath, "/"+version) + resourcePath = removeFirstOccurrence(resource.GetPath(), "/"+version) + } } if pathMatchType != gwapiv1.PathMatchExact { @@ -1058,6 +1131,16 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error rewritePath := generateRoutePathForReWrite(basePath, resourcePath, pathMatchType) action.Route.RegexRewrite = generateRegexMatchAndSubstitute(rewritePath, resourcePath, pathMatchType) + if apiType == "GRPC" { + match.Headers = nil + newRoutePath := "/" + strings.TrimPrefix(resourcePath, basePath+".") + if newRoutePath == "/"+resourcePath { + temp := removeFirstOccurrence(basePath, "."+version) + newRoutePath = "/" + strings.TrimPrefix(resourcePath, temp+".") + } + action.Route.RegexRewrite = generateRegexMatchAndSubstitute(rewritePath, newRoutePath, pathMatchType) + } + route := generateRouteConfig(xWso2Basepath, match, action, nil, decorator, perRouteFilterConfigs, nil, nil, nil, nil) // general headers to add and remove are included in this methods routes = append(routes, route) @@ -1209,8 +1292,14 @@ func CreateAPIDefinitionEndpoint(adapterInternalAPI *model.AdapterInternalAPI, v matchPath := basePath + endpoint if isDefaultversion { - basePathWithoutVersion := removeLastOccurrence(basePath, "/"+version) - matchPath = basePathWithoutVersion + endpoint + if adapterInternalAPI.GetAPIType() == "GRPC" { + basePathWithoutVersion := removeLastOccurrence(basePath, "."+version) + matchPath = basePathWithoutVersion + "/" + vHost + endpoint + } else { + basePathWithoutVersion := removeLastOccurrence(basePath, "/"+version) + matchPath = basePathWithoutVersion + endpoint + + } } matchPath = strings.Replace(matchPath, basePath, regexp.QuoteMeta(basePath), 1) @@ -1466,7 +1555,7 @@ func getUpgradeConfig(apiType string) []*routev3.RouteAction_UpgradeConfig { return upgradeConfig } -func getAPIProperties(apiPropertiesConfig []dpv1alpha2.Property) string { +func getAPIProperties(apiPropertiesConfig []dpv1beta1.Property) string { var apiProperties = make(map[string]string) for _, val := range apiPropertiesConfig { apiProperties[val.Name] = val.Value diff --git a/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go b/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go index a9697dacd..3f64b33f9 100644 --- a/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go +++ b/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go @@ -30,7 +30,7 @@ import ( "github.com/wso2/apk/adapter/internal/operator/synchronizer" operatorutils "github.com/wso2/apk/adapter/internal/operator/utils" "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" - "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" k8types "k8s.io/apimachinery/pkg/types" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -39,16 +39,16 @@ import ( func TestCreateRoutesWithClustersWithExactAndRegularExpressionRules(t *testing.T) { apiState := synchronizer.APIState{} - apiDefinition := v1alpha2.API{ + apiDefinition := v1beta1.API{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "test-api-2", }, - Spec: v1alpha2.APISpec{ + Spec: v1beta1.APISpec{ APIName: "test-api-2", APIVersion: "2.0.0", BasePath: "/test-api/2.0.0", - Production: []v1alpha2.EnvConfig{ + Production: []v1beta1.EnvConfig{ { RouteRefs: []string{ "test-api-2-prod-http-route", @@ -211,16 +211,16 @@ func TestExtractAPIDetailsFromHTTPRouteForSpecificEnvironment(t *testing.T) { func generateSampleAPI(apiName string, apiVersion string, basePath string) synchronizer.APIState { apiState := synchronizer.APIState{} - apiDefinition := v1alpha2.API{ + apiDefinition := v1beta1.API{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: apiName, }, - Spec: v1alpha2.APISpec{ + Spec: v1beta1.APISpec{ APIName: apiName, APIVersion: apiVersion, BasePath: basePath, - Production: []v1alpha2.EnvConfig{ + Production: []v1beta1.EnvConfig{ { RouteRefs: []string{ apiName + "-prod-http-route", @@ -274,16 +274,16 @@ func generateSampleAPI(apiName string, apiVersion string, basePath string) synch // TODO: Fix this test case func TestCreateRoutesWithClustersWithMultiplePathPrefixRules(t *testing.T) { apiState := synchronizer.APIState{} - apiDefinition := v1alpha2.API{ + apiDefinition := v1beta1.API{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "test-api-1", }, - Spec: v1alpha2.APISpec{ + Spec: v1beta1.APISpec{ APIName: "test-api", APIVersion: "1.0.0", BasePath: "/test-api/1.0.0", - Production: []v1alpha2.EnvConfig{ + Production: []v1beta1.EnvConfig{ { RouteRefs: []string{ "test-api-1-prod-http-route", @@ -423,16 +423,16 @@ func TestCreateRoutesWithClustersWithMultiplePathPrefixRules(t *testing.T) { func TestCreateRoutesWithClustersWithBackendTLSConfigs(t *testing.T) { apiState := synchronizer.APIState{} - apiDefinition := v1alpha2.API{ + apiDefinition := v1beta1.API{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "test-api-3", }, - Spec: v1alpha2.APISpec{ + Spec: v1beta1.APISpec{ APIName: "test-api-3", APIVersion: "1.0.0", BasePath: "/test-api-3/1.0.0", - Production: []v1alpha2.EnvConfig{ + Production: []v1beta1.EnvConfig{ { RouteRefs: []string{ "test-api-3-prod-http-route", @@ -546,16 +546,16 @@ func TestCreateHealthEndpoint(t *testing.T) { func TestCreateRoutesWithClustersDifferentBackendRefs(t *testing.T) { apiState := synchronizer.APIState{} - apiDefinition := v1alpha2.API{ + apiDefinition := v1beta1.API{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "test-api-different-backendrefs", }, - Spec: v1alpha2.APISpec{ + Spec: v1beta1.APISpec{ APIName: "test-api-different-backendrefs", APIVersion: "1.0.0", BasePath: "/test-api-different-backendrefs/1.0.0", - Production: []v1alpha2.EnvConfig{ + Production: []v1beta1.EnvConfig{ { RouteRefs: []string{ "test-api-different-backendrefs-prod-http-route", @@ -638,16 +638,16 @@ func TestCreateRoutesWithClustersDifferentBackendRefs(t *testing.T) { func TestCreateRoutesWithClustersSameBackendRefs(t *testing.T) { apiState := synchronizer.APIState{} - apiDefinition := v1alpha2.API{ + apiDefinition := v1beta1.API{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "test-api-same-backendrefs", }, - Spec: v1alpha2.APISpec{ + Spec: v1beta1.APISpec{ APIName: "test-api-same-backendrefs", APIVersion: "1.0.0", BasePath: "/test-api-same-backendrefs/1.0.0", - Production: []v1alpha2.EnvConfig{ + Production: []v1beta1.EnvConfig{ { RouteRefs: []string{ "test-api-same-backendrefs-prod-http-route", diff --git a/adapter/internal/oasparser/model/adapter_internal_api.go b/adapter/internal/oasparser/model/adapter_internal_api.go index a5318d66a..50352a987 100644 --- a/adapter/internal/oasparser/model/adapter_internal_api.go +++ b/adapter/internal/oasparser/model/adapter_internal_api.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "net/url" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" "strconv" "strings" "time" @@ -33,6 +34,7 @@ import ( "github.com/wso2/apk/adapter/internal/operator/utils" dpv1alpha1 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "golang.org/x/exp/maps" "k8s.io/apimachinery/pkg/types" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -72,7 +74,7 @@ type AdapterInternalAPI struct { apiDefinitionFile []byte apiDefinitionEndpoint string subscriptionValidation bool - APIProperties []dpv1alpha2.Property + APIProperties []dpv1beta1.Property // GraphQLSchema string // GraphQLComplexities GraphQLComplexityYaml IsSystemAPI bool @@ -940,6 +942,182 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoGQLRouteCR(gqlRoute *dpv1al return nil } +// SetInfoGRPCRouteCR populates resources and endpoints of adapterInternalAPI. httpRoute.Spec.Rules.Matches +// are used to create resources and httpRoute.Spec.Rules.BackendRefs are used to create EndpointClusters. +func (adapterInternalAPI *AdapterInternalAPI) SetInfoGRPCRouteCR(grpcRoute *gwapiv1a2.GRPCRoute, resourceParams ResourceParams) error { + var resources []*Resource + outputAuthScheme := utils.TieBreaker(utils.GetPtrSlice(maps.Values(resourceParams.AuthSchemes))) + outputAPIPolicy := utils.TieBreaker(utils.GetPtrSlice(maps.Values(resourceParams.APIPolicies))) + outputRatelimitPolicy := utils.TieBreaker(utils.GetPtrSlice(maps.Values(resourceParams.RateLimitPolicies))) + + disableScopes := true + config := config.ReadConfigs() + + var authScheme *dpv1alpha2.Authentication + if outputAuthScheme != nil { + authScheme = *outputAuthScheme + } + var apiPolicy *dpv1alpha2.APIPolicy + if outputAPIPolicy != nil { + apiPolicy = *outputAPIPolicy + } + var ratelimitPolicy *dpv1alpha1.RateLimitPolicy + if outputRatelimitPolicy != nil { + ratelimitPolicy = *outputRatelimitPolicy + } + + //We are only supporting one backend for now + backend := grpcRoute.Spec.Rules[0].BackendRefs[0] + backendName := types.NamespacedName{ + Name: string(backend.Name), + Namespace: utils.GetNamespace(backend.Namespace, grpcRoute.Namespace), + } + resolvedBackend, ok := resourceParams.BackendMapping[backendName.String()] + if ok { + endpointConfig := &EndpointConfig{} + if resolvedBackend.CircuitBreaker != nil { + endpointConfig.CircuitBreakers = &CircuitBreakers{ + MaxConnections: int32(resolvedBackend.CircuitBreaker.MaxConnections), + MaxRequests: int32(resolvedBackend.CircuitBreaker.MaxRequests), + MaxPendingRequests: int32(resolvedBackend.CircuitBreaker.MaxPendingRequests), + MaxRetries: int32(resolvedBackend.CircuitBreaker.MaxRetries), + MaxConnectionPools: int32(resolvedBackend.CircuitBreaker.MaxConnectionPools), + } + } + if resolvedBackend.Timeout != nil { + endpointConfig.TimeoutInMillis = resolvedBackend.Timeout.UpstreamResponseTimeout * 1000 + endpointConfig.IdleTimeoutInSeconds = resolvedBackend.Timeout.DownstreamRequestIdleTimeout + } + if resolvedBackend.Retry != nil { + statusCodes := config.Envoy.Upstream.Retry.StatusCodes + if len(resolvedBackend.Retry.StatusCodes) > 0 { + statusCodes = resolvedBackend.Retry.StatusCodes + } + endpointConfig.RetryConfig = &RetryConfig{ + Count: int32(resolvedBackend.Retry.Count), + StatusCodes: statusCodes, + BaseIntervalInMillis: int32(resolvedBackend.Retry.BaseIntervalMillis), + } + } + adapterInternalAPI.Endpoints = &EndpointCluster{ + Endpoints: GetEndpoints(backendName, resourceParams.BackendMapping), + Config: endpointConfig, + } + if resolvedBackend.HealthCheck != nil { + adapterInternalAPI.Endpoints.HealthCheck = &HealthCheck{ + Interval: resolvedBackend.HealthCheck.Interval, + Timeout: resolvedBackend.HealthCheck.Timeout, + UnhealthyThreshold: resolvedBackend.HealthCheck.UnhealthyThreshold, + HealthyThreshold: resolvedBackend.HealthCheck.HealthyThreshold, + } + } + + var securityConfig []EndpointSecurity + switch resolvedBackend.Security.Type { + case "Basic": + securityConfig = append(securityConfig, EndpointSecurity{ + Password: string(resolvedBackend.Security.Basic.Password), + Username: string(resolvedBackend.Security.Basic.Username), + Type: string(resolvedBackend.Security.Type), + Enabled: true, + }) + } + adapterInternalAPI.EndpointSecurity = utils.GetPtrSlice(securityConfig) + } else { + return fmt.Errorf("backend: %s has not been resolved", backendName) + } + + for _, rule := range grpcRoute.Spec.Rules { + var policies = OperationPolicies{} + var endPoints []Endpoint + resourceAuthScheme := authScheme + resourceRatelimitPolicy := ratelimitPolicy + var scopes []string + for _, filter := range rule.Filters { + if filter.ExtensionRef != nil && filter.ExtensionRef.Kind == constants.KindAuthentication { + if ref, found := resourceParams.ResourceAuthSchemes[types.NamespacedName{ + Name: string(filter.ExtensionRef.Name), + Namespace: grpcRoute.Namespace, + }.String()]; found { + resourceAuthScheme = concatAuthSchemes(authScheme, &ref) + } else { + return fmt.Errorf(`auth scheme: %s has not been resolved, spec.targetRef.kind should be + 'Resource' in resource level Authentications`, filter.ExtensionRef.Name) + } + } + if filter.ExtensionRef != nil && filter.ExtensionRef.Kind == constants.KindScope { + if ref, found := resourceParams.ResourceScopes[types.NamespacedName{ + Name: string(filter.ExtensionRef.Name), + Namespace: grpcRoute.Namespace, + }.String()]; found { + scopes = ref.Spec.Names + disableScopes = false + } else { + return fmt.Errorf("scope: %s has not been resolved in namespace %s", filter.ExtensionRef.Name, grpcRoute.Namespace) + } + } + if filter.ExtensionRef != nil && filter.ExtensionRef.Kind == constants.KindRateLimitPolicy { + if ref, found := resourceParams.ResourceRateLimitPolicies[types.NamespacedName{ + Name: string(filter.ExtensionRef.Name), + Namespace: grpcRoute.Namespace, + }.String()]; found { + resourceRatelimitPolicy = concatRateLimitPolicies(ratelimitPolicy, &ref) + } else { + return fmt.Errorf(`ratelimitpolicy: %s has not been resolved, spec.targetRef.kind should be + 'Resource' in resource level RateLimitPolicies`, filter.ExtensionRef.Name) + } + } + } + resourceAuthScheme = concatAuthSchemes(resourceAuthScheme, nil) + resourceRatelimitPolicy = concatRateLimitPolicies(resourceRatelimitPolicy, nil) + + loggers.LoggerOasparser.Debugf("Calculating auths for API ..., API_UUID = %v", adapterInternalAPI.UUID) + apiAuth := getSecurity(resourceAuthScheme) + + for _, match := range rule.Matches { + resourcePath := adapterInternalAPI.GetXWso2Basepath() + "." + *match.Method.Service + "/" + *match.Method.Method + endPoints = append(endPoints, GetEndpoints(backendName, resourceParams.BackendMapping)...) + resource := &Resource{path: resourcePath, pathMatchType: "Exact", + methods: []*Operation{{iD: uuid.New().String(), method: "post", policies: policies, + auth: apiAuth, rateLimitPolicy: parseRateLimitPolicyToInternal(resourceRatelimitPolicy), scopes: scopes}}, + iD: uuid.New().String(), + } + endpoints := GetEndpoints(backendName, resourceParams.BackendMapping) + resource.endpoints = &EndpointCluster{ + Endpoints: endpoints, + } + resources = append(resources, resource) + } + } + + ratelimitPolicy = concatRateLimitPolicies(ratelimitPolicy, nil) + apiPolicy = concatAPIPolicies(apiPolicy, nil) + authScheme = concatAuthSchemes(authScheme, nil) + + adapterInternalAPI.RateLimitPolicy = parseRateLimitPolicyToInternal(ratelimitPolicy) + adapterInternalAPI.resources = resources + adapterInternalAPI.xWso2Cors = getCorsConfigFromAPIPolicy(apiPolicy) + if authScheme.Spec.Override != nil && authScheme.Spec.Override.Disabled != nil { + adapterInternalAPI.disableAuthentications = *authScheme.Spec.Override.Disabled + } + authSpec := utils.SelectPolicy(&authScheme.Spec.Override, &authScheme.Spec.Default, nil, nil) + if authSpec != nil && authSpec.AuthTypes != nil && authSpec.AuthTypes.Oauth2.Required != "" { + adapterInternalAPI.SetXWSO2ApplicationSecurity(authSpec.AuthTypes.Oauth2.Required == "mandatory") + } else { + adapterInternalAPI.SetXWSO2ApplicationSecurity(true) + } + adapterInternalAPI.disableScopes = disableScopes + // Check whether the API has a backend JWT token + if apiPolicy != nil && apiPolicy.Spec.Override != nil && apiPolicy.Spec.Override.BackendJWTPolicy != nil { + backendJWTPolicy := resourceParams.BackendJWTMapping[types.NamespacedName{ + Name: apiPolicy.Spec.Override.BackendJWTPolicy.Name, + Namespace: grpcRoute.Namespace, + }.String()].Spec + adapterInternalAPI.backendJWTTokenInfo = parseBackendJWTTokenToInternal(backendJWTPolicy) + } + return nil +} + func (endpoint *Endpoint) validateEndpoint() error { if endpoint.Port == 0 || endpoint.Port > 65535 { return errors.New("endpoint port value should be between 0 and 65535") diff --git a/adapter/internal/oasparser/model/common.go b/adapter/internal/oasparser/model/common.go index d1d3ba664..8c5c2f54c 100644 --- a/adapter/internal/oasparser/model/common.go +++ b/adapter/internal/oasparser/model/common.go @@ -108,7 +108,7 @@ func getHostandBasepathandPort(apiType string, rawURL string) (*Endpoint, error) rawURL = strings.Trim(rawURL, " ") if !strings.Contains(rawURL, "://") { - if apiType == constants.REST || apiType == constants.GRAPHQL { + if apiType == constants.REST || apiType == constants.GRAPHQL || apiType == constants.GRPC { rawURL = "http://" + rawURL } else if apiType == constants.WS { rawURL = "ws://" + rawURL diff --git a/adapter/internal/oasparser/model/http_route.go b/adapter/internal/oasparser/model/http_route.go index 58bdeebde..1bffff0f5 100644 --- a/adapter/internal/oasparser/model/http_route.go +++ b/adapter/internal/oasparser/model/http_route.go @@ -24,6 +24,7 @@ import ( "github.com/wso2/apk/adapter/internal/operator/utils" dpv1alpha1 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "k8s.io/apimachinery/pkg/types" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) @@ -309,7 +310,7 @@ func getAllowedOperations(httpMethod *gwapiv1.HTTPMethod, policies OperationPoli } // SetInfoAPICR populates ID, ApiType, Version and XWso2BasePath of adapterInternalAPI. -func (swagger *AdapterInternalAPI) SetInfoAPICR(api dpv1alpha2.API) { +func (swagger *AdapterInternalAPI) SetInfoAPICR(api dpv1beta1.API) { swagger.UUID = string(api.ObjectMeta.UID) swagger.title = api.Spec.APIName swagger.apiType = api.Spec.APIType diff --git a/adapter/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml b/adapter/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml index fc4e0a2a9..212b5237e 100644 --- a/adapter/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml +++ b/adapter/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml @@ -72,7 +72,7 @@ spec: type: array apiType: description: APIType denotes the type of the API. Possible values - could be REST, GraphQL, Async + could be REST, GraphQL, GRPC Async enum: - REST type: string @@ -244,10 +244,11 @@ spec: type: array apiType: description: APIType denotes the type of the API. Possible values - could be REST, GraphQL, Async + could be REST, GraphQL, GRPC Async enum: - REST - GraphQL + - GRPC type: string apiVersion: description: APIVersion is the version number of the API. @@ -361,6 +362,184 @@ spec: type: object type: object served: true - storage: true + storage: false subresources: status: {} + - additionalPrinterColumns: + - jsonPath: .spec.apiName + name: API Name + type: string + - jsonPath: .spec.apiVersion + name: Version + type: string + - jsonPath: .spec.basePath + name: BasePath + type: string + - jsonPath: .spec.organization + name: Organization + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: API is the Schema for the apis API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APISpec defines the desired state of API + properties: + apiName: + description: APIName is the unique name of the API can be used to + uniquely identify an API. + maxLength: 60 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&$\[\]\/]*$ + type: string + apiProperties: + description: APIProperties denotes the custom properties of the API. + items: + description: Property holds key value pair of APIProperties + properties: + name: + type: string + value: + type: string + type: object + nullable: true + type: array + apiType: + description: APIType denotes the type of the API. Possible values + could be REST, GraphQL, GRPC Async + enum: + - REST + - GraphQL + - GRPC + type: string + apiVersion: + description: APIVersion is the version number of the API. + maxLength: 30 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&/$\[\]\s+\/]+$ + type: string + basePath: + description: 'BasePath denotes the basepath of the API. e.g: /pet-store-api/1.0.6' + pattern: ^[/][a-zA-Z0-9~/_.-]*$ + type: string + definitionFileRef: + description: DefinitionFileRef contains the OpenAPI 3 or SDL file + in gzipped format. definition of the API in a ConfigMap. + type: string + definitionPath: + default: /api-definition + description: DefinitionPath contains the path to expose the API definition. + minLength: 1 + type: string + environment: + description: Environment denotes the environment of the API. + nullable: true + type: string + isDefaultVersion: + description: IsDefaultVersion indicates whether this API version should + be used as a default API + type: boolean + organization: + description: Organization denotes the organization. related to the + API + type: string + production: + description: 'Production contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + httpRouteRefs: + description: HTTPRouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - httpRouteRefs + type: object + maxItems: 1 + nullable: true + type: array + sandbox: + description: 'Sandbox contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + httpRouteRefs: + description: HTTPRouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - httpRouteRefs + type: object + maxItems: 1 + nullable: true + type: array + systemAPI: + description: SystemAPI denotes if it is an internal system API. + type: boolean + required: + - apiName + - apiType + - apiVersion + - basePath + - definitionPath + type: object + status: + description: APIStatus defines the observed state of API + properties: + deploymentStatus: + description: DeploymentStatus denotes the deployment status of the + API + properties: + accepted: + description: Accepted represents whether the API is accepted or + not. + type: boolean + events: + description: Events contains a list of events related to the API. + items: + type: string + type: array + message: + description: Message represents a user friendly message that explains + the current state of the API. + type: string + status: + description: Status denotes the state of the API in its lifecycle. + Possible values could be Accepted, Invalid, Deploy etc. + type: string + transitionTime: + description: TransitionTime represents the last known transition + timestamp. + format: date-time + type: string + required: + - accepted + - status + - transitionTime + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/adapter/internal/operator/controllers/dp/api_controller.go b/adapter/internal/operator/controllers/dp/api_controller.go index 0c13b4570..3b530d933 100644 --- a/adapter/internal/operator/controllers/dp/api_controller.go +++ b/adapter/internal/operator/controllers/dp/api_controller.go @@ -26,6 +26,7 @@ import ( "encoding/json" "errors" "fmt" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "io/ioutil" "reflect" "sort" @@ -54,6 +55,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" ctrl "sigs.k8s.io/controller-runtime" @@ -67,6 +69,7 @@ import ( ) const ( + grpcRouteAPIIndex = "grpcRouteAPIIndex" httpRouteAPIIndex = "httpRouteAPIIndex" gqlRouteAPIIndex = "gqlRouteAPIIndex" // apiAuthenticationIndex Index for API level authentications @@ -79,6 +82,8 @@ const ( apiRateLimitResourceIndex = "apiRateLimitResourceIndex" // gatewayHTTPRouteIndex Index for gateway httproutes gatewayHTTPRouteIndex = "gatewayHTTPRouteIndex" + // gatewayGRPCRouteIndex Index for gateway grpcroutes + gatewayGRPCRouteIndex = "gatewayGRPCRouteIndex" // apiAPIPolicyIndex Index for API level apipolicies apiAPIPolicyIndex = "apiAPIPolicyIndex" // apiAPIPolicyResourceIndex Index for resource level apipolicies @@ -86,6 +91,7 @@ const ( serviceHTTPRouteIndex = "serviceHTTPRouteIndex" httprouteScopeIndex = "httprouteScopeIndex" gqlRouteScopeIndex = "gqlRouteScopeIndex" + grpcRouteScopeIndex = "grpcRouteScopeIndex" configMapBackend = "configMapBackend" configMapAPIDefinition = "configMapAPIDefinition" secretBackend = "secretBackend" @@ -93,6 +99,7 @@ const ( secretAuthentication = "secretAuthentication" backendHTTPRouteIndex = "backendHTTPRouteIndex" backendGQLRouteIndex = "backendGQLRouteIndex" + backendGRPCRouteIndex = "backendGRPCRouteIndex" interceptorServiceAPIPolicyIndex = "interceptorServiceAPIPolicyIndex" backendInterceptorServiceIndex = "backendInterceptorServiceIndex" backendJWTAPIPolicyIndex = "backendJWTAPIPolicyIndex" @@ -113,7 +120,7 @@ type APIReconciler struct { apiPropagationEnabled bool } -// NewAPIController creates a new API controller instance. API Controllers watches for dpv1alpha2.API and gwapiv1b1.HTTPRoute. +// NewAPIController creates a new API controller instance. API Controllers watches for dpv1beta1.API and gwapiv1b1.HTTPRoute. func NewAPIController(mgr manager.Manager, operatorDataStore *synchronizer.OperatorDataStore, statusUpdater *status.UpdateHandler, ch *chan *synchronizer.APIEvent, successChannel *chan synchronizer.SuccessEvent) error { apiReconciler := &APIReconciler{ @@ -135,7 +142,7 @@ func NewAPIController(mgr manager.Manager, operatorDataStore *synchronizer.Opera apiReconciler.apiPropagationEnabled = conf.Adapter.ControlPlane.EnableAPIPropagation predicates := []predicate.Predicate{predicate.NewPredicateFuncs(utils.FilterByNamespaces(conf.Adapter.Operator.Namespaces))} - if err := c.Watch(source.Kind(mgr.GetCache(), &dpv1alpha2.API{}), &handler.EnqueueRequestForObject{}, + if err := c.Watch(source.Kind(mgr.GetCache(), &dpv1beta1.API{}), &handler.EnqueueRequestForObject{}, predicates...); err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2611, logging.BLOCKER, "Error watching API resources: %v", err)) return err @@ -157,6 +164,13 @@ func NewAPIController(mgr manager.Manager, operatorDataStore *synchronizer.Opera return err } + if err := c.Watch(source.Kind(mgr.GetCache(), &gwapiv1a2.GRPCRoute{}), handler.EnqueueRequestsFromMapFunc(apiReconciler.populateAPIReconcileRequestsForGRPCRoute), + predicates...); err != nil { + //TODO change the error number + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2667, logging.BLOCKER, "Error watching GRPCRoute resources: %v", err)) + return err + } + if err := c.Watch(source.Kind(mgr.GetCache(), &gwapiv1b1.Gateway{}), handler.EnqueueRequestsFromMapFunc(apiReconciler.getAPIsForGateway), predicates...); err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2611, logging.BLOCKER, "Error watching API resources: %v", err)) @@ -232,6 +246,9 @@ func NewAPIController(mgr manager.Manager, operatorDataStore *synchronizer.Opera // +kubebuilder:rbac:groups=dp.wso2.com,resources=gqlroutes,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=dp.wso2.com,resources=gqlroutes/status,verbs=get;update;patch // +kubebuilder:rbac:groups=dp.wso2.com,resources=gqlroutes/finalizers,verbs=update +// +kubebuilder:rbac:groups=dp.wso2.com,resources=grpcroutes,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=dp.wso2.com,resources=grpcroutes/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=dp.wso2.com,resources=grpcroutes/finalizers,verbs=update // +kubebuilder:rbac:groups=dp.wso2.com,resources=authentications,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=dp.wso2.com,resources=authentications/status,verbs=get;update;patch // +kubebuilder:rbac:groups=dp.wso2.com,resources=authentications/finalizers,verbs=update @@ -254,7 +271,7 @@ func (apiReconciler *APIReconciler) Reconcile(ctx context.Context, req ctrl.Requ applyAllAPIsOnce.Do(apiReconciler.applyStartupAPIs) loggers.LoggerAPKOperator.Infof("Reconciling for API %s", req.NamespacedName.String()) // Check whether the API CR exist, if not consider as a DELETE event. - var apiCR dpv1alpha2.API + var apiCR dpv1beta1.API if err := apiReconciler.client.Get(ctx, req.NamespacedName, &apiCR); err != nil { apiState, found := apiReconciler.ods.GetCachedAPI(req.NamespacedName) if found && k8error.IsNotFound(err) { @@ -321,7 +338,7 @@ func (apiReconciler *APIReconciler) applyStartupAPIs() { // resolveAPIRefs validates following references related to the API // - HTTPRoutes -func (apiReconciler *APIReconciler) resolveAPIRefs(ctx context.Context, api dpv1alpha2.API) (*synchronizer.APIEvent, error) { +func (apiReconciler *APIReconciler) resolveAPIRefs(ctx context.Context, api dpv1beta1.API) (*synchronizer.APIEvent, error) { var prodRouteRefs, sandRouteRefs []string if len(api.Spec.Production) > 0 { prodRouteRefs = api.Spec.Production[0].RouteRefs @@ -419,6 +436,24 @@ func (apiReconciler *APIReconciler) resolveAPIRefs(ctx context.Context, api dpv1 } } + //handle grpc apis + if len(prodRouteRefs) > 0 && apiState.APIDefinition.Spec.APIType == "GRPC" { + apiState.ProdGRPCRoute = &synchronizer.GRPCRouteState{} + if apiState.ProdGRPCRoute, err = apiReconciler.resolveGRPCRouteRefs(ctx, prodRouteRefs, + namespace, api); err != nil { + return nil, fmt.Errorf("error while resolving production grpcRouteref %s in namespace :%s has not found. %s", + prodRouteRefs, namespace, err.Error()) + } + } + if len(sandRouteRefs) > 0 && apiState.APIDefinition.Spec.APIType == "GRPC" { + apiState.SandGRPCRoute = &synchronizer.GRPCRouteState{} + if apiState.SandGRPCRoute, err = apiReconciler.resolveGRPCRouteRefs(ctx, sandRouteRefs, + namespace, api); err != nil { + return nil, fmt.Errorf("error while resolving sandbox grpcRouteref %s in namespace :%s has not found. %s", + sandRouteRefs, namespace, err.Error()) + } + } + // handle gql apis if len(prodRouteRefs) > 0 && apiState.APIDefinition.Spec.APIType == "GraphQL" { if apiState.ProdGQLRoute, err = apiReconciler.resolveGQLRouteRefs(ctx, prodRouteRefs, namespace, @@ -495,6 +530,9 @@ func (apiReconciler *APIReconciler) resolveAPIRefs(ctx context.Context, api dpv1 func isAPIPropagatable(apiState *synchronizer.APIState) bool { validOrgs := []string{"carbon.super"} + if apiState.APIDefinition.Spec.APIType == "GRPC" { + return false + } // System APIs should not be propagated to CP if apiState.APIDefinition.Spec.SystemAPI { return false @@ -507,7 +545,7 @@ func isAPIPropagatable(apiState *synchronizer.APIState) bool { } func (apiReconciler *APIReconciler) resolveGQLRouteRefs(ctx context.Context, gqlRouteRefs []string, - namespace string, api dpv1alpha2.API) (*synchronizer.GQLRouteState, error) { + namespace string, api dpv1beta1.API) (*synchronizer.GQLRouteState, error) { gqlRouteState, err := apiReconciler.concatGQLRoutes(ctx, gqlRouteRefs, namespace, api) if err != nil { return nil, err @@ -516,11 +554,21 @@ func (apiReconciler *APIReconciler) resolveGQLRouteRefs(ctx context.Context, gql return &gqlRouteState, err } +func (apiReconciler *APIReconciler) resolveGRPCRouteRefs(ctx context.Context, grpcRouteRefs []string, + namespace string, api dpv1beta1.API) (*synchronizer.GRPCRouteState, error) { + grpcRouteState, err := apiReconciler.concatGRPCRoutes(ctx, grpcRouteRefs, namespace, api) + if err != nil { + return nil, err + } + grpcRouteState.Scopes, err = apiReconciler.getScopesForGRPCRoute(ctx, grpcRouteState.GRPCRouteCombined, api) + return &grpcRouteState, err +} + // resolveHTTPRouteRefs validates following references related to the API // - Authentications func (apiReconciler *APIReconciler) resolveHTTPRouteRefs(ctx context.Context, httpRouteState *synchronizer.HTTPRouteState, httpRouteRefs []string, namespace string, interceptorServiceMapping map[string]dpv1alpha1.InterceptorService, - api dpv1alpha2.API) (*synchronizer.HTTPRouteState, error) { + api dpv1beta1.API) (*synchronizer.HTTPRouteState, error) { var err error httpRouteState.HTTPRouteCombined, httpRouteState.HTTPRoutePartitions, err = apiReconciler.concatHTTPRoutes(ctx, httpRouteRefs, namespace, api) if err != nil { @@ -534,9 +582,43 @@ func (apiReconciler *APIReconciler) resolveHTTPRouteRefs(ctx context.Context, ht return httpRouteState, err } +func (apiReconciler *APIReconciler) concatGRPCRoutes(ctx context.Context, grpcRouteRefs []string, + namespace string, api dpv1beta1.API) (synchronizer.GRPCRouteState, error) { + grpcRouteState := synchronizer.GRPCRouteState{} + grpcRoutePartitions := make(map[string]*gwapiv1a2.GRPCRoute) + for _, grpcRouteRef := range grpcRouteRefs { + var grpcRoute gwapiv1a2.GRPCRoute + namespacedName := types.NamespacedName{Namespace: namespace, Name: grpcRouteRef} + if err := utils.ResolveRef(ctx, apiReconciler.client, &api, namespacedName, true, &grpcRoute); err != nil { + return grpcRouteState, fmt.Errorf("error while getting grpcroute %s in namespace :%s, %s", grpcRouteRef, + namespace, err.Error()) + } + grpcRoutePartitions[namespacedName.String()] = &grpcRoute + if grpcRouteState.GRPCRouteCombined == nil { + grpcRouteState.GRPCRouteCombined = &grpcRoute + } else { + grpcRouteState.GRPCRouteCombined.Spec.Rules = append(grpcRouteState.GRPCRouteCombined.Spec.Rules, + grpcRoute.Spec.Rules...) + } + } + grpcRouteState.GRPCRoutePartitions = grpcRoutePartitions + backendNamespacedName := types.NamespacedName{ + //TODO check if this is correct + Name: string(grpcRouteState.GRPCRouteCombined.Spec.Rules[0].BackendRefs[0].BackendRef.Name), + Namespace: namespace, + } + resolvedBackend := utils.GetResolvedBackend(ctx, apiReconciler.client, backendNamespacedName, &api) + if resolvedBackend != nil { + grpcRouteState.BackendMapping = map[string]*dpv1alpha1.ResolvedBackend{ + backendNamespacedName.String(): resolvedBackend, + } + return grpcRouteState, nil + } + return grpcRouteState, errors.New("error while resolving backend for grpcroute") +} func (apiReconciler *APIReconciler) concatGQLRoutes(ctx context.Context, gqlRouteRefs []string, - namespace string, api dpv1alpha2.API) (synchronizer.GQLRouteState, error) { + namespace string, api dpv1beta1.API) (synchronizer.GQLRouteState, error) { gqlRouteState := synchronizer.GQLRouteState{} gqlRoutePartitions := make(map[string]*dpv1alpha2.GQLRoute) for _, gqlRouteRef := range gqlRouteRefs { @@ -570,7 +652,7 @@ func (apiReconciler *APIReconciler) concatGQLRoutes(ctx context.Context, gqlRout } func (apiReconciler *APIReconciler) concatHTTPRoutes(ctx context.Context, httpRouteRefs []string, - namespace string, api dpv1alpha2.API) (*gwapiv1b1.HTTPRoute, map[string]*gwapiv1b1.HTTPRoute, error) { + namespace string, api dpv1beta1.API) (*gwapiv1b1.HTTPRoute, map[string]*gwapiv1b1.HTTPRoute, error) { var combinedHTTPRoute *gwapiv1b1.HTTPRoute httpRoutePartitions := make(map[string]*gwapiv1b1.HTTPRoute) for _, httpRouteRef := range httpRouteRefs { @@ -591,7 +673,7 @@ func (apiReconciler *APIReconciler) concatHTTPRoutes(ctx context.Context, httpRo } func (apiReconciler *APIReconciler) getAuthenticationsForAPI(ctx context.Context, - api dpv1alpha2.API) (map[string]dpv1alpha2.Authentication, error) { + api dpv1beta1.API) (map[string]dpv1alpha2.Authentication, error) { nameSpacedName := utils.NamespacedName(&api).String() authentications := make(map[string]dpv1alpha2.Authentication) authenticationList := &dpv1alpha2.AuthenticationList{} @@ -608,7 +690,7 @@ func (apiReconciler *APIReconciler) getAuthenticationsForAPI(ctx context.Context } func (apiReconciler *APIReconciler) getRatelimitPoliciesForAPI(ctx context.Context, - api dpv1alpha2.API) (map[string]dpv1alpha1.RateLimitPolicy, error) { + api dpv1beta1.API) (map[string]dpv1alpha1.RateLimitPolicy, error) { nameSpacedName := utils.NamespacedName(&api).String() ratelimitPolicies := make(map[string]dpv1alpha1.RateLimitPolicy) ratelimitPolicyList := &dpv1alpha1.RateLimitPolicyList{} @@ -623,9 +705,27 @@ func (apiReconciler *APIReconciler) getRatelimitPoliciesForAPI(ctx context.Conte } return ratelimitPolicies, nil } - +func (apiReconciler *APIReconciler) getScopesForGRPCRoute(ctx context.Context, + grpcRoute *gwapiv1a2.GRPCRoute, api dpv1beta1.API) (map[string]dpv1alpha1.Scope, error) { + scopes := make(map[string]dpv1alpha1.Scope) + for _, rule := range grpcRoute.Spec.Rules { + for _, filter := range rule.Filters { + if filter.ExtensionRef != nil && filter.ExtensionRef.Kind == constants.KindScope { + scope := &dpv1alpha1.Scope{} + if err := utils.ResolveRef(ctx, apiReconciler.client, &api, + types.NamespacedName{Namespace: grpcRoute.Namespace, Name: string(filter.ExtensionRef.Name)}, false, + scope); err != nil { + return nil, fmt.Errorf("error while getting scope %s in namespace :%s, %s", filter.ExtensionRef.Name, + grpcRoute.Namespace, err.Error()) + } + scopes[utils.NamespacedName(scope).String()] = *scope + } + } + } + return scopes, nil +} func (apiReconciler *APIReconciler) getScopesForGQLRoute(ctx context.Context, - gqlRoute *dpv1alpha2.GQLRoute, api dpv1alpha2.API) (map[string]dpv1alpha1.Scope, error) { + gqlRoute *dpv1alpha2.GQLRoute, api dpv1beta1.API) (map[string]dpv1alpha1.Scope, error) { scopes := make(map[string]dpv1alpha1.Scope) for _, rule := range gqlRoute.Spec.Rules { for _, filter := range rule.Filters { @@ -645,7 +745,7 @@ func (apiReconciler *APIReconciler) getScopesForGQLRoute(ctx context.Context, } func (apiReconciler *APIReconciler) getScopesForHTTPRoute(ctx context.Context, - httpRoute *gwapiv1b1.HTTPRoute, api dpv1alpha2.API) (map[string]dpv1alpha1.Scope, error) { + httpRoute *gwapiv1b1.HTTPRoute, api dpv1beta1.API) (map[string]dpv1alpha1.Scope, error) { scopes := make(map[string]dpv1alpha1.Scope) for _, rule := range httpRoute.Spec.Rules { for _, filter := range rule.Filters { @@ -667,7 +767,7 @@ func (apiReconciler *APIReconciler) getScopesForHTTPRoute(ctx context.Context, } func (apiReconciler *APIReconciler) getAuthenticationsForResources(ctx context.Context, - api dpv1alpha2.API) (map[string]dpv1alpha2.Authentication, error) { + api dpv1beta1.API) (map[string]dpv1alpha2.Authentication, error) { nameSpacedName := utils.NamespacedName(&api).String() authentications := make(map[string]dpv1alpha2.Authentication) authenticationList := &dpv1alpha2.AuthenticationList{} @@ -684,7 +784,7 @@ func (apiReconciler *APIReconciler) getAuthenticationsForResources(ctx context.C } func (apiReconciler *APIReconciler) getRatelimitPoliciesForResources(ctx context.Context, - api dpv1alpha2.API) (map[string]dpv1alpha1.RateLimitPolicy, error) { + api dpv1beta1.API) (map[string]dpv1alpha1.RateLimitPolicy, error) { nameSpacedName := utils.NamespacedName(&api).String() ratelimitpolicies := make(map[string]dpv1alpha1.RateLimitPolicy) ratelimitPolicyList := &dpv1alpha1.RateLimitPolicyList{} @@ -700,7 +800,7 @@ func (apiReconciler *APIReconciler) getRatelimitPoliciesForResources(ctx context return ratelimitpolicies, nil } -func (apiReconciler *APIReconciler) getAPIPoliciesForAPI(ctx context.Context, api dpv1alpha2.API) (map[string]dpv1alpha2.APIPolicy, error) { +func (apiReconciler *APIReconciler) getAPIPoliciesForAPI(ctx context.Context, api dpv1beta1.API) (map[string]dpv1alpha2.APIPolicy, error) { nameSpacedName := utils.NamespacedName(&api).String() apiPolicies := make(map[string]dpv1alpha2.APIPolicy) apiPolicyList := &dpv1alpha2.APIPolicyList{} @@ -717,7 +817,7 @@ func (apiReconciler *APIReconciler) getAPIPoliciesForAPI(ctx context.Context, ap } func (apiReconciler *APIReconciler) getAPIDefinitionForAPI(ctx context.Context, - apiDefinitionFile, namespace string, api dpv1alpha2.API) ([]byte, error) { + apiDefinitionFile, namespace string, api dpv1beta1.API) ([]byte, error) { configMap := &corev1.ConfigMap{} if err := utils.ResolveRef(ctx, apiReconciler.client, &api, types.NamespacedName{Namespace: namespace, Name: apiDefinitionFile}, true, configMap); err != nil { @@ -734,7 +834,7 @@ func (apiReconciler *APIReconciler) getAPIDefinitionForAPI(ctx context.Context, } func (apiReconciler *APIReconciler) getAPIPoliciesForResources(ctx context.Context, - api dpv1alpha2.API) (map[string]dpv1alpha2.APIPolicy, error) { + api dpv1beta1.API) (map[string]dpv1alpha2.APIPolicy, error) { nameSpacedName := utils.NamespacedName(&api).String() apiPolicies := make(map[string]dpv1alpha2.APIPolicy) apiPolicyList := &dpv1alpha2.APIPolicyList{} @@ -756,7 +856,7 @@ func (apiReconciler *APIReconciler) getAPIPoliciesForResources(ctx context.Conte // - subscription validation func (apiReconciler *APIReconciler) getAPIPolicyChildrenRefs(ctx context.Context, apiPolicies, resourceAPIPolicies map[string]dpv1alpha2.APIPolicy, - api dpv1alpha2.API) (map[string]dpv1alpha1.InterceptorService, map[string]dpv1alpha1.BackendJWT, bool, error) { + api dpv1beta1.API) (map[string]dpv1alpha1.InterceptorService, map[string]dpv1alpha1.BackendJWT, bool, error) { allAPIPolicies := append(maps.Values(apiPolicies), maps.Values(resourceAPIPolicies)...) interceptorServices := make(map[string]dpv1alpha1.InterceptorService) backendJWTs := make(map[string]dpv1alpha1.BackendJWT) @@ -828,7 +928,7 @@ func (apiReconciler *APIReconciler) resolveAuthentications(ctx context.Context, func (apiReconciler *APIReconciler) getResolvedBackendsMapping(ctx context.Context, httpRouteState *synchronizer.HTTPRouteState, interceptorServiceMapping map[string]dpv1alpha1.InterceptorService, - api dpv1alpha2.API) (map[string]*dpv1alpha1.ResolvedBackend, error) { + api dpv1beta1.API) (map[string]*dpv1alpha1.ResolvedBackend, error) { backendMapping := make(map[string]*dpv1alpha1.ResolvedBackend) // Resolve backends in HTTPRoute @@ -876,6 +976,12 @@ func (apiReconciler *APIReconciler) populateAPIReconcileRequestsForHTTPRoute(ctx return requests } +func (apiReconciler *APIReconciler) populateAPIReconcileRequestsForGRPCRoute(ctx context.Context, obj k8client.Object) []reconcile.Request { + requests := apiReconciler.getAPIForGRPCRoute(ctx, obj) + apiReconciler.handleOwnerReference(ctx, obj, &requests) + return requests +} + func (apiReconciler *APIReconciler) populateAPIReconcileRequestsForConfigMap(ctx context.Context, obj k8client.Object) []reconcile.Request { requests := apiReconciler.getAPIsForConfigMap(ctx, obj) apiReconciler.handleOwnerReference(ctx, obj, &requests) @@ -952,6 +1058,16 @@ func (apiReconciler *APIReconciler) traverseAPIStateAndUpdateOwnerReferences(ctx apiReconciler.retriveParentAPIsAndUpdateOwnerReferene(ctx, gqlRoute) } } + if apiState.ProdGRPCRoute != nil { + for _, grpcRoute := range apiState.ProdGRPCRoute.GRPCRoutePartitions { + apiReconciler.retriveParentAPIsAndUpdateOwnerReferene(ctx, grpcRoute) + } + } + if apiState.SandGRPCRoute != nil { + for _, grpcRoute := range apiState.SandGRPCRoute.GRPCRoutePartitions { + apiReconciler.retriveParentAPIsAndUpdateOwnerReferene(ctx, grpcRoute) + } + } for _, auth := range apiState.Authentications { apiReconciler.retriveParentAPIsAndUpdateOwnerReferene(ctx, &auth) } @@ -1001,6 +1117,20 @@ func (apiReconciler *APIReconciler) traverseAPIStateAndUpdateOwnerReferences(ctx } } } + if apiState.ProdGRPCRoute != nil { + for _, backend := range apiState.ProdGRPCRoute.BackendMapping { + if &backend != nil { + apiReconciler.retriveParentAPIsAndUpdateOwnerReferene(ctx, &backend.Backend) + } + } + } + if apiState.SandGRPCRoute != nil { + for _, backend := range apiState.SandGRPCRoute.BackendMapping { + if &backend != nil { + apiReconciler.retriveParentAPIsAndUpdateOwnerReferene(ctx, &backend.Backend) + } + } + } for _, backendJwt := range apiState.BackendJWTMapping { apiReconciler.retriveParentAPIsAndUpdateOwnerReferene(ctx, &backendJwt) } @@ -1142,6 +1272,16 @@ func (apiReconciler *APIReconciler) retriveParentAPIsAndUpdateOwnerReferene(ctx } requests = apiReconciler.getAPIForGQLRoute(ctx, &gqlRoute) apiReconciler.handleOwnerReference(ctx, &gqlRoute, &requests) + case *gwapiv1a2.GRPCRoute: + var grpcRoute gwapiv1a2.GRPCRoute + namespaceName := types.NamespacedName{ + Name: string(obj.GetName()), + Namespace: string(obj.GetNamespace()), + } + if err := apiReconciler.client.Get(ctx, namespaceName, &grpcRoute); err != nil { + loggers.LoggerAPKOperator.Errorf("Unexpected error occured while loading the cr object from cluster %+v", err) + return + } default: loggers.LoggerAPKOperator.Errorf("Unexpected type found while processing owner reference %+v", obj) } @@ -1157,7 +1297,7 @@ func (apiReconciler *APIReconciler) getAPIForGQLRoute(ctx context.Context, obj k loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2665, logging.TRIVIAL, "Unexpected object type, bypassing reconciliation: %v", gqlRoute)) return []reconcile.Request{} } - apiList := &dpv1alpha2.APIList{} + apiList := &dpv1beta1.APIList{} if err := apiReconciler.client.List(ctx, apiList, &k8client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(gqlRouteAPIIndex, utils.NamespacedName(gqlRoute).String()), }); err != nil { @@ -1192,7 +1332,7 @@ func (apiReconciler *APIReconciler) getAPIForHTTPRoute(ctx context.Context, obj return []reconcile.Request{} } - apiList := &dpv1alpha2.APIList{} + apiList := &dpv1beta1.APIList{} if err := apiReconciler.client.List(ctx, apiList, &k8client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(httpRouteAPIIndex, utils.NamespacedName(httpRoute).String()), }); err != nil { @@ -1219,6 +1359,44 @@ func (apiReconciler *APIReconciler) getAPIForHTTPRoute(ctx context.Context, obj return requests } +// getAPIForGRPCRoute triggers the API controller reconcile method based on the changes detected +// from GRPCRoute objects. If the changes are done for an API stored in the Operator Data store, +// a new reconcile event will be created and added to the reconcile event queue. +func (apiReconciler *APIReconciler) getAPIForGRPCRoute(ctx context.Context, obj k8client.Object) []reconcile.Request { + grpcRoute, ok := obj.(*gwapiv1a2.GRPCRoute) + if !ok { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2622, logging.TRIVIAL, "Unexpected object type, bypassing reconciliation: %v", grpcRoute)) + return []reconcile.Request{} + } + + apiList := &dpv1beta1.APIList{} + + if err := apiReconciler.client.List(ctx, apiList, &k8client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(grpcRouteAPIIndex, utils.NamespacedName(grpcRoute).String()), + }); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2623, logging.CRITICAL, "Unable to find associated APIs: %s", utils.NamespacedName(grpcRoute).String())) + return []reconcile.Request{} + } + + if len(apiList.Items) == 0 { + loggers.LoggerAPKOperator.Debugf("APIs for GRPCRoute not found: %s", utils.NamespacedName(grpcRoute).String()) + return []reconcile.Request{} + } + + requests := []reconcile.Request{} + for _, api := range apiList.Items { + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: api.Name, + Namespace: api.Namespace}, + } + requests = append(requests, req) + loggers.LoggerAPKOperator.Infof("Adding reconcile request for API: %s/%s with API UUID: %v", api.Namespace, api.Name, + string(api.ObjectMeta.UID)) + } + return requests +} + // getAPIsForConfigMap triggers the API controller reconcile method based on the changes detected // in configMap resources. func (apiReconciler *APIReconciler) getAPIsForConfigMap(ctx context.Context, obj k8client.Object) []reconcile.Request { @@ -1242,7 +1420,7 @@ func (apiReconciler *APIReconciler) getAPIsForConfigMap(ctx context.Context, obj return requests } - apiList := &dpv1alpha2.APIList{} + apiList := &dpv1beta1.APIList{} err = apiReconciler.client.List(ctx, apiList, &k8client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(configMapAPIDefinition, utils.NamespacedName(configMap).String()), }) @@ -1487,6 +1665,22 @@ func (apiReconciler *APIReconciler) getAPIsForScope(ctx context.Context, obj k8c requests = append(requests, apiReconciler.getAPIForGQLRoute(ctx, &httpRoute)...) } + grpcRouteList := &gwapiv1a2.GRPCRouteList{} + if err := apiReconciler.client.List(ctx, grpcRouteList, &k8client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(grpcRouteScopeIndex, utils.NamespacedName(scope).String()), + }); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2625, logging.CRITICAL, "Unable to find associated GRPCRoutes: %s", utils.NamespacedName(scope).String())) + return []reconcile.Request{} + } + + if len(grpcRouteList.Items) == 0 { + loggers.LoggerAPKOperator.Debugf("GRPCRoutes for scope not found: %s", utils.NamespacedName(scope).String()) + } + for item := range grpcRouteList.Items { + grpcRoute := grpcRouteList.Items[item] + requests = append(requests, apiReconciler.getAPIForGRPCRoute(ctx, &grpcRoute)...) + } + return requests } @@ -1507,15 +1701,30 @@ func (apiReconciler *APIReconciler) getAPIsForBackend(ctx context.Context, obj k return []reconcile.Request{} } + grpcRouteList := &gwapiv1a2.GRPCRouteList{} + if err := apiReconciler.client.List(ctx, grpcRouteList, &k8client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(backendGRPCRouteIndex, utils.NamespacedName(backend).String()), + }); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2625, logging.CRITICAL, "Unable to find associated GRPCRoutes: %s", utils.NamespacedName(backend).String())) + return []reconcile.Request{} + } + if len(httpRouteList.Items) == 0 { loggers.LoggerAPKOperator.Debugf("HTTPRoutes for Backend not found: %s", utils.NamespacedName(backend).String()) } + if len(grpcRouteList.Items) == 0 { + loggers.LoggerAPKOperator.Debugf("GRPCRoutes for Backend not found: %s", utils.NamespacedName(backend).String()) + } requests := []reconcile.Request{} for item := range httpRouteList.Items { httpRoute := httpRouteList.Items[item] requests = append(requests, apiReconciler.getAPIForHTTPRoute(ctx, &httpRoute)...) } + for item := range grpcRouteList.Items { + grpcRoute := grpcRouteList.Items[item] + requests = append(requests, apiReconciler.getAPIForGRPCRoute(ctx, &grpcRoute)...) + } gqlRouteList := &dpv1alpha2.GQLRouteList{} if err := apiReconciler.client.List(ctx, gqlRouteList, &k8client.ListOptions{ @@ -1570,17 +1779,33 @@ func (apiReconciler *APIReconciler) getAPIsForGateway(ctx context.Context, obj k loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2625, logging.CRITICAL, "Unable to find associated HTTPRoutes: %s", utils.NamespacedName(gateway).String())) return []reconcile.Request{} } + grpcRouteList := &gwapiv1a2.GRPCRouteList{} + if err := apiReconciler.client.List(ctx, grpcRouteList, &k8client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(gatewayGRPCRouteIndex, utils.NamespacedName(gateway).String()), + }); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2625, logging.CRITICAL, "Unable to find associated GRPCRoutes: %s", utils.NamespacedName(gateway).String())) + return []reconcile.Request{} + } if len(httpRouteList.Items) == 0 { loggers.LoggerAPKOperator.Debugf("HTTPRoutes for Gateway not found: %s", utils.NamespacedName(gateway).String()) return []reconcile.Request{} } + if len(grpcRouteList.Items) == 0 { + loggers.LoggerAPKOperator.Debugf("GRPCRoutes for Gateway not found: %s", utils.NamespacedName(gateway).String()) + return []reconcile.Request{} + } requests := []reconcile.Request{} for item := range httpRouteList.Items { httpRoute := httpRouteList.Items[item] requests = append(requests, apiReconciler.getAPIForHTTPRoute(ctx, &httpRoute)...) } + for item := range grpcRouteList.Items { + grpcRoute := grpcRouteList.Items[item] + requests = append(requests, apiReconciler.getAPIForGRPCRoute(ctx, &grpcRoute)...) + } + return requests } @@ -1595,9 +1820,9 @@ func (apiReconciler *APIReconciler) getAPIsForGateway(ctx context.Context, obj k // apiPolicy schemes related to httproutes // This helps to find apiPolicy schemes binded to HTTPRoute. func addIndexes(ctx context.Context, mgr manager.Manager) error { - if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.API{}, httpRouteAPIIndex, + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1beta1.API{}, httpRouteAPIIndex, func(rawObj k8client.Object) []string { - api := rawObj.(*dpv1alpha2.API) + api := rawObj.(*dpv1beta1.API) var httpRoutes []string if len(api.Spec.Production) > 0 { for _, ref := range api.Spec.Production[0].RouteRefs { @@ -1626,9 +1851,9 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { return err } - if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.API{}, gqlRouteAPIIndex, + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1beta1.API{}, gqlRouteAPIIndex, func(rawObj k8client.Object) []string { - api := rawObj.(*dpv1alpha2.API) + api := rawObj.(*dpv1beta1.API) var gqlRoutes []string if len(api.Spec.Production) > 0 { for _, ref := range api.Spec.Production[0].RouteRefs { @@ -1656,10 +1881,44 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { }); err != nil { return err } + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1beta1.API{}, grpcRouteAPIIndex, + func(rawObj k8client.Object) []string { + //check Spec.Kind + api := rawObj.(*dpv1beta1.API) + if api.Spec.APIType != "GRPC" { + return nil + } + var grpcRoutes []string + if len(api.Spec.Production) > 0 { + for _, ref := range api.Spec.Production[0].RouteRefs { + if ref != "" { + grpcRoutes = append(grpcRoutes, + types.NamespacedName{ + Namespace: api.Namespace, + Name: ref, + }.String()) + } + } + } + if len(api.Spec.Sandbox) > 0 { + for _, ref := range api.Spec.Sandbox[0].RouteRefs { + if ref != "" { + grpcRoutes = append(grpcRoutes, + types.NamespacedName{ + Namespace: api.Namespace, + Name: ref, + }.String()) + } + } + } + return grpcRoutes + }); err != nil { + return err + } - if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.API{}, configMapAPIDefinition, + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1beta1.API{}, configMapAPIDefinition, func(rawObj k8client.Object) []string { - api := rawObj.(*dpv1alpha2.API) + api := rawObj.(*dpv1beta1.API) var configMaps []string if api.Spec.DefinitionFileRef != "" { configMaps = append(configMaps, @@ -1734,6 +1993,27 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { return err } + // Backend to GRPCRoute indexer + if err := mgr.GetFieldIndexer().IndexField(ctx, &gwapiv1a2.GRPCRoute{}, backendGRPCRouteIndex, + func(rawObj k8client.Object) []string { + grpcRoute := rawObj.(*gwapiv1a2.GRPCRoute) + var backends []string + for _, rule := range grpcRoute.Spec.Rules { + for _, backendRef := range rule.BackendRefs { + if backendRef.Kind != nil && *backendRef.Kind == constants.KindBackend { + backends = append(backends, types.NamespacedName{ + Namespace: utils.GetNamespace(backendRef.Namespace, + grpcRoute.ObjectMeta.Namespace), + Name: string(backendRef.Name), + }.String()) + } + } + } + return backends + }); err != nil { + return err + } + // Backend to GQLRoute indexer if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.GQLRoute{}, backendGQLRouteIndex, func(rawObj k8client.Object) []string { @@ -1771,6 +2051,23 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { return err } + //Gateway to GRPCRoute indexer + if err := mgr.GetFieldIndexer().IndexField(ctx, &gwapiv1a2.GRPCRoute{}, gatewayGRPCRouteIndex, + func(rawObj k8client.Object) []string { + grpcRoute := rawObj.(*gwapiv1a2.GRPCRoute) + var gateways []string + for _, parentRef := range grpcRoute.Spec.ParentRefs { + gateways = append(gateways, types.NamespacedName{ + Namespace: utils.GetNamespace(parentRef.Namespace, + grpcRoute.Namespace), + Name: string(parentRef.Name), + }.String()) + } + return gateways + }); err != nil { + return err + } + // ConfigMap to Backend indexer if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha1.Backend{}, configMapBackend, func(rawObj k8client.Object) []string { @@ -2146,9 +2443,9 @@ func (apiReconciler *APIReconciler) handleStatus() { for _, apiName := range successEvent.APINamespacedName { // handle startup multiple apis apiReconciler.statusUpdater.Send(status.Update{ NamespacedName: apiName, - Resource: new(dpv1alpha2.API), + Resource: new(dpv1beta1.API), UpdateStatus: func(obj k8client.Object) k8client.Object { - h, ok := obj.(*dpv1alpha2.API) + h, ok := obj.(*dpv1beta1.API) if !ok { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2626, logging.BLOCKER, "Unsupported object type %T", obj)) } @@ -2185,7 +2482,7 @@ func (apiReconciler *APIReconciler) handleLabels(ctx context.Context) { }) } payloadBytes, _ := json.Marshal(patchOps) - apiCR := dpv1alpha2.API{ + apiCR := dpv1beta1.API{ ObjectMeta: metav1.ObjectMeta{ Namespace: labelUpdate.Namespace, Name: labelUpdate.Name, @@ -2196,7 +2493,7 @@ func (apiReconciler *APIReconciler) handleLabels(ctx context.Context) { if err != nil { loggers.LoggerAPKOperator.Errorf("Failed to patch api %s/%s with patch: %+v, error: %+v", labelUpdate.Name, labelUpdate.Namespace, patchOps, err) // Patch did not work it could be due to labels field does not exists. Lets try to update the CR with labels field. - var apiCR dpv1alpha2.API + var apiCR dpv1beta1.API if err := apiReconciler.client.Get(ctx, types.NamespacedName{Namespace: labelUpdate.Namespace, Name: labelUpdate.Name}, &apiCR); err == nil { if apiCR.ObjectMeta.Labels == nil { apiCR.ObjectMeta.Labels = map[string]string{} @@ -2216,9 +2513,9 @@ func (apiReconciler *APIReconciler) handleLabels(ctx context.Context) { } func (apiReconciler *APIReconciler) handleOwnerReference(ctx context.Context, obj k8client.Object, apiRequests *[]reconcile.Request) { - apis := []dpv1alpha2.API{} + apis := []dpv1beta1.API{} for _, req := range *apiRequests { - var apiCR dpv1alpha2.API + var apiCR dpv1beta1.API if err := apiReconciler.client.Get(ctx, req.NamespacedName, &apiCR); err == nil { apis = append(apis, apiCR) } else { @@ -2248,7 +2545,7 @@ func (apiReconciler *APIReconciler) handleOwnerReference(ctx context.Context, ob } } -func prepareOwnerReference(apiItems []dpv1alpha2.API) []metav1.OwnerReference { +func prepareOwnerReference(apiItems []dpv1beta1.API) []metav1.OwnerReference { ownerReferences := []metav1.OwnerReference{} uidMap := make(map[string]bool) for _, ref := range apiItems { diff --git a/adapter/internal/operator/operator.go b/adapter/internal/operator/operator.go index 151314fc5..20db27c27 100644 --- a/adapter/internal/operator/operator.go +++ b/adapter/internal/operator/operator.go @@ -20,6 +20,7 @@ package operator import ( "flag" "fmt" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "strings" "github.com/wso2/apk/adapter/config" @@ -66,6 +67,8 @@ func init() { utilruntime.Must(gwapiv1a2.AddToScheme(scheme)) utilruntime.Must(dpv1alpha2.AddToScheme(scheme)) + utilruntime.Must(dpv1beta1.AddToScheme(scheme)) + //+kubebuilder:scaffold:scheme } diff --git a/adapter/internal/operator/synchronizer/api_state.go b/adapter/internal/operator/synchronizer/api_state.go index 10e50c223..6f79af8ea 100644 --- a/adapter/internal/operator/synchronizer/api_state.go +++ b/adapter/internal/operator/synchronizer/api_state.go @@ -20,6 +20,8 @@ package synchronizer import ( "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) @@ -27,11 +29,13 @@ import ( // the state of the Kubernetes controller cache to detect updates. // +k8s:deepcopy-gen=true type APIState struct { - APIDefinition *v1alpha2.API + APIDefinition *v1beta1.API ProdHTTPRoute *HTTPRouteState SandHTTPRoute *HTTPRouteState ProdGQLRoute *GQLRouteState SandGQLRoute *GQLRouteState + ProdGRPCRoute *GRPCRouteState + SandGRPCRoute *GRPCRouteState Authentications map[string]v1alpha2.Authentication RateLimitPolicies map[string]v1alpha1.RateLimitPolicy ResourceAuthentications map[string]v1alpha2.Authentication @@ -64,3 +68,13 @@ type GQLRouteState struct { BackendMapping map[string]*v1alpha1.ResolvedBackend Scopes map[string]v1alpha1.Scope } + +// GRPCRouteState holds the state of the deployed grpcRoutes. This state is compared with +// the state of the Kubernetes controller cache to detect updates. +// +k8s:deepcopy-gen=true +type GRPCRouteState struct { + GRPCRouteCombined *gwapiv1a2.GRPCRoute + GRPCRoutePartitions map[string]*gwapiv1a2.GRPCRoute + BackendMapping map[string]*v1alpha1.ResolvedBackend + Scopes map[string]v1alpha1.Scope +} diff --git a/adapter/internal/operator/synchronizer/data_store.go b/adapter/internal/operator/synchronizer/data_store.go index 9b3afab1d..8c2c23d4b 100644 --- a/adapter/internal/operator/synchronizer/data_store.go +++ b/adapter/internal/operator/synchronizer/data_store.go @@ -18,6 +18,7 @@ package synchronizer import ( + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" "sync" "github.com/wso2/apk/adapter/internal/loggers" @@ -115,6 +116,23 @@ func (ods *OperatorDataStore) processAPIState(apiNamespacedName types.Namespaced } cachedAPI.ProdGQLRoute = nil } + if apiState.ProdGRPCRoute != nil { + if cachedAPI.ProdGRPCRoute == nil { + cachedAPI.ProdGRPCRoute = apiState.ProdGRPCRoute + updated = true + events = append(events, "Production") + } else if routeEvents, routesUpdated := updateGRPCRoute(apiState.ProdGRPCRoute, cachedAPI.ProdGRPCRoute, + "Production"); routesUpdated { + updated = true + events = append(events, routeEvents...) + } + } else { + if cachedAPI.ProdGRPCRoute != nil { + updated = true + events = append(events, "Production") + } + cachedAPI.ProdGRPCRoute = nil + } if apiState.SandHTTPRoute != nil { if cachedAPI.SandHTTPRoute == nil { cachedAPI.SandHTTPRoute = apiState.SandHTTPRoute @@ -147,6 +165,22 @@ func (ods *OperatorDataStore) processAPIState(apiNamespacedName types.Namespaced } cachedAPI.SandGQLRoute = nil } + if apiState.SandGRPCRoute != nil { + if cachedAPI.SandGRPCRoute == nil { + cachedAPI.SandGRPCRoute = apiState.SandGRPCRoute + updated = true + events = append(events, "Sandbox") + } else if routeEvents, routesUpdated := updateGRPCRoute(apiState.SandGRPCRoute, cachedAPI.SandGRPCRoute, "Sandbox"); routesUpdated { + updated = true + events = append(events, routeEvents...) + } + } else { + if cachedAPI.SandGRPCRoute != nil { + updated = true + events = append(events, "Sandbox") + } + cachedAPI.SandGRPCRoute = nil + } if len(apiState.Authentications) != len(cachedAPI.Authentications) { cachedAPI.Authentications = apiState.Authentications cachedAPI.MutualSSL = apiState.MutualSSL @@ -443,6 +477,61 @@ func updateGQLRoute(gqlRoute *GQLRouteState, cachedGQLRoute *GQLRouteState, endp return events, updated } +func updateGRPCRoute(grpcRoute *GRPCRouteState, cachedGRPCRoute *GRPCRouteState, endpointType string) ([]string, bool) { + var updated bool + events := []string{} + if cachedGRPCRoute.GRPCRouteCombined == nil || !isEqualGRPCRoutes(cachedGRPCRoute.GRPCRoutePartitions, grpcRoute.GRPCRoutePartitions) { + cachedGRPCRoute.GRPCRouteCombined = grpcRoute.GRPCRouteCombined + cachedGRPCRoute.GRPCRoutePartitions = grpcRoute.GRPCRoutePartitions + updated = true + events = append(events, endpointType+" Endpoint") + } + + if len(grpcRoute.Scopes) != len(cachedGRPCRoute.Scopes) { + cachedGRPCRoute.Scopes = grpcRoute.Scopes + updated = true + events = append(events, "Resource Scopes") + } else { + for key, scope := range grpcRoute.Scopes { + if existingScope, found := cachedGRPCRoute.Scopes[key]; found { + if scope.UID != existingScope.UID || scope.Generation > existingScope.Generation { + cachedGRPCRoute.Scopes = grpcRoute.Scopes + updated = true + events = append(events, "Resource Scopes") + break + } + } else { + cachedGRPCRoute.Scopes = grpcRoute.Scopes + updated = true + events = append(events, "Resource Scopes") + break + } + } + } + + if len(grpcRoute.BackendMapping) != len(cachedGRPCRoute.BackendMapping) { + cachedGRPCRoute.BackendMapping = grpcRoute.BackendMapping + updated = true + events = append(events, endpointType+" Backend Properties") + } else { + for key, backend := range grpcRoute.BackendMapping { + if existingBackend, found := cachedGRPCRoute.BackendMapping[key]; found { + if backend.Backend.UID != existingBackend.Backend.UID || backend.Backend.Generation > existingBackend.Backend.Generation { + cachedGRPCRoute.BackendMapping = grpcRoute.BackendMapping + updated = true + events = append(events, endpointType+" Backend Properties") + break + } + } else { + cachedGRPCRoute.BackendMapping = grpcRoute.BackendMapping + updated = true + events = append(events, endpointType+" Backend Properties") + break + } + } + } + return events, updated +} func isEqualHTTPRoutes(cachedHTTPRoutes, newHTTPRoutes map[string]*gwapiv1b1.HTTPRoute) bool { for key, cachedHTTPRoute := range cachedHTTPRoutes { if newHTTPRoutes[key] == nil { @@ -469,6 +558,19 @@ func isEqualGQLRoutes(cachedGQLRoutes, newGQLRoutes map[string]*dpv1alpha2.GQLRo return true } +func isEqualGRPCRoutes(cachedGRPCRoutes, newGRPCRoutes map[string]*gwapiv1a2.GRPCRoute) bool { + for key, cachedGRPCRoute := range cachedGRPCRoutes { + if newGRPCRoutes[key] == nil { + return false + } + if newGRPCRoutes[key].UID == cachedGRPCRoute.UID && + newGRPCRoutes[key].Generation > cachedGRPCRoute.Generation { + return false + } + } + return true +} + // GetCachedAPI get cached apistate func (ods *OperatorDataStore) GetCachedAPI(apiName types.NamespacedName) (APIState, bool) { if cachedAPI, found := ods.apiStore[apiName]; found { diff --git a/adapter/internal/operator/synchronizer/grpc_api.go b/adapter/internal/operator/synchronizer/grpc_api.go new file mode 100644 index 000000000..26c0bd92c --- /dev/null +++ b/adapter/internal/operator/synchronizer/grpc_api.go @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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 synchronizer + +import ( + "errors" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + + "github.com/wso2/apk/adapter/config" + "github.com/wso2/apk/adapter/internal/dataholder" + "github.com/wso2/apk/adapter/internal/discovery/xds" + "github.com/wso2/apk/adapter/internal/discovery/xds/common" + "github.com/wso2/apk/adapter/internal/loggers" + "github.com/wso2/apk/adapter/internal/oasparser/model" + "github.com/wso2/apk/adapter/pkg/logging" + "k8s.io/apimachinery/pkg/types" + gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" +) + +// extract APIDetails from the GQLRoute +func updateInternalMapsFromGRPCRoute(apiState APIState, grpcRoute *GRPCRouteState, envType string) (*model.AdapterInternalAPI, map[string]struct{}, error) { + adapterInternalAPI, err := generateGRPCAdapterInternalAPI(apiState, grpcRoute, envType) + if err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2632, logging.MAJOR, "Error generating AdapterInternalAPI for GRPCRoute: %v. %v", grpcRoute.GRPCRouteCombined.Name, err)) + return nil, nil, err + } + + vHosts := getVhostsForGRPCAPI(grpcRoute.GRPCRouteCombined) + labels := getLabelsForGRPCAPI(grpcRoute.GRPCRouteCombined) + listeners, relativeSectionNames := getListenersForGRPCAPI(grpcRoute.GRPCRouteCombined, adapterInternalAPI.UUID) + // We dont have a use case where a perticular API's two different grpc routes refer to two different gateway. Hence get the first listener name for the list for processing. + if len(listeners) == 0 || len(relativeSectionNames) == 0 { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2633, logging.MINOR, "Failed to find a matching listener for grpc route: %v. ", + grpcRoute.GRPCRouteCombined.Name)) + return nil, nil, errors.New("failed to find matching listener name for the provided grpc route") + } + listenerName := listeners[0] + sectionName := relativeSectionNames[0] + + if len(listeners) > 0 { + if err := xds.PopulateInternalMaps(adapterInternalAPI, labels, vHosts, sectionName, listenerName); err != nil { + return nil, nil, err + } + } + return adapterInternalAPI, labels, nil +} + +// generateGRPCAdapterInternalAPI this will populate a AdapterInternalAPI representation for an GRPCRoute +func generateGRPCAdapterInternalAPI(apiState APIState, grpcRoute *GRPCRouteState, envType string) (*model.AdapterInternalAPI, error) { + var adapterInternalAPI model.AdapterInternalAPI + adapterInternalAPI.SetIsDefaultVersion(apiState.APIDefinition.Spec.IsDefaultVersion) + adapterInternalAPI.SetInfoAPICR(*apiState.APIDefinition) + adapterInternalAPI.SetAPIDefinitionFile(apiState.APIDefinitionFile) + adapterInternalAPI.SetAPIDefinitionEndpoint(apiState.APIDefinition.Spec.DefinitionPath) + adapterInternalAPI.SetSubscriptionValidation(apiState.SubscriptionValidation) + adapterInternalAPI.EnvType = envType + + environment := apiState.APIDefinition.Spec.Environment + if environment == "" { + conf := config.ReadConfigs() + environment = conf.Adapter.Environment + } + adapterInternalAPI.SetEnvironment(environment) + adapterInternalAPI.SetXWso2RequestBodyPass(true) + + resourceParams := model.ResourceParams{ + AuthSchemes: apiState.Authentications, + ResourceAuthSchemes: apiState.ResourceAuthentications, + BackendMapping: grpcRoute.BackendMapping, + APIPolicies: apiState.APIPolicies, + ResourceAPIPolicies: apiState.ResourceAPIPolicies, + ResourceScopes: grpcRoute.Scopes, + InterceptorServiceMapping: apiState.InterceptorServiceMapping, + BackendJWTMapping: apiState.BackendJWTMapping, + RateLimitPolicies: apiState.RateLimitPolicies, + ResourceRateLimitPolicies: apiState.ResourceRateLimitPolicies, + } + if err := adapterInternalAPI.SetInfoGRPCRouteCR(grpcRoute.GRPCRouteCombined, resourceParams); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2631, logging.MAJOR, "Error setting GRPCRoute CR info to adapterInternalAPI. %v", err)) + return nil, err + } + if apiState.MutualSSL != nil && apiState.MutualSSL.Required != "" && !adapterInternalAPI.GetDisableAuthentications() { + adapterInternalAPI.SetDisableMtls(apiState.MutualSSL.Disabled) + adapterInternalAPI.SetMutualSSL(apiState.MutualSSL.Required) + adapterInternalAPI.SetClientCerts(apiState.APIDefinition.Name, apiState.MutualSSL.ClientCertificates) + } else { + adapterInternalAPI.SetDisableMtls(true) + } + + return &adapterInternalAPI, nil + +} + +// getVhostForAPI returns the vHosts related to an API. +func getVhostsForGRPCAPI(grpcRoute *gwapiv1a2.GRPCRoute) map[string]struct{} { + vHosts := make(map[string]struct{}) + for _, hostName := range grpcRoute.Spec.Hostnames { + vHosts[string(hostName)] = struct{}{} + } + return vHosts +} + +// getLabelsForAPI returns the labels related to an API. +func getLabelsForGRPCAPI(grpcRoute *gwapiv1a2.GRPCRoute) map[string]struct{} { + labels := make(map[string]struct{}) + for _, parentRef := range grpcRoute.Spec.ParentRefs { + err := xds.SanitizeGateway(string(parentRef.Name), false) + if err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2653, logging.CRITICAL, "Gateway Label is invalid: %s", string(parentRef.Name))) + } else { + labels[string(parentRef.Name)] = struct{}{} + } + } + return labels +} + +// getListenersForGRPCAPI returns the listeners related to an API. +func getListenersForGRPCAPI(grpcRoute *gwapiv1a2.GRPCRoute, apiUUID string) ([]string, []string) { + var listeners []string + var sectionNames []string + for _, parentRef := range grpcRoute.Spec.ParentRefs { + namespace := grpcRoute.GetNamespace() + if parentRef.Namespace != nil && *parentRef.Namespace != "" { + namespace = string(*parentRef.Namespace) + } + gateway, found := dataholder.GetGatewayMap()[types.NamespacedName{ + Namespace: namespace, + Name: string(parentRef.Name), + }.String()] + if found { + // find the matching listener + matchedListener, listenerFound := common.FindElement(gateway.Spec.Listeners, func(listener gwapiv1b1.Listener) bool { + if string(listener.Name) == string(*parentRef.SectionName) { + return true + } + return false + }) + if listenerFound { + sectionNames = append(sectionNames, string(matchedListener.Name)) + listeners = append(listeners, common.GetEnvoyListenerName(string(matchedListener.Protocol), uint32(matchedListener.Port))) + continue + } + } + loggers.LoggerAPKOperator.Errorf("Failed to find matching listeners for the grpcroute: %+v", grpcRoute.Name) + } + return listeners, sectionNames +} + +func deleteGRPCAPIFromEnv(grpcRoute *gwapiv1a2.GRPCRoute, apiState APIState) error { + labels := getLabelsForGRPCAPI(grpcRoute) + uuid := string(apiState.APIDefinition.ObjectMeta.UID) + return xds.DeleteAPI(uuid, labels) +} + +// undeployGRPCAPIInGateway undeploys the related API in CREATE and UPDATE events. +func undeployGRPCAPIInGateway(apiState APIState) error { + var err error + if apiState.ProdGRPCRoute != nil { + err = deleteGRPCAPIFromEnv(apiState.ProdGRPCRoute.GRPCRouteCombined, apiState) + } + if err != nil { + loggers.LoggerXds.ErrorC(logging.PrintError(logging.Error2630, logging.MAJOR, "Error undeploying prod grpcRoute of API : %v in Organization %v from environments."+ + " Hence not checking on deleting the sand grpcRoute of the API", string(apiState.APIDefinition.ObjectMeta.UID), apiState.APIDefinition.Spec.Organization)) + return err + } + if apiState.SandGRPCRoute != nil { + err = deleteGRPCAPIFromEnv(apiState.SandGRPCRoute.GRPCRouteCombined, apiState) + } + return err +} diff --git a/adapter/internal/operator/synchronizer/synchronizer.go b/adapter/internal/operator/synchronizer/synchronizer.go index a61aa181c..0ce9bbea7 100644 --- a/adapter/internal/operator/synchronizer/synchronizer.go +++ b/adapter/internal/operator/synchronizer/synchronizer.go @@ -117,12 +117,16 @@ func undeployAPIInGateway(apiEvent *APIEvent) error { if apiState.APIDefinition.Spec.APIType == "GraphQL" { err = undeployGQLAPIInGateway(apiState) } + if apiState.APIDefinition.Spec.APIType == "GRPC" { + return undeployGRPCAPIInGateway(apiState) + } if err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2629, logging.CRITICAL, "API deployment failed for %s event : %v, %v", apiEvent.EventType, apiState.APIDefinition.Name, err)) } else if config.ReadConfigs().PartitionServer.Enabled { paritionCh <- apiEvent } + return nil } @@ -199,6 +203,34 @@ func deployMultipleAPIsInGateway(event *APIEvent, successChannel *chan SuccessEv } } } + if apiState.APIDefinition.Spec.APIType == "GRPC" { + if apiState.ProdGRPCRoute != nil { + _, updatedLabels, err := updateInternalMapsFromGRPCRoute(apiState, apiState.ProdGRPCRoute, constants.Production) + if err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2665, logging.CRITICAL, + "Error deploying prod grpcRoute of API : %v in Organization %v from environments %v. Error: %v", + string(apiState.APIDefinition.Spec.APIName), apiState.APIDefinition.Spec.Organization, + getLabelsForGRPCAPI(apiState.ProdGRPCRoute.GRPCRouteCombined), err)) + continue + } + for label := range updatedLabels { + updatedLabelsMap[label] = struct{}{} + } + } + if apiState.SandGRPCRoute != nil { + _, updatedLabels, err := updateInternalMapsFromGRPCRoute(apiState, apiState.SandGRPCRoute, constants.Sandbox) + if err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2665, logging.CRITICAL, + "Error deploying sand grpcRoute of API : %v in Organization %v from environments %v. Error: %v", + string(apiState.APIDefinition.Spec.APIName), apiState.APIDefinition.Spec.Organization, + getLabelsForGRPCAPI(apiState.SandGRPCRoute.GRPCRouteCombined), err)) + continue + } + for label := range updatedLabels { + updatedLabelsMap[label] = struct{}{} + } + } + } updatedAPIs = append(updatedAPIs, utils.NamespacedName(apiState.APIDefinition)) } @@ -254,6 +286,13 @@ func SendEventToPartitionServer() { for _, hostName := range httpRoute.HTTPRouteCombined.Spec.Hostnames { hostNames = append(hostNames, string(hostName)) } + grpcRoute := api.ProdGRPCRoute + if grpcRoute == nil { + grpcRoute = api.SandGRPCRoute + } + for _, hostName := range grpcRoute.GRPCRouteCombined.Spec.Hostnames { + hostNames = append(hostNames, string(hostName)) + } data := PartitionEvent{ EventType: eventType, BasePath: basePath, diff --git a/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go b/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go index f2dc5002c..95a916ca9 100644 --- a/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go +++ b/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go @@ -25,6 +25,7 @@ package synchronizer import ( "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "sigs.k8s.io/gateway-api/apis/v1beta1" ) @@ -33,7 +34,7 @@ func (in *APIState) DeepCopyInto(out *APIState) { *out = *in if in.APIDefinition != nil { in, out := &in.APIDefinition, &out.APIDefinition - *out = new(v1alpha2.API) + *out = new(dpv1beta1.API) (*in).DeepCopyInto(*out) } if in.ProdHTTPRoute != nil { diff --git a/adapter/internal/operator/utils/utils.go b/adapter/internal/operator/utils/utils.go index 11c1867b0..cb8b5f626 100644 --- a/adapter/internal/operator/utils/utils.go +++ b/adapter/internal/operator/utils/utils.go @@ -35,6 +35,7 @@ import ( "github.com/wso2/apk/adapter/pkg/utils/stringutils" dpv1alpha1 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -297,7 +298,7 @@ func getSecretValue(ctx context.Context, client k8client.Client, // ResolveAndAddBackendToMapping resolves backend from reference and adds it to the backendMapping. func ResolveAndAddBackendToMapping(ctx context.Context, client k8client.Client, backendMapping map[string]*dpv1alpha1.ResolvedBackend, - backendRef dpv1alpha1.BackendReference, interceptorServiceNamespace string, api *dpv1alpha2.API) { + backendRef dpv1alpha1.BackendReference, interceptorServiceNamespace string, api *dpv1beta1.API) { backendName := types.NamespacedName{ Name: backendRef.Name, Namespace: interceptorServiceNamespace, @@ -309,7 +310,7 @@ func ResolveAndAddBackendToMapping(ctx context.Context, client k8client.Client, } // ResolveRef this function will return k8client object and update owner -func ResolveRef(ctx context.Context, client k8client.Client, api *dpv1alpha2.API, +func ResolveRef(ctx context.Context, client k8client.Client, api *dpv1beta1.API, namespacedName types.NamespacedName, isReplace bool, obj k8client.Object, opts ...k8client.GetOption) error { err := client.Get(ctx, namespacedName, obj, opts...) return err @@ -317,7 +318,7 @@ func ResolveRef(ctx context.Context, client k8client.Client, api *dpv1alpha2.API // GetResolvedBackend resolves backend TLS configurations. func GetResolvedBackend(ctx context.Context, client k8client.Client, - backendNamespacedName types.NamespacedName, api *dpv1alpha2.API) *dpv1alpha1.ResolvedBackend { + backendNamespacedName types.NamespacedName, api *dpv1beta1.API) *dpv1alpha1.ResolvedBackend { resolvedBackend := dpv1alpha1.ResolvedBackend{} resolvedTLSConfig := dpv1alpha1.ResolvedTLSConfig{} var backend dpv1alpha1.Backend @@ -518,7 +519,7 @@ func RetrieveNamespaceListOptions(namespaces []string) k8client.ListOptions { // GetInterceptorService reads InterceptorService when interceptorReference is given func GetInterceptorService(ctx context.Context, client k8client.Client, namespace string, - interceptorReference *dpv1alpha2.InterceptorReference, api *dpv1alpha2.API) *dpv1alpha1.InterceptorService { + interceptorReference *dpv1alpha2.InterceptorReference, api *dpv1beta1.API) *dpv1alpha1.InterceptorService { interceptorService := &dpv1alpha1.InterceptorService{} interceptorRef := types.NamespacedName{ Namespace: namespace, @@ -534,7 +535,7 @@ func GetInterceptorService(ctx context.Context, client k8client.Client, namespac // GetBackendJWT reads BackendJWT when backendJWTReference is given func GetBackendJWT(ctx context.Context, client k8client.Client, namespace, - backendJWTReference string, api *dpv1alpha2.API) *dpv1alpha1.BackendJWT { + backendJWTReference string, api *dpv1beta1.API) *dpv1alpha1.BackendJWT { backendJWT := &dpv1alpha1.BackendJWT{} backendJWTRef := types.NamespacedName{ Namespace: namespace, @@ -549,21 +550,21 @@ func GetBackendJWT(ctx context.Context, client k8client.Client, namespace, } // RetrieveAPIList retrieves API list from the given kubernetes client -func RetrieveAPIList(k8sclient k8client.Client) ([]dpv1alpha2.API, error) { +func RetrieveAPIList(k8sclient k8client.Client) ([]dpv1beta1.API, error) { ctx := context.Background() conf := config.ReadConfigs() namespaces := conf.Adapter.Operator.Namespaces - var apis []dpv1alpha2.API + var apis []dpv1beta1.API if namespaces == nil { - apiList := &dpv1alpha2.APIList{} + apiList := &dpv1beta1.APIList{} if err := k8sclient.List(ctx, apiList, &k8client.ListOptions{}); err != nil { return nil, err } - apis = make([]dpv1alpha2.API, len(apiList.Items)) + apis = make([]dpv1beta1.API, len(apiList.Items)) copy(apis[:], apiList.Items[:]) } else { for _, namespace := range namespaces { - apiList := &dpv1alpha2.APIList{} + apiList := &dpv1beta1.APIList{} if err := k8sclient.List(ctx, apiList, &k8client.ListOptions{Namespace: namespace}); err != nil { return nil, err } @@ -587,10 +588,10 @@ func ConvertRefConfigsV1ToV2(refConfig *dpv1alpha1.RefConfig) *dpv1alpha2.RefCon // ContainsString checks whether a list contains a specific string. // It returns true if the string is found in the list, otherwise false. func ContainsString(list []string, target string) bool { - for _, item := range list { - if item == target { - return true - } - } - return false + for _, item := range list { + if item == target { + return true + } + } + return false } diff --git a/common-controller/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml b/common-controller/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml index 304529c66..705182f96 100644 --- a/common-controller/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml +++ b/common-controller/internal/operator/config/crd/bases/dp.wso2.com_apis.yaml @@ -247,6 +247,7 @@ spec: enum: - REST - GraphQL + - GRPC type: string apiVersion: description: APIVersion is the version number of the API. @@ -363,3 +364,180 @@ spec: storage: true subresources: status: {} + - additionalPrinterColumns: + - jsonPath: .spec.apiName + name: API Name + type: string + - jsonPath: .spec.apiVersion + name: Version + type: string + - jsonPath: .spec.basePath + name: BasePath + type: string + - jsonPath: .spec.organization + name: Organization + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: API is the Schema for the apis API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APISpec defines the desired state of API + properties: + apiName: + description: APIName is the unique name of the API can be used to + uniquely identify an API. + maxLength: 60 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&$\[\]\/]*$ + type: string + apiProperties: + description: APIProperties denotes the custom properties of the API. + items: + description: Property holds key value pair of APIProperties + properties: + name: + type: string + value: + type: string + type: object + nullable: true + type: array + apiType: + description: APIType denotes the type of the API. Possible values + could be REST, GraphQL, Async + enum: + - REST + - GraphQL + - GRPC + type: string + apiVersion: + description: APIVersion is the version number of the API. + maxLength: 30 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&/$\[\]\s+\/]+$ + type: string + basePath: + description: 'BasePath denotes the basepath of the API. e.g: /pet-store-api/1.0.6' + type: string + definitionFileRef: + description: DefinitionFileRef contains the OpenAPI 3 or Swagger definition + of the API in a ConfigMap. + type: string + definitionPath: + default: /api-definition + description: DefinitionPath contains the path to expose the API definition. + minLength: 1 + type: string + environment: + description: Environment denotes the environment of the API. + nullable: true + type: string + isDefaultVersion: + description: IsDefaultVersion indicates whether this API version should + be used as a default API + type: boolean + organization: + description: Organization denotes the organization. related to the + API + type: string + production: + description: 'Production contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + httpRouteRefs: + description: HTTPRouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - httpRouteRefs + type: object + maxItems: 1 + nullable: true + type: array + sandbox: + description: 'Sandbox contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + httpRouteRefs: + description: HTTPRouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - httpRouteRefs + type: object + maxItems: 1 + nullable: true + type: array + systemAPI: + description: SystemAPI denotes if it is an internal system API. + type: boolean + required: + - apiName + - apiType + - apiVersion + - basePath + - definitionPath + type: object + status: + description: APIStatus defines the observed state of API + properties: + deploymentStatus: + description: DeploymentStatus denotes the deployment status of the + API + properties: + accepted: + description: Accepted represents whether the API is accepted or + not. + type: boolean + events: + description: Events contains a list of events related to the API. + items: + type: string + type: array + message: + description: Message represents a user friendly message that explains + the current state of the API. + type: string + status: + description: Status denotes the state of the API in its lifecycle. + Possible values could be Accepted, Invalid, Deploy etc. + type: string + transitionTime: + description: TransitionTime represents the last known transition + timestamp. + format: date-time + type: string + required: + - accepted + - status + - transitionTime + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/common-controller/internal/operator/controllers/dp/ratelimitpolicy_controller.go b/common-controller/internal/operator/controllers/dp/ratelimitpolicy_controller.go index c4de5e578..012c9280f 100644 --- a/common-controller/internal/operator/controllers/dp/ratelimitpolicy_controller.go +++ b/common-controller/internal/operator/controllers/dp/ratelimitpolicy_controller.go @@ -19,6 +19,7 @@ package dp import ( "context" "fmt" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "time" logger "github.com/sirupsen/logrus" @@ -46,7 +47,6 @@ import ( "github.com/wso2/apk/common-controller/internal/utils" xds "github.com/wso2/apk/common-controller/internal/xds" dpv1alpha1 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" - dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" "github.com/wso2/apk/common-go-libs/constants" ) @@ -87,7 +87,7 @@ func NewratelimitController(mgr manager.Manager, ratelimitStore *cache.Ratelimit conf := config.ReadConfigs() predicates := []predicate.Predicate{predicate.NewPredicateFuncs(utils.FilterByNamespaces(conf.CommonController.Operator.Namespaces))} - if err := c.Watch(source.Kind(mgr.GetCache(), &dpv1alpha2.API{}), + if err := c.Watch(source.Kind(mgr.GetCache(), &dpv1beta1.API{}), handler.EnqueueRequestsFromMapFunc(ratelimitReconsiler.getRatelimitForAPI), predicates...); err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2611, logging.BLOCKER, "Error watching API resources: %v", err)) @@ -149,7 +149,7 @@ func (ratelimitReconsiler *RateLimitPolicyReconciler) Reconcile(ctx context.Cont xds.DeleteCustomRateLimitPolicies(resolveCustomRateLimitPolicy) xds.UpdateRateLimiterPolicies(conf.CommonController.Server.Label) } - if (k8error.IsNotFound(err)) { + if k8error.IsNotFound(err) { return ctrl.Result{}, nil } return ctrl.Result{ @@ -177,7 +177,7 @@ func (ratelimitReconsiler *RateLimitPolicyReconciler) Reconcile(ctx context.Cont } func (ratelimitReconsiler *RateLimitPolicyReconciler) getRatelimitForAPI(ctx context.Context, obj k8client.Object) []reconcile.Request { - api, ok := obj.(*dpv1alpha2.API) + api, ok := obj.(*dpv1beta1.API) if !ok { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2622, logging.TRIVIAL, "Unexpected object type, bypassing reconciliation: %v", api)) @@ -246,7 +246,7 @@ func (ratelimitReconsiler *RateLimitPolicyReconciler) marshelRateLimit(ctx conte ratelimitPolicy dpv1alpha1.RateLimitPolicy) ([]dpv1alpha1.ResolveRateLimitAPIPolicy, error) { policyList := []dpv1alpha1.ResolveRateLimitAPIPolicy{} - var api dpv1alpha2.API + var api dpv1beta1.API if err := ratelimitReconsiler.client.Get(ctx, types.NamespacedName{ Namespace: ratelimitKey.Namespace, diff --git a/common-controller/internal/operator/operator.go b/common-controller/internal/operator/operator.go index 25c87115e..ccb30129f 100644 --- a/common-controller/internal/operator/operator.go +++ b/common-controller/internal/operator/operator.go @@ -39,6 +39,7 @@ import ( cpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/cp/v1alpha2" dpv1alpha1 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -63,6 +64,8 @@ func init() { utilruntime.Must(dpv1alpha2.AddToScheme(scheme)) utilruntime.Must(cpv1alpha2.AddToScheme(scheme)) utilruntime.Must(cpv1alpha2.AddToScheme(scheme)) + utilruntime.Must(dpv1beta1.AddToScheme(scheme)) + //+kubebuilder:scaffold:scheme } @@ -127,7 +130,7 @@ func InitOperator(metricsConfig config.Metrics) { "Unable to create webhook API, error: %v", err)) } - if err = (&dpv1alpha2.API{}).SetupWebhookWithManager(mgr); err != nil { + if err = (&dpv1beta1.API{}).SetupWebhookWithManager(mgr); err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2601, logging.MAJOR, "Unable to create webhook API, error: %v", err)) } diff --git a/common-go-libs/PROJECT b/common-go-libs/PROJECT index 89fbcd315..f6217e3bc 100644 --- a/common-go-libs/PROJECT +++ b/common-go-libs/PROJECT @@ -1,3 +1,7 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html domain: wso2.com layout: - go.kubebuilder.io/v3 @@ -160,4 +164,13 @@ resources: defaulting: true validation: true webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: wso2.com + group: dp + kind: Api + path: github.com/wso2/apk/common-go-libs/apis/dp/v1beta1 + version: v1beta1 version: "3" diff --git a/common-go-libs/apis/dp/v1alpha1/api_conversion.go b/common-go-libs/apis/dp/v1alpha1/api_conversion.go index 2aaf06c91..39d22c48e 100644 --- a/common-go-libs/apis/dp/v1alpha1/api_conversion.go +++ b/common-go-libs/apis/dp/v1alpha1/api_conversion.go @@ -18,15 +18,15 @@ package v1alpha1 import ( - "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" "sigs.k8s.io/controller-runtime/pkg/conversion" ) -// ConvertTo converts this API CR to the Hub version (v1alpha2). -// src is v1alpha1.API and dst is v1alpha2.API. +// ConvertTo converts this API CR to the Hub version (v1beta1). +// src is v1alpha1.API and dst is v1beta1.API. func (src *API) ConvertTo(dstRaw conversion.Hub) error { - dst := dstRaw.(*v1alpha2.API) + dst := dstRaw.(*v1beta1.API) dst.ObjectMeta = src.ObjectMeta // Spec @@ -41,40 +41,40 @@ func (src *API) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.SystemAPI = src.Spec.SystemAPI if src.Spec.Production != nil { - dst.Spec.Production = []v1alpha2.EnvConfig{} + dst.Spec.Production = []v1beta1.EnvConfig{} for _, productionRef := range src.Spec.Production { - dst.Spec.Production = append(dst.Spec.Production, v1alpha2.EnvConfig{ + dst.Spec.Production = append(dst.Spec.Production, v1beta1.EnvConfig{ RouteRefs: productionRef.HTTPRouteRefs, }) } } if src.Spec.Sandbox != nil { - dst.Spec.Sandbox = []v1alpha2.EnvConfig{} + dst.Spec.Sandbox = []v1beta1.EnvConfig{} for _, sandboxRef := range src.Spec.Sandbox { - dst.Spec.Sandbox = append(dst.Spec.Sandbox, v1alpha2.EnvConfig{ + dst.Spec.Sandbox = append(dst.Spec.Sandbox, v1beta1.EnvConfig{ RouteRefs: sandboxRef.HTTPRouteRefs, }) } } - // Convert []Property to []v1alpha2.Property - var properties []v1alpha2.Property + // Convert []Property to []v1beta1.Property + var properties []v1beta1.Property for _, p := range src.Spec.APIProperties { - properties = append(properties, v1alpha2.Property(p)) + properties = append(properties, v1beta1.Property(p)) } dst.Spec.APIProperties = properties // Status - dst.Status.DeploymentStatus = v1alpha2.DeploymentStatus(src.Status.DeploymentStatus) + dst.Status.DeploymentStatus = v1beta1.DeploymentStatus(src.Status.DeploymentStatus) return nil } -// ConvertFrom converts from the Hub version (v1alpha2) to this version. -// src is v1alpha1.API and dst is v1alpha2.API. +// ConvertFrom converts from the Hub version (v1beta1) to this version. +// src is v1beta1.API and dst is v1alpha1.API. func (src *API) ConvertFrom(srcRaw conversion.Hub) error { - dst := srcRaw.(*v1alpha2.API) + dst := srcRaw.(*v1beta1.API) src.ObjectMeta = dst.ObjectMeta // Spec @@ -106,7 +106,7 @@ func (src *API) ConvertFrom(srcRaw conversion.Hub) error { } } - // Convert []Property to []v1alpha1.Property + // Convert []Property to []v1beta1.Property var properties []Property for _, p := range dst.Spec.APIProperties { properties = append(properties, Property(p)) diff --git a/common-go-libs/apis/dp/v1alpha2/api_conversion.go b/common-go-libs/apis/dp/v1alpha2/api_conversion.go index 5a1953e13..fed53bed6 100644 --- a/common-go-libs/apis/dp/v1alpha2/api_conversion.go +++ b/common-go-libs/apis/dp/v1alpha2/api_conversion.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024 WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,5 +17,104 @@ package v1alpha2 -// Hub marks this type as a conversion hub. -func (*API) Hub() {} +import ( + "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +// ConvertTo converts this API CR to the Hub version (v1beta1). +// src is v1alpha12API and dst is v1beta1.API. +func (src *API) ConvertTo(dstRaw conversion.Hub) error { + + dst := dstRaw.(*v1beta1.API) + dst.ObjectMeta = src.ObjectMeta + + // Spec + dst.Spec.APIName = src.Spec.APIName + dst.Spec.APIVersion = src.Spec.APIVersion + dst.Spec.IsDefaultVersion = src.Spec.IsDefaultVersion + dst.Spec.DefinitionFileRef = src.Spec.DefinitionFileRef + dst.Spec.DefinitionPath = src.Spec.DefinitionPath + dst.Spec.APIType = src.Spec.APIType + dst.Spec.BasePath = src.Spec.BasePath + dst.Spec.Organization = src.Spec.Organization + dst.Spec.SystemAPI = src.Spec.SystemAPI + + if src.Spec.Production != nil { + dst.Spec.Production = []v1beta1.EnvConfig{} + for _, productionRef := range src.Spec.Production { + dst.Spec.Production = append(dst.Spec.Production, v1beta1.EnvConfig{ + RouteRefs: productionRef.RouteRefs, + }) + } + } + if src.Spec.Sandbox != nil { + dst.Spec.Sandbox = []v1beta1.EnvConfig{} + for _, sandboxRef := range src.Spec.Sandbox { + dst.Spec.Sandbox = append(dst.Spec.Sandbox, v1beta1.EnvConfig{ + RouteRefs: sandboxRef.RouteRefs, + }) + } + } + + // Convert []Property to []v1alpha2.Property + var properties []v1beta1.Property + for _, p := range src.Spec.APIProperties { + properties = append(properties, v1beta1.Property(p)) + } + dst.Spec.APIProperties = properties + + // Status + dst.Status.DeploymentStatus = v1beta1.DeploymentStatus(src.Status.DeploymentStatus) + + return nil +} + +// ConvertFrom converts from the Hub version (v1beta1) to this version. +// src is v1beta1.API and dst is v1alpha2.API. +func (src *API) ConvertFrom(srcRaw conversion.Hub) error { + + dst := srcRaw.(*v1beta1.API) + src.ObjectMeta = dst.ObjectMeta + + // Spec + src.Spec.APIName = dst.Spec.APIName + src.Spec.APIVersion = dst.Spec.APIVersion + src.Spec.IsDefaultVersion = dst.Spec.IsDefaultVersion + src.Spec.DefinitionFileRef = dst.Spec.DefinitionFileRef + src.Spec.DefinitionPath = dst.Spec.DefinitionPath + src.Spec.APIType = dst.Spec.APIType + src.Spec.BasePath = dst.Spec.BasePath + src.Spec.Organization = dst.Spec.Organization + src.Spec.SystemAPI = dst.Spec.SystemAPI + + if dst.Spec.Production != nil { + src.Spec.Production = []EnvConfig{} + for _, productionRef := range dst.Spec.Production { + src.Spec.Production = append(src.Spec.Production, EnvConfig{ + RouteRefs: productionRef.RouteRefs, + }) + } + } + + if dst.Spec.Sandbox != nil { + src.Spec.Sandbox = []EnvConfig{} + for _, sandboxRef := range dst.Spec.Sandbox { + src.Spec.Sandbox = append(src.Spec.Sandbox, EnvConfig{ + RouteRefs: sandboxRef.RouteRefs, + }) + } + } + + // Convert []Property to []v1alpha2Property + var properties []Property + for _, p := range dst.Spec.APIProperties { + properties = append(properties, Property(p)) + } + src.Spec.APIProperties = properties + + // Status + src.Status.DeploymentStatus = DeploymentStatus(dst.Status.DeploymentStatus) + + return nil +} diff --git a/common-go-libs/apis/dp/v1alpha2/api_types.go b/common-go-libs/apis/dp/v1alpha2/api_types.go index 4579e5e0b..c6bee13ef 100644 --- a/common-go-libs/apis/dp/v1alpha2/api_types.go +++ b/common-go-libs/apis/dp/v1alpha2/api_types.go @@ -80,16 +80,15 @@ type APISpec struct { Sandbox []EnvConfig `json:"sandbox"` // APIType denotes the type of the API. - // Possible values could be REST, GraphQL, Async + // Possible values could be REST, GraphQL, Async, GRPC etc. // - // +kubebuilder:validation:Enum=REST;GraphQL + // +kubebuilder:validation:Enum=REST;GraphQL;GRPC APIType string `json:"apiType"` // BasePath denotes the basepath of the API. // e.g: /pet-store-api/1.0.6 // // +kubectl:validation:MaxLength=232 - // +kubebuilder:validation:Pattern=^[/][a-zA-Z0-9~/_.-]*$ BasePath string `json:"basePath"` // Organization denotes the organization. @@ -172,7 +171,6 @@ type DeploymentStatus struct { // +genclient //+kubebuilder:object:root=true //+kubebuilder:subresource:status -//+kubebuilder:storageversion //+kubebuilder:printcolumn:name="API Name",type="string",JSONPath=".spec.apiName" //+kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.apiVersion" //+kubebuilder:printcolumn:name="BasePath",type="string",JSONPath=".spec.basePath" diff --git a/common-go-libs/apis/dp/v1alpha2/api_webhook.go b/common-go-libs/apis/dp/v1alpha2/api_webhook.go index 2e3348be3..67faddea5 100644 --- a/common-go-libs/apis/dp/v1alpha2/api_webhook.go +++ b/common-go-libs/apis/dp/v1alpha2/api_webhook.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "io" + "regexp" "strings" gqlparser "github.com/vektah/gqlparser" @@ -103,6 +104,8 @@ func (r *API) validateAPI() error { if r.Spec.BasePath == "" { allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("basePath"), "API basePath is required")) + } else if errMsg := validateAPIBasePathRegex(r.Spec.BasePath, r.Spec.APIType); errMsg != "" { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("basePath"), r.Spec.BasePath, errMsg)) } else if errMsg := validateAPIBasePathFormat(r.Spec.BasePath, r.Spec.APIVersion); errMsg != "" { allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("basePath"), r.Spec.BasePath, errMsg)) } else if err := r.validateAPIBasePathExistsAndDefaultVersion(); err != nil { @@ -250,6 +253,23 @@ func validateAPIBasePathFormat(basePath string, apiVersion string) string { return "" } +func validateAPIBasePathRegex(basePath, apiType string) string { + var pattern string + if apiType == "GRPC" { + pattern = `^[/][a-zA-Z][a-zA-Z0-9_.]*$` + } else { + pattern = `^[/][a-zA-Z0-9~/_.-]*$` + } + re, err := regexp.Compile(pattern) + if err != nil { + return "Failed to compile basePath regex pattern" + } + if !re.MatchString(basePath) { + return "API basePath is not in a valid format for the specified API type" + } + return "" +} + // getBasePathWithoutVersion returns the basePath without version func getBasePathWithoutVersion(basePath string) string { lastIndex := strings.LastIndex(basePath, "/") diff --git a/common-go-libs/apis/dp/v1beta1/api_conversion.go b/common-go-libs/apis/dp/v1beta1/api_conversion.go new file mode 100644 index 000000000..5564f83e0 --- /dev/null +++ b/common-go-libs/apis/dp/v1beta1/api_conversion.go @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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 v1beta1 + +// Hub marks this type as a conversion hub. +func (*API) Hub() {} diff --git a/common-go-libs/apis/dp/v1beta1/api_types.go b/common-go-libs/apis/dp/v1beta1/api_types.go new file mode 100644 index 000000000..357fab4a4 --- /dev/null +++ b/common-go-libs/apis/dp/v1beta1/api_types.go @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// APISpec defines the desired state of API +type APISpec struct { + + // APIName is the unique name of the API + //can be used to uniquely identify an API. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=60 + // +kubebuilder:validation:Pattern="^[^~!@#;:%^*()+={}|\\<>\"'',&$\\[\\]\\/]*$" + APIName string `json:"apiName"` + + // APIVersion is the version number of the API. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=30 + // +kubebuilder:validation:Pattern="^[^~!@#;:%^*()+={}|\\<>\"'',&/$\\[\\]\\s+\\/]+$" + APIVersion string `json:"apiVersion"` + + // IsDefaultVersion indicates whether this API version should be used as a default API + // + // +optional + IsDefaultVersion bool `json:"isDefaultVersion"` + + // DefinitionFileRef contains the + // definition of the API in a ConfigMap. + // + // +optional + DefinitionFileRef string `json:"definitionFileRef"` + + // DefinitionPath contains the path to expose the API definition. + // + // +kubebuilder:default:=/api-definition + // +kubebuilder:validation:MinLength=1 + DefinitionPath string `json:"definitionPath"` + + // Production contains a list of references to HttpRoutes + // of type HttpRoute. + // xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go + // + // + // +optional + // +nullable + // +kubebuilder:validation:MaxItems=1 + Production []EnvConfig `json:"production"` + + // Sandbox contains a list of references to HttpRoutes + // of type HttpRoute. + // xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go + // + // + // +optional + // +nullable + // +kubebuilder:validation:MaxItems=1 + Sandbox []EnvConfig `json:"sandbox"` + + // APIType denotes the type of the API. + // Possible values could be REST, GraphQL, Async, GRPC etc. + // + // +kubebuilder:validation:Enum=REST;GraphQL;GRPC + APIType string `json:"apiType"` + + // BasePath denotes the basepath of the API. + // e.g: /pet-store-api/1.0.6 + // + // +kubectl:validation:MaxLength=232 + BasePath string `json:"basePath"` + + // Organization denotes the organization. + // related to the API + // + // +optional + Organization string `json:"organization"` + + // SystemAPI denotes if it is an internal system API. + // + // +optional + SystemAPI bool `json:"systemAPI"` + + // APIProperties denotes the custom properties of the API. + // + // +optional + // +nullable + APIProperties []Property `json:"apiProperties,omitempty"` + + // Environment denotes the environment of the API. + // + // +optional + // +nullable + Environment string `json:"environment,omitempty"` +} + +// Property holds key value pair of APIProperties +type Property struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` +} + +// EnvConfig contains the environment specific configuration +type EnvConfig struct { + // RouteRefs denotes the environment of the API. + RouteRefs []string `json:"routeRefs"` +} + +// APIStatus defines the observed state of API +type APIStatus struct { + // DeploymentStatus denotes the deployment status of the API + // + // +optional + DeploymentStatus DeploymentStatus `json:"deploymentStatus"` +} + +// DeploymentStatus contains the status of the API deployment +type DeploymentStatus struct { + + // Status denotes the state of the API in its lifecycle. + // Possible values could be Accepted, Invalid, Deploy etc. + // + // + Status string `json:"status"` + + // Message represents a user friendly message that explains the + // current state of the API. + // + // + // +optional + Message string `json:"message"` + + // Accepted represents whether the API is accepted or not. + // + // + Accepted bool `json:"accepted"` + + // TransitionTime represents the last known transition timestamp. + // + // + TransitionTime *metav1.Time `json:"transitionTime"` + + // Events contains a list of events related to the API. + // + // + // +optional + Events []string `json:"events,omitempty"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion +//+kubebuilder:printcolumn:name="API Name",type="string",JSONPath=".spec.apiName" +//+kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.apiVersion" +//+kubebuilder:printcolumn:name="BasePath",type="string",JSONPath=".spec.basePath" +//+kubebuilder:printcolumn:name="Organization",type="string",JSONPath=".spec.organization" +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" + +// API is the Schema for the apis API +type API struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec APISpec `json:"spec,omitempty"` + Status APIStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// APIList contains a list of API +type APIList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []API `json:"items"` +} + +func init() { + SchemeBuilder.Register(&API{}, &APIList{}) +} diff --git a/common-go-libs/apis/dp/v1beta1/api_webhook.go b/common-go-libs/apis/dp/v1beta1/api_webhook.go new file mode 100644 index 000000000..0ddb52772 --- /dev/null +++ b/common-go-libs/apis/dp/v1beta1/api_webhook.go @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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 v1beta1 + +import ( + "bytes" + "compress/gzip" + "context" + "errors" + "fmt" + "io" + "regexp" + "strings" + + gqlparser "github.com/vektah/gqlparser" + "github.com/vektah/gqlparser/ast" + "github.com/wso2/apk/adapter/pkg/logging" + config "github.com/wso2/apk/common-go-libs/configs" + loggers "github.com/wso2/apk/common-go-libs/loggers" + utils "github.com/wso2/apk/common-go-libs/utils" + "golang.org/x/exp/slices" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/validation/field" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +var c client.Client + +// SetupWebhookWithManager creates a new webhook builder for API +func (r *API) SetupWebhookWithManager(mgr ctrl.Manager) error { + + c = mgr.GetClient() + return ctrl.NewWebhookManagedBy(mgr). + For(r). + Complete() +} + +// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! + +//+kubebuilder:webhook:path=/mutate-dp-wso2-com-v1beta1-api,mutating=true,failurePolicy=fail,sideEffects=None,groups=dp.wso2.com,resources=apis,verbs=create;update,versions=v1alpha2,name=mapi.kb.io,admissionReviewVersions=v1 + +var _ webhook.Defaulter = &API{} + +// Default implements webhook.Defaulter so a webhook will be registered for the type +func (r *API) Default() { + // TODO(user): fill in your defaulting logic. +} + +// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. +//+kubebuilder:webhook:path=/validate-dp-wso2-com-v1beta1-api,mutating=false,failurePolicy=fail,sideEffects=None,groups=dp.wso2.com,resources=apis,verbs=create;update,versions=v1alpha2,name=vapi.kb.io,admissionReviewVersions=v1 + +var _ webhook.Validator = &API{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (r *API) ValidateCreate() (admission.Warnings, error) { + return nil, r.validateAPI() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (r *API) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + return nil, r.validateAPI() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (r *API) ValidateDelete() (admission.Warnings, error) { + + // TODO(user): fill in your validation logic upon object deletion. + return nil, nil +} + +// validateAPI validate api crd fields +func (r *API) validateAPI() error { + var allErrs field.ErrorList + conf := config.ReadConfigs() + namespaces := conf.CommonController.Operator.Namespaces + if len(namespaces) > 0 { + if !slices.Contains(namespaces, r.Namespace) { + loggers.LoggerAPK.Debugf("API validation Skipped for namespace: %v", r.Namespace) + return nil + } + } + + if r.Spec.BasePath == "" { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("basePath"), "API basePath is required")) + } else if errMsg := validateAPIBasePathRegex(r.Spec.BasePath, r.Spec.APIType); errMsg != "" { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("basePath"), r.Spec.BasePath, errMsg)) + } else if errMsg := validateAPIBasePathFormat(r.Spec.BasePath, r.Spec.APIVersion); errMsg != "" { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("basePath"), r.Spec.BasePath, errMsg)) + } else if err := r.validateAPIBasePathExistsAndDefaultVersion(); err != nil { + allErrs = append(allErrs, err) + } + + if r.Spec.DefinitionFileRef != "" { + if schemaString, errMsg := validateGzip(r.Spec.DefinitionFileRef, r.Namespace); errMsg != "" { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("definitionFileRef"), r.Spec.DefinitionFileRef, errMsg)) + } else if schemaString != "" && r.Spec.APIType == "GraphQL" { + if errMsg := validateSDL(schemaString); errMsg != "" { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("definitionFileRef"), r.Spec.DefinitionFileRef, errMsg)) + } + } + } else if r.Spec.APIType == "GraphQL" { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("definitionFileRef"), "GraphQL API definitionFileRef is required")) + } + + // Organization value should not be empty as it required when applying ratelimit policy + if r.Spec.Organization == "" { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("organization"), "Organization can not be empty")) + } + + if !(len(r.Spec.Production) > 0 && r.Spec.Production[0].RouteRefs != nil && len(r.Spec.Production[0].RouteRefs) > 0) && + !(len(r.Spec.Sandbox) > 0 && r.Spec.Sandbox[0].RouteRefs != nil && len(r.Spec.Sandbox[0].RouteRefs) > 0) { + allErrs = append(allErrs, field.Required(field.NewPath("spec"), + "both API production and sandbox endpoint references cannot be empty")) + } + + var prodHTTPRoute1, sandHTTPRoute1 []string + if len(r.Spec.Production) > 0 { + prodHTTPRoute1 = r.Spec.Production[0].RouteRefs + } + if len(r.Spec.Sandbox) > 0 { + sandHTTPRoute1 = r.Spec.Sandbox[0].RouteRefs + } + + if isEmptyStringsInArray(prodHTTPRoute1) { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("production").Child("httpRouteRefs"), + "API production endpoint reference cannot be empty")) + } + + if isEmptyStringsInArray(sandHTTPRoute1) { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("sandbox").Child("httpRouteRefs"), + "API sandbox endpoint reference cannot be empty")) + } + + if len(allErrs) > 0 { + return apierrors.NewInvalid( + schema.GroupKind{Group: "dp.wso2.com", Kind: "API"}, + r.Name, allErrs) + } + + return nil +} + +func isEmptyStringsInArray(strings []string) bool { + for _, str := range strings { + if str == "" { + return true + } + } + return false +} + +func (r *API) validateAPIBasePathExistsAndDefaultVersion() *field.Error { + + apiList, err := retrieveAPIList() + if err != nil { + return field.InternalError(field.NewPath("spec").Child("basePath"), + errors.New("unable to list APIs for API basePath validation")) + + } + currentAPIBasePathWithoutVersion := getBasePathWithoutVersion(r.Spec.BasePath) + incomingAPIEnvironment := utils.GetEnvironment(r.Spec.Environment) + for _, api := range apiList { + if (types.NamespacedName{Namespace: r.Namespace, Name: r.Name} != + types.NamespacedName{Namespace: api.Namespace, Name: api.Name}) { + + existingAPIEnvironment := utils.GetEnvironment(api.Spec.Environment) + if api.Spec.Organization == r.Spec.Organization && api.Spec.BasePath == r.Spec.BasePath && + incomingAPIEnvironment == existingAPIEnvironment { + return &field.Error{ + Type: field.ErrorTypeDuplicate, + Field: field.NewPath("spec").Child("basePath").String(), + BadValue: r.Spec.BasePath, + Detail: "an API has been already created for the basePath"} + } + if r.Spec.IsDefaultVersion { + targetAPIBasePathWithoutVersion := getBasePathWithoutVersion(api.Spec.BasePath) + targetAPIBasePathWithVersion := api.Spec.BasePath + if api.Spec.IsDefaultVersion { + if targetAPIBasePathWithoutVersion == currentAPIBasePathWithoutVersion { + return &field.Error{ + Type: field.ErrorTypeForbidden, + Field: field.NewPath("spec").Child("isDefaultVersion").String(), + BadValue: r.Spec.BasePath, + Detail: "this API already has a default version"} + } + + } + if targetAPIBasePathWithVersion == currentAPIBasePathWithoutVersion { + return &field.Error{ + Type: field.ErrorTypeForbidden, + Field: field.NewPath("spec").Child("isDefaultVersion").String(), + BadValue: r.Spec.BasePath, + Detail: fmt.Sprintf("api: %s's basePath path is colliding with default path", r.Name)} + } + } + } + } + return nil +} + +func retrieveAPIList() ([]API, error) { + ctx := context.Background() + conf := config.ReadConfigs() + namespaces := conf.CommonController.Operator.Namespaces + var apis []API + if namespaces == nil { + apiList := &APIList{} + if err := c.List(ctx, apiList, &client.ListOptions{}); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2605, logging.CRITICAL, "Unable to list APIs: %v", err.Error())) + return nil, err + } + apis = make([]API, len(apiList.Items)) + copy(apis[:], apiList.Items[:]) + } else { + for _, namespace := range namespaces { + apiList := &APIList{} + if err := c.List(ctx, apiList, &client.ListOptions{Namespace: namespace}); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2605, logging.CRITICAL, "Unable to list APIs: %v", err.Error())) + return nil, err + } + apis = append(apis, apiList.Items...) + } + } + return apis, nil +} + +func validateAPIBasePathFormat(basePath string, apiVersion string) string { + if !strings.HasSuffix("/"+basePath, apiVersion) { + return "API basePath value should contain the /{APIVersion} at end." + } + return "" +} + +func validateAPIBasePathRegex(basePath, apiType string) string { + var pattern string + if apiType == "GRPC" { + pattern = `^[/][a-zA-Z][a-zA-Z0-9_.]*$` + } else { + pattern = `^[/][a-zA-Z0-9~/_.-]*$` + } + re, err := regexp.Compile(pattern) + if err != nil { + return "Failed to compile basePath regex pattern" + } + if !re.MatchString(basePath) { + return "API basePath is not in a valid format for the specified API type" + } + return "" +} + +// getBasePathWithoutVersion returns the basePath without version +func getBasePathWithoutVersion(basePath string) string { + lastIndex := strings.LastIndex(basePath, "/") + if lastIndex != -1 { + return basePath[:lastIndex] + } + return basePath +} + +func validateGzip(name, namespace string) (string, string) { + configMap := &corev1.ConfigMap{} + var err error + + if err = c.Get(context.Background(), types.NamespacedName{Name: string(name), Namespace: namespace}, configMap); err == nil { + var apiDef []byte + for _, val := range configMap.BinaryData { + // config map data key is "swagger.yaml" + apiDef = []byte(val) + } + // unzip gzip bytes + var schemaString string + if schemaString, err = unzip(apiDef); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2600, logging.MINOR, "Error while unzipping gzip bytes: %v", err)) + return "", "invalid gzipped content" + } + return schemaString, "" + } + + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2600, logging.MINOR, "ConfigMap for sdl not found: %v", err)) + + return "", "" +} + +// unzip gzip bytes +func unzip(compressedData []byte) (string, error) { + reader, err := gzip.NewReader(bytes.NewBuffer(compressedData)) + if err != nil { + return "", fmt.Errorf("error creating gzip reader: %v", err) + } + defer reader.Close() + + // Read the decompressed data + schemaString, err := io.ReadAll(reader) + if err != nil { + return "", fmt.Errorf("error reading decompressed data of the apiDefinition: %v", err) + } + return string(schemaString), nil +} + +func validateSDL(sdl string) string { + _, err := gqlparser.LoadSchema(&ast.Source{Input: sdl}) + if err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2600, logging.MINOR, "Error while parsing the GraphQL SDL: %v", err)) + return "error while parsing the GraphQL SDL" + } + return "" +} diff --git a/common-go-libs/apis/dp/v1beta1/groupversion_info.go b/common-go-libs/apis/dp/v1beta1/groupversion_info.go new file mode 100644 index 000000000..9f7ad3d00 --- /dev/null +++ b/common-go-libs/apis/dp/v1beta1/groupversion_info.go @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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 v1beta1 contains API Schema definitions for the dp v1beta1 API group +// +kubebuilder:object:generate=true +// +groupName=dp.wso2.com +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "dp.wso2.com", Version: "v1beta1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/common-go-libs/apis/dp/v1beta1/zz_generated.deepcopy.go b/common-go-libs/apis/dp/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 000000000..79cffd6db --- /dev/null +++ b/common-go-libs/apis/dp/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,195 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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. + * + */ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *API) DeepCopyInto(out *API) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new API. +func (in *API) DeepCopy() *API { + if in == nil { + return nil + } + out := new(API) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *API) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIList) DeepCopyInto(out *APIList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]API, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIList. +func (in *APIList) DeepCopy() *APIList { + if in == nil { + return nil + } + out := new(APIList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *APIList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APISpec) DeepCopyInto(out *APISpec) { + *out = *in + if in.Production != nil { + in, out := &in.Production, &out.Production + *out = make([]EnvConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Sandbox != nil { + in, out := &in.Sandbox, &out.Sandbox + *out = make([]EnvConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.APIProperties != nil { + in, out := &in.APIProperties, &out.APIProperties + *out = make([]Property, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APISpec. +func (in *APISpec) DeepCopy() *APISpec { + if in == nil { + return nil + } + out := new(APISpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIStatus) DeepCopyInto(out *APIStatus) { + *out = *in + in.DeploymentStatus.DeepCopyInto(&out.DeploymentStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIStatus. +func (in *APIStatus) DeepCopy() *APIStatus { + if in == nil { + return nil + } + out := new(APIStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) { + *out = *in + if in.TransitionTime != nil { + in, out := &in.TransitionTime, &out.TransitionTime + *out = (*in).DeepCopy() + } + if in.Events != nil { + in, out := &in.Events, &out.Events + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentStatus. +func (in *DeploymentStatus) DeepCopy() *DeploymentStatus { + if in == nil { + return nil + } + out := new(DeploymentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvConfig) DeepCopyInto(out *EnvConfig) { + *out = *in + if in.RouteRefs != nil { + in, out := &in.RouteRefs, &out.RouteRefs + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvConfig. +func (in *EnvConfig) DeepCopy() *EnvConfig { + if in == nil { + return nil + } + out := new(EnvConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Property) DeepCopyInto(out *Property) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Property. +func (in *Property) DeepCopy() *Property { + if in == nil { + return nil + } + out := new(Property) + in.DeepCopyInto(out) + return out +} diff --git a/common-go-libs/config/crd/bases/dp.wso2.com_apis.yaml b/common-go-libs/config/crd/bases/dp.wso2.com_apis.yaml index 7846de3ca..656e1ec56 100644 --- a/common-go-libs/config/crd/bases/dp.wso2.com_apis.yaml +++ b/common-go-libs/config/crd/bases/dp.wso2.com_apis.yaml @@ -243,10 +243,188 @@ spec: type: array apiType: description: APIType denotes the type of the API. Possible values - could be REST, GraphQL, Async + could be REST, GraphQL, Async, GRPC etc. enum: - REST - GraphQL + - GRPC + type: string + apiVersion: + description: APIVersion is the version number of the API. + maxLength: 30 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&/$\[\]\s+\/]+$ + type: string + basePath: + description: 'BasePath denotes the basepath of the API. e.g: /pet-store-api/1.0.6' + type: string + definitionFileRef: + description: DefinitionFileRef contains the definition of the API + in a ConfigMap. + type: string + definitionPath: + default: /api-definition + description: DefinitionPath contains the path to expose the API definition. + minLength: 1 + type: string + environment: + description: Environment denotes the environment of the API. + nullable: true + type: string + isDefaultVersion: + description: IsDefaultVersion indicates whether this API version should + be used as a default API + type: boolean + organization: + description: Organization denotes the organization. related to the + API + type: string + production: + description: 'Production contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + routeRefs: + description: RouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - routeRefs + type: object + maxItems: 1 + nullable: true + type: array + sandbox: + description: 'Sandbox contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + routeRefs: + description: RouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - routeRefs + type: object + maxItems: 1 + nullable: true + type: array + systemAPI: + description: SystemAPI denotes if it is an internal system API. + type: boolean + required: + - apiName + - apiType + - apiVersion + - basePath + - definitionPath + type: object + status: + description: APIStatus defines the observed state of API + properties: + deploymentStatus: + description: DeploymentStatus denotes the deployment status of the + API + properties: + accepted: + description: Accepted represents whether the API is accepted or + not. + type: boolean + events: + description: Events contains a list of events related to the API. + items: + type: string + type: array + message: + description: Message represents a user friendly message that explains + the current state of the API. + type: string + status: + description: Status denotes the state of the API in its lifecycle. + Possible values could be Accepted, Invalid, Deploy etc. + type: string + transitionTime: + description: TransitionTime represents the last known transition + timestamp. + format: date-time + type: string + required: + - accepted + - status + - transitionTime + type: object + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.apiName + name: API Name + type: string + - jsonPath: .spec.apiVersion + name: Version + type: string + - jsonPath: .spec.basePath + name: BasePath + type: string + - jsonPath: .spec.organization + name: Organization + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: API is the Schema for the apis API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APISpec defines the desired state of API + properties: + apiName: + description: APIName is the unique name of the API can be used to + uniquely identify an API. + maxLength: 60 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&$\[\]\/]*$ + type: string + apiProperties: + description: APIProperties denotes the custom properties of the API. + items: + description: Property holds key value pair of APIProperties + properties: + name: + type: string + value: + type: string + type: object + nullable: true + type: array + apiType: + description: APIType denotes the type of the API. Possible values + could be REST, GraphQL, Async, GRPC etc. + enum: + - REST + - GraphQL + - GRPC type: string apiVersion: description: APIVersion is the version number of the API. @@ -256,7 +434,6 @@ spec: type: string basePath: description: 'BasePath denotes the basepath of the API. e.g: /pet-store-api/1.0.6' - pattern: ^[/][a-zA-Z0-9~/_.-]*$ type: string definitionFileRef: description: DefinitionFileRef contains the definition of the API diff --git a/common-go-libs/config/crd/kustomization.yaml b/common-go-libs/config/crd/kustomization.yaml new file mode 100644 index 000000000..f5a7460e0 --- /dev/null +++ b/common-go-libs/config/crd/kustomization.yaml @@ -0,0 +1,21 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/dp.wso2.com_apis.yaml +#+kubebuilder:scaffold:crdkustomizeresource + +patchesStrategicMerge: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +#- patches/webhook_in_apis.yaml +#+kubebuilder:scaffold:crdkustomizewebhookpatch + +# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. +# patches here are for enabling the CA injection for each CRD +#- patches/cainjection_in_apis.yaml +#+kubebuilder:scaffold:crdkustomizecainjectionpatch + +# the following config is for teaching kustomize how to do kustomization for CRDs. +configurations: +- kustomizeconfig.yaml diff --git a/common-go-libs/config/crd/kustomizeconfig.yaml b/common-go-libs/config/crd/kustomizeconfig.yaml new file mode 100644 index 000000000..ec5c150a9 --- /dev/null +++ b/common-go-libs/config/crd/kustomizeconfig.yaml @@ -0,0 +1,19 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/common-go-libs/config/crd/patches/cainjection_in_dp_apis.yaml b/common-go-libs/config/crd/patches/cainjection_in_dp_apis.yaml new file mode 100644 index 000000000..7f949667b --- /dev/null +++ b/common-go-libs/config/crd/patches/cainjection_in_dp_apis.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: apis.dp.wso2.com diff --git a/common-go-libs/config/crd/patches/webhook_in_dp_apis.yaml b/common-go-libs/config/crd/patches/webhook_in_dp_apis.yaml new file mode 100644 index 000000000..ad0c609d5 --- /dev/null +++ b/common-go-libs/config/crd/patches/webhook_in_dp_apis.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: apis.dp.wso2.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/common-go-libs/config/rbac/dp_api_editor_role.yaml b/common-go-libs/config/rbac/dp_api_editor_role.yaml new file mode 100644 index 000000000..2de3070c5 --- /dev/null +++ b/common-go-libs/config/rbac/dp_api_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit apis. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: api-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: api-editor-role +rules: +- apiGroups: + - dp.wso2.com + resources: + - apis + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - dp.wso2.com + resources: + - apis/status + verbs: + - get diff --git a/common-go-libs/config/rbac/dp_api_viewer_role.yaml b/common-go-libs/config/rbac/dp_api_viewer_role.yaml new file mode 100644 index 000000000..75e4c488a --- /dev/null +++ b/common-go-libs/config/rbac/dp_api_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view apis. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: api-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: api-viewer-role +rules: +- apiGroups: + - dp.wso2.com + resources: + - apis + verbs: + - get + - list + - watch +- apiGroups: + - dp.wso2.com + resources: + - apis/status + verbs: + - get diff --git a/common-go-libs/config/rbac/role.yaml b/common-go-libs/config/rbac/role.yaml new file mode 100644 index 000000000..44306fcc6 --- /dev/null +++ b/common-go-libs/config/rbac/role.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manager-role +rules: +- apiGroups: + - dp.wso2.com + resources: + - apis + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - dp.wso2.com + resources: + - apis/finalizers + verbs: + - update +- apiGroups: + - dp.wso2.com + resources: + - apis/status + verbs: + - get + - patch + - update diff --git a/common-go-libs/config/samples/dp_v1beta1_api.yaml b/common-go-libs/config/samples/dp_v1beta1_api.yaml new file mode 100644 index 000000000..0e8e11b32 --- /dev/null +++ b/common-go-libs/config/samples/dp_v1beta1_api.yaml @@ -0,0 +1,12 @@ +apiVersion: dp.wso2.com/v1beta1 +kind: Api +metadata: + labels: + app.kubernetes.io/name: api + app.kubernetes.io/instance: api-sample + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operator + name: api-sample +spec: + # TODO(user): Add fields here diff --git a/common-go-libs/config/webhook/manifests.yaml b/common-go-libs/config/webhook/manifests.yaml index 411ed6ee8..0df6a571a 100644 --- a/common-go-libs/config/webhook/manifests.yaml +++ b/common-go-libs/config/webhook/manifests.yaml @@ -10,7 +10,7 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-dp-wso2-com-v1alpha2-api + path: /mutate-dp-wso2-com-v1beta1-api failurePolicy: Fail name: mapi.kb.io rules: @@ -30,9 +30,9 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-dp-wso2-com-v1alpha2-apipolicy + path: /mutate-dp-wso2-com-v1alpha2-api failurePolicy: Fail - name: mapipolicy.kb.io + name: mapi.kb.io rules: - apiGroups: - dp.wso2.com @@ -42,7 +42,7 @@ webhooks: - CREATE - UPDATE resources: - - apipolicies + - apis sideEffects: None - admissionReviewVersions: - v1 @@ -50,9 +50,9 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-dp-wso2-com-v1alpha2-authentication + path: /mutate-dp-wso2-com-v1alpha2-apipolicy failurePolicy: Fail - name: mauthentication.kb.io + name: mapipolicy.kb.io rules: - apiGroups: - dp.wso2.com @@ -62,7 +62,7 @@ webhooks: - CREATE - UPDATE resources: - - authentications + - apipolicies sideEffects: None - admissionReviewVersions: - v1 @@ -70,19 +70,19 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-dp-wso2-com-v1alpha1-apipolicy + path: /mutate-dp-wso2-com-v1alpha2-authentication failurePolicy: Fail - name: mapipolicy.kb.io + name: mauthentication.kb.io rules: - apiGroups: - dp.wso2.com apiVersions: - - v1alpha1 + - v1alpha2 operations: - CREATE - UPDATE resources: - - apipolicies + - authentications sideEffects: None - admissionReviewVersions: - v1 @@ -90,9 +90,9 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-dp-wso2-com-v1alpha1-authentication + path: /mutate-dp-wso2-com-v1alpha1-apipolicy failurePolicy: Fail - name: mauthentication.kb.io + name: mapipolicy.kb.io rules: - apiGroups: - dp.wso2.com @@ -102,7 +102,7 @@ webhooks: - CREATE - UPDATE resources: - - authentications + - apipolicies sideEffects: None - admissionReviewVersions: - v1 @@ -196,7 +196,7 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-dp-wso2-com-v1alpha2-api + path: /validate-dp-wso2-com-v1beta1-api failurePolicy: Fail name: vapi.kb.io rules: @@ -216,9 +216,9 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-dp-wso2-com-v1alpha2-apipolicy + path: /validate-dp-wso2-com-v1alpha2-api failurePolicy: Fail - name: vapipolicy.kb.io + name: vapi.kb.io rules: - apiGroups: - dp.wso2.com @@ -228,7 +228,7 @@ webhooks: - CREATE - UPDATE resources: - - apipolicies + - apis sideEffects: None - admissionReviewVersions: - v1 @@ -236,9 +236,9 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-dp-wso2-com-v1alpha2-authentication + path: /validate-dp-wso2-com-v1alpha2-apipolicy failurePolicy: Fail - name: vauthentication.kb.io + name: vapipolicy.kb.io rules: - apiGroups: - dp.wso2.com @@ -248,7 +248,7 @@ webhooks: - CREATE - UPDATE resources: - - authentications + - apipolicies sideEffects: None - admissionReviewVersions: - v1 @@ -256,19 +256,19 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-dp-wso2-com-v1alpha1-apipolicy + path: /validate-dp-wso2-com-v1alpha2-authentication failurePolicy: Fail - name: vapipolicy.kb.io + name: vauthentication.kb.io rules: - apiGroups: - dp.wso2.com apiVersions: - - v1alpha1 + - v1alpha2 operations: - CREATE - UPDATE resources: - - apipolicies + - authentications sideEffects: None - admissionReviewVersions: - v1 @@ -276,9 +276,9 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-dp-wso2-com-v1alpha1-authentication + path: /validate-dp-wso2-com-v1alpha1-apipolicy failurePolicy: Fail - name: vauthentication.kb.io + name: vapipolicy.kb.io rules: - apiGroups: - dp.wso2.com @@ -288,7 +288,7 @@ webhooks: - CREATE - UPDATE resources: - - authentications + - apipolicies sideEffects: None - admissionReviewVersions: - v1 diff --git a/common-go-libs/controllers/dp/suite_test.go b/common-go-libs/controllers/dp/suite_test.go new file mode 100644 index 000000000..ebb404125 --- /dev/null +++ b/common-go-libs/controllers/dp/suite_test.go @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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 dp + +import ( + "path/filepath" + "testing" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + dpv1beta1 "github.com/wso2/apk/common-go-libs/apis/dp/v1beta1" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestAPIs(t *testing.T) { + gomega.RegisterFailHandler(ginkgo.Fail) + + ginkgo.RunSpecs(t, "Controller Suite") +} + +var _ = ginkgo.BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(ginkgo.GinkgoWriter), zap.UseDevMode(true))) + + ginkgo.By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Expect(cfg).NotTo(gomega.BeNil()) + + err = dpv1beta1.AddToScheme(scheme.Scheme) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Expect(k8sClient).NotTo(gomega.BeNil()) + +}) + +var _ = ginkgo.AfterSuite(func() { + ginkgo.By("tearing down the test environment") + err := testEnv.Stop() + gomega.Expect(err).NotTo(gomega.HaveOccurred()) +}) diff --git a/common-go-libs/coverage.out b/common-go-libs/coverage.out new file mode 100644 index 000000000..ccf60e676 --- /dev/null +++ b/common-go-libs/coverage.out @@ -0,0 +1,1186 @@ +mode: atomic +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:27.56,43.32 12 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:43.32,45.53 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:45.53,49.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:51.2,51.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:51.29,53.47 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:53.47,57.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:61.2,62.43 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:62.43,64.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:65.2,70.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:75.58,91.32 12 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:91.32,93.53 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:93.53,97.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:100.2,100.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:100.29,102.47 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:102.47,106.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:110.2,111.43 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:111.43,113.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_conversion.go:114.2,119.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_types.go:194.13,196.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/api_webhook.go:25.63,29.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:28.62,32.29 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:32.29,34.47 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:34.47,37.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:38.3,38.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:38.41,47.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:48.3,48.50 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:48.50,50.69 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:50.69,53.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:55.3,55.51 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:55.51,57.70 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:57.70,60.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:62.3,63.36 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:66.2,66.30 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:66.30,68.48 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:68.48,71.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:72.3,72.42 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:72.42,81.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:82.3,82.51 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:82.51,84.70 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:84.70,87.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:89.3,89.52 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:89.52,91.71 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:91.71,94.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:96.3,97.37 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:99.2,99.35 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:99.35,104.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:105.2,105.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:110.64,115.29 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:115.29,117.47 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:117.47,120.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:121.3,121.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:121.41,129.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:130.3,130.50 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:130.50,132.69 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:132.69,135.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:137.3,137.51 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:137.51,139.70 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:139.70,142.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:144.3,144.36 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:146.2,146.30 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:146.30,148.48 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:148.48,151.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:152.3,152.42 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:152.42,160.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:161.3,161.51 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:161.51,163.70 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:163.70,166.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:168.3,168.52 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:168.52,170.71 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:170.71,173.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:175.3,175.37 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:177.2,177.35 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:177.35,182.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_conversion.go:183.2,183.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_types.go:138.13,140.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:33.69,37.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:46.32,46.33 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:54.66,56.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:59.84,61.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:64.44,67.33 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:67.33,69.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:70.2,71.51 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:71.51,74.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:75.2,75.107 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:75.107,78.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:79.2,79.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:79.22,83.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:84.2,84.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/apipolicy_webhook.go:88.66,91.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:27.67,34.29 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:34.29,38.41 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:38.41,47.66 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:47.66,54.5 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:55.4,55.76 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:55.76,60.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:61.4,61.60 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:63.3,63.48 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:66.2,66.30 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:66.30,70.42 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:70.42,79.67 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:79.67,86.5 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:87.4,87.77 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:87.77,92.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:93.4,93.61 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:95.3,95.50 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:99.2,100.12 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:105.69,112.29 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:112.29,116.41 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:116.41,124.66 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:124.66,131.5 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:132.4,136.60 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:138.3,138.48 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:141.2,141.30 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:141.30,145.42 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:145.42,153.67 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:153.67,160.5 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:161.4,165.61 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:167.3,167.50 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go:170.2,172.12 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_types.go:142.13,144.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/authentication_webhook.go:25.74,29.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_types.go:280.13,282.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:35.67,39.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:48.29,52.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:60.64,62.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:65.82,67.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:70.64,75.2 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:77.47,80.24 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:80.24,81.54 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:81.54,82.44 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:82.44,85.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:89.2,89.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:89.22,93.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backend_webhook.go:94.2,94.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_types.go:109.13,111.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:34.70,38.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:47.33,49.2 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:57.67,60.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:63.85,66.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:68.48,71.31 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:71.31,73.18 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:74.14,75.55 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:75.55,77.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:78.16,79.65 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:79.65,81.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:82.15,83.60 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:83.60,85.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:86.15,87.67 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:87.67,89.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:90.15,91.67 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:91.67,93.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:97.2,97.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:97.22,101.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:102.2,102.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/backendjwt_webhook.go:106.67,109.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/custom_ratelimit_policy.go:32.94,40.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/interceptorservice_types.go:91.13,93.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/interceptorservice_webhook.go:28.78,32.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/interceptorservice_webhook.go:41.41,41.42 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/interceptorservice_webhook.go:49.75,52.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/interceptorservice_webhook.go:55.93,58.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/interceptorservice_webhook.go:61.75,64.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_types.go:114.13,116.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:33.75,37.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:46.38,48.2 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:56.72,60.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:63.90,67.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:70.72,74.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:77.52,79.33 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:79.33,82.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:83.2,84.51 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:84.51,87.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:88.2,88.107 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:88.107,91.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:93.2,93.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:93.22,97.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/ratelimitpolicy_webhook.go:98.2,98.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/scope_types.go:66.13,68.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenIssuer_types.go:129.13,131.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:27.64,39.41 8 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:39.41,42.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:42.22,47.23 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:47.23,49.42 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:49.42,51.6 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:52.5,52.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:52.34,57.6 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:58.5,58.37 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:58.37,63.6 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:65.4,65.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:67.3,67.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:67.29,72.36 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:72.36,77.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:78.4,78.39 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:78.39,83.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:84.4,84.48 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:86.3,86.57 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:88.2,88.35 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:88.35,91.45 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:91.45,93.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:94.3,94.42 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:96.2,97.12 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:102.66,114.41 8 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:114.41,117.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:117.22,122.23 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:122.23,124.42 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:124.42,126.6 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:127.5,127.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:127.34,132.6 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:133.5,133.37 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:133.37,138.6 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:140.4,140.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:142.3,142.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:142.29,147.36 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:147.36,152.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:153.4,153.39 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:153.39,158.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:159.4,159.48 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:161.3,161.57 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:163.2,163.35 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:163.35,166.45 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:166.45,168.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:169.3,169.42 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/tokenissuer_conversion.go:171.2,172.12 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:31.39,37.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:40.32,41.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:41.15,43.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:44.2,46.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:50.48,51.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:51.34,53.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:54.2,54.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:58.47,61.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:61.22,65.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:66.2,66.40 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:70.40,71.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:71.15,73.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:74.2,76.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:80.53,82.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:85.46,86.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:86.15,88.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:89.2,91.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:95.47,99.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:99.21,102.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:102.22,104.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:109.40,110.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:110.15,112.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:113.2,115.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:119.52,120.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:120.34,122.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:123.2,123.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:127.51,133.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:136.44,137.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:137.15,139.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:140.2,142.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:146.54,147.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:147.34,149.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:150.2,150.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:154.59,158.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:158.21,161.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:161.22,163.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:168.52,169.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:169.15,171.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:172.2,174.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:178.58,179.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:179.34,181.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:182.2,182.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:186.59,188.23 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:188.23,192.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:193.2,193.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:193.24,197.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:198.2,198.43 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:202.52,203.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:203.15,205.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:206.2,208.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:212.63,214.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:217.56,218.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:218.15,220.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:221.2,223.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:227.69,229.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:232.62,233.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:233.15,235.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:236.2,238.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:242.47,244.26 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:244.26,247.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:247.22,249.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:251.2,251.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:251.23,254.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:254.22,256.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:258.2,258.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:258.29,262.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:266.40,267.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:267.15,269.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:270.2,272.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:276.51,279.2 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:282.44,283.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:283.15,285.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:286.2,288.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:292.49,294.24 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:294.24,298.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:299.2,299.25 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:299.25,303.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:307.42,308.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:308.15,310.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:311.2,313.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:317.61,323.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:326.54,327.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:327.15,329.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:330.2,332.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:336.59,337.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:337.34,339.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:340.2,340.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:344.69,348.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:348.21,351.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:351.22,353.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:358.62,359.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:359.15,361.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:362.2,364.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:368.63,369.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:369.34,371.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:372.2,372.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:376.69,378.23 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:378.23,382.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:383.2,383.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:383.24,387.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:388.2,388.43 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:392.62,393.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:393.15,395.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:396.2,398.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:402.73,404.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:407.66,408.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:408.15,410.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:411.2,413.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:417.47,423.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:426.40,427.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:427.15,429.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:430.2,432.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:436.52,437.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:437.34,439.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:440.2,440.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:444.53,450.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:453.46,454.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:454.15,456.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:457.2,459.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:463.55,464.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:464.34,466.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:467.2,467.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:471.61,475.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:475.21,478.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:478.22,480.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:485.54,486.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:486.15,488.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:489.2,491.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:495.59,496.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:496.34,498.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:499.2,499.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:503.61,505.28 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:505.28,509.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:513.54,514.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:514.15,516.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:517.2,519.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:523.65,525.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:528.58,529.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:529.15,531.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:532.2,534.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:538.63,540.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:543.56,544.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:544.15,546.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:547.2,549.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:553.55,557.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:557.21,560.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:560.22,562.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:567.48,568.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:568.15,570.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:571.2,573.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:577.56,578.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:578.34,580.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:581.2,581.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:585.65,587.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:590.58,591.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:591.15,593.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:594.2,596.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:600.55,602.24 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:602.24,606.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:607.2,607.19 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:607.19,611.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:612.2,612.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:612.24,616.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:617.2,617.30 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:617.30,621.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:622.2,622.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:622.23,626.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:627.2,627.21 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:627.21,631.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:632.2,632.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:632.27,636.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:640.48,641.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:641.15,643.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:644.2,646.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:650.59,652.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:655.52,656.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:656.15,658.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:659.2,661.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:665.71,668.2 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:671.64,672.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:672.15,674.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:675.2,677.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:681.53,683.33 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:683.33,687.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:688.2,688.25 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:688.25,692.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:693.2,693.28 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:693.28,697.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:701.46,702.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:702.15,704.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:705.2,707.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:711.53,713.41 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:713.41,717.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:718.2,718.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:718.41,722.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:723.2,723.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:723.41,727.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:728.2,728.42 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:728.42,732.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:733.2,733.35 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:733.35,737.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:741.46,742.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:742.15,744.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:745.2,747.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:751.61,753.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:756.54,757.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:757.15,759.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:760.2,762.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:766.57,768.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:771.50,772.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:772.15,774.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:775.2,777.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:781.55,783.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:786.48,787.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:787.15,789.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:790.2,792.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:796.75,798.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:801.68,802.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:802.15,804.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:805.2,807.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:811.81,813.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:816.74,817.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:817.15,819.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:820.2,822.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:826.65,828.30 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:828.30,831.3 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:832.2,832.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:832.22,836.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:840.58,841.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:841.15,843.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:844.2,846.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:850.51,852.29 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:852.29,856.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:860.44,861.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:861.15,863.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:864.2,866.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:870.55,872.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:875.48,876.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:876.15,878.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:879.2,881.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:885.73,887.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:890.66,891.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:891.15,893.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:894.2,896.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:900.69,906.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:909.62,910.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:910.15,912.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:913.2,915.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:919.63,920.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:920.34,922.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:923.2,923.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:927.77,931.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:931.21,934.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:934.22,936.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:941.70,942.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:942.15,944.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:945.2,947.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:951.67,952.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:952.34,954.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:955.2,955.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:959.77,962.24 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:962.24,966.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:970.70,971.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:971.15,973.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:974.2,976.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:980.81,982.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:985.74,986.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:986.15,988.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:989.2,991.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:995.41,997.19 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:997.19,1001.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1005.34,1006.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1006.15,1008.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1009.2,1011.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1015.64,1016.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1016.2,1019.29 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1019.29,1021.18 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1021.18,1023.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1023.10,1027.5 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1028.4,1028.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1034.56,1035.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1035.15,1037.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1038.2,1040.13 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1044.53,1046.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1049.46,1050.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1050.15,1052.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1053.2,1055.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1059.53,1061.35 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1061.35,1065.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1066.2,1066.36 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1066.36,1070.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1071.2,1071.32 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1071.32,1075.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1076.2,1076.26 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1076.26,1080.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1084.46,1085.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1085.15,1087.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1088.2,1090.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1094.49,1096.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1099.42,1100.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1100.15,1102.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1103.2,1105.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1109.69,1111.19 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1111.19,1115.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1116.2,1116.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1116.22,1120.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1124.62,1125.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1125.15,1127.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1128.2,1130.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1134.63,1140.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1143.56,1144.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1144.15,1146.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1147.2,1149.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1153.60,1154.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1154.34,1156.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1157.2,1157.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1161.71,1165.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1165.21,1168.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1168.22,1170.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1175.64,1176.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1176.15,1178.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1179.2,1181.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1185.64,1186.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1186.34,1188.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1189.2,1189.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1193.71,1195.23 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1195.23,1199.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1200.2,1200.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1200.24,1204.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1205.2,1205.43 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1209.64,1210.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1210.15,1212.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1213.2,1215.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1219.75,1221.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1224.68,1225.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1225.15,1227.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1228.2,1230.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1234.51,1236.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1239.44,1240.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1240.15,1242.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1243.2,1245.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1249.65,1251.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1254.58,1255.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1255.15,1257.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1258.2,1260.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1264.83,1267.25 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1267.25,1271.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1275.76,1276.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1276.15,1278.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1279.2,1281.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1285.63,1288.2 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1291.56,1292.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1292.15,1294.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1295.2,1297.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1301.63,1304.24 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1304.24,1308.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1309.2,1311.30 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1311.30,1315.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1316.2,1316.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1316.23,1320.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1321.2,1321.21 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1321.21,1325.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1326.2,1326.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1326.27,1330.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1334.56,1335.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1335.15,1337.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1338.2,1340.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1344.87,1346.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1349.80,1350.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1350.15,1352.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1353.2,1355.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1359.57,1361.19 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1361.19,1365.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1369.50,1370.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1370.15,1372.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1373.2,1375.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1379.67,1382.29 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1382.29,1385.29 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1385.29,1387.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1389.2,1389.28 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1389.28,1393.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1397.60,1398.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1398.15,1400.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1401.2,1403.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1407.77,1410.2 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1413.70,1414.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1414.15,1416.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1417.2,1419.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1423.87,1425.20 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1425.20,1429.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1430.2,1430.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1430.27,1434.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1438.80,1439.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1439.15,1441.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1442.2,1444.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1448.67,1450.27 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1450.27,1454.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1458.60,1459.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1459.15,1461.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1462.2,1464.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1468.55,1470.27 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1470.27,1474.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1478.48,1479.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1479.15,1481.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1482.2,1484.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1488.43,1494.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1497.36,1498.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1498.15,1500.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1501.2,1503.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1507.50,1508.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1508.34,1510.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1511.2,1511.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1515.51,1519.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1519.21,1522.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1522.22,1524.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1529.44,1530.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1530.15,1532.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1533.2,1535.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1539.54,1540.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1540.34,1542.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1543.2,1543.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1547.51,1549.21 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1549.21,1553.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1557.44,1558.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1558.15,1560.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1561.2,1563.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1567.55,1569.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1572.48,1573.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1573.15,1575.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1576.2,1578.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1582.51,1584.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1587.44,1588.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1588.15,1590.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1591.2,1593.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1597.61,1599.21 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1599.21,1603.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1607.54,1608.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1608.15,1610.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1611.2,1613.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1617.47,1619.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1622.40,1623.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1623.15,1625.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1626.2,1628.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1632.71,1634.20 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1634.20,1638.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1639.2,1639.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1639.27,1643.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1647.64,1648.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1648.15,1650.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1651.2,1653.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1657.51,1659.33 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1659.33,1663.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1664.2,1664.25 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1664.25,1668.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1669.2,1669.28 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1669.28,1673.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1674.2,1674.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1674.27,1678.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1682.44,1683.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1683.15,1685.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1686.2,1688.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1692.69,1694.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1697.62,1698.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1698.15,1700.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1701.2,1703.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1707.47,1709.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1712.40,1713.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1713.15,1715.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1716.2,1718.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1722.55,1728.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1731.48,1732.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1732.15,1734.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1735.2,1737.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1741.56,1742.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1742.34,1744.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1745.2,1745.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1749.63,1753.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1753.21,1756.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1756.22,1758.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1763.56,1764.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1764.15,1766.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1767.2,1769.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1773.60,1774.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1774.34,1776.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1777.2,1777.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1781.63,1783.35 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1783.35,1787.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1788.2,1788.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1788.29,1791.18 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1791.18,1795.4 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1797.2,1797.25 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1797.25,1801.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1805.56,1806.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1806.15,1808.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1809.2,1811.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1815.67,1817.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1820.60,1821.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1821.15,1823.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1/zz_generated.deepcopy.go:1824.2,1826.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:27.56,43.32 12 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:43.32,45.53 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:45.53,49.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:51.2,51.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:51.29,53.47 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:53.47,57.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:61.2,62.43 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:62.43,64.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:65.2,70.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:75.58,91.32 12 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:91.32,93.53 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:93.53,97.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:100.2,100.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:100.29,102.47 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:102.47,106.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:110.2,111.43 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:111.43,113.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_conversion.go:114.2,119.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_types.go:198.13,200.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:52.63,58.2 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:67.26,69.2 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:77.60,79.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:82.78,84.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:87.60,91.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:94.35,98.25 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:98.25,99.48 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:99.48,102.4 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:105.2,105.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:105.27,107.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:107.8,107.94 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:107.94,109.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:109.8,109.98 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:109.98,111.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:111.8,111.78 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:111.78,113.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:115.2,115.36 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:115.36,116.96 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:116.96,118.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:118.9,118.63 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:118.63,119.57 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:119.57,121.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:123.8,123.40 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:123.40,125.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:128.2,128.31 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:128.31,130.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:132.2,133.108 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:133.108,136.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:138.2,139.32 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:139.32,141.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:142.2,142.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:142.29,144.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:146.2,146.43 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:146.43,149.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:151.2,151.43 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:151.43,154.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:156.2,156.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:156.22,160.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:162.2,162.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:165.51,166.30 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:166.30,167.16 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:167.16,169.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:171.2,171.14 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:174.73,177.16 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:177.16,181.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:182.2,184.30 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:184.30,186.68 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:186.68,190.54 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:190.54,196.5 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:197.4,197.31 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:197.31,200.34 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:200.34,201.77 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:201.77,207.7 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:210.5,210.73 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:210.73,216.6 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:220.2,220.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:223.39,228.23 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:228.23,230.69 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:230.69,233.4 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:234.3,235.34 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:236.8,237.40 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:237.40,239.90 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:239.90,242.5 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:243.4,243.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:246.2,246.18 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:249.75,250.50 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:250.50,252.3 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:253.2,253.11 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:256.64,258.23 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:258.23,260.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:260.8,262.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:263.2,264.16 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:264.16,266.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:267.2,267.31 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:267.31,269.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:270.2,270.11 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:274.56,276.21 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:276.21,278.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:279.2,279.17 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:282.60,286.126 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:286.126,288.44 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:288.44,291.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:293.3,294.52 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:294.52,297.4 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:298.3,298.26 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:301.2,303.15 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:307.51,309.16 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:309.16,311.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:312.2,316.16 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:316.16,318.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:319.2,319.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:322.37,324.16 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:324.16,327.3 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/api_webhook.go:328.2,328.11 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_conversion.go:21.26,21.27 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_types.go:153.13,155.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:33.69,37.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:46.32,46.33 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:54.66,56.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:59.84,61.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:64.44,67.33 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:67.33,69.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:70.2,71.51 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:71.51,74.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:75.2,75.107 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:75.107,78.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:79.2,79.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:79.22,83.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:84.2,84.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/apipolicy_webhook.go:88.66,91.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_conversion.go:21.31,21.32 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_types.go:196.13,198.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:34.74,38.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:47.37,49.2 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:57.71,60.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:63.89,65.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:68.57,71.33 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:71.33,73.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:74.2,74.102 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:74.102,77.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:79.2,88.107 7 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:88.107,98.69 7 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:98.69,101.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:103.3,103.64 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:103.64,106.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:108.3,108.40 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:108.40,111.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:113.3,113.136 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:113.136,116.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:117.8,117.117 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:117.117,127.69 7 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:127.69,130.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:132.3,132.64 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:132.64,135.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:137.3,137.40 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:137.40,140.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:142.3,142.136 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:142.136,145.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:148.2,148.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:148.22,152.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:153.2,153.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go:157.71,160.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/gqlroute_types.go:136.13,138.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/tokenissuer_conversion.go:21.28,21.29 0 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/tokenissuer_types.go:149.13,151.2 1 1 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:32.39,38.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:41.32,42.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:42.15,44.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:45.2,47.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:51.48,52.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:52.34,54.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:55.2,55.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:59.47,62.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:62.22,66.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:67.2,68.25 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:68.25,72.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:76.40,77.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:77.15,79.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:80.2,82.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:86.53,88.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:91.46,92.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:92.15,94.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:95.2,97.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:101.47,105.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:105.21,108.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:108.22,110.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:115.40,116.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:116.15,118.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:119.2,121.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:125.52,126.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:126.34,128.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:129.2,129.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:133.51,139.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:142.44,143.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:143.15,145.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:146.2,148.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:152.54,153.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:153.34,155.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:156.2,156.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:160.59,164.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:164.21,167.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:167.22,169.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:174.52,175.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:175.15,177.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:178.2,180.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:184.58,185.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:185.34,187.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:188.2,188.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:192.59,194.23 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:194.23,198.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:199.2,199.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:199.24,203.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:204.2,204.43 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:208.52,209.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:209.15,211.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:212.2,214.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:218.63,220.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:223.56,224.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:224.15,226.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:227.2,229.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:233.47,235.26 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:235.26,238.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:238.22,240.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:242.2,242.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:242.23,245.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:245.22,247.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:249.2,249.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:249.29,253.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:257.40,258.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:258.15,260.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:261.2,263.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:267.51,270.2 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:273.44,274.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:274.15,276.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:277.2,279.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:283.49,285.24 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:285.24,289.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:290.2,290.25 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:290.25,294.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:298.42,299.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:299.15,301.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:302.2,304.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:308.61,314.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:317.54,318.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:318.15,320.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:321.2,323.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:327.59,328.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:328.34,330.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:331.2,331.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:335.69,339.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:339.21,342.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:342.22,344.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:349.62,350.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:350.15,352.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:353.2,355.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:359.63,360.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:360.34,362.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:363.2,363.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:367.69,369.23 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:369.23,373.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:374.2,374.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:374.24,378.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:379.2,379.43 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:383.62,384.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:384.15,386.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:387.2,389.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:393.73,395.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:398.66,399.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:399.15,401.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:402.2,404.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:408.63,410.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:413.56,414.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:414.15,416.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:417.2,419.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:423.53,425.33 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:425.33,429.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:430.2,430.25 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:430.25,434.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:435.2,435.28 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:435.28,439.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:443.46,444.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:444.15,446.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:447.2,449.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:453.53,455.41 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:455.41,459.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:460.2,460.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:460.41,464.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:465.2,465.41 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:465.41,469.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:470.2,470.42 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:470.42,474.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:475.2,475.35 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:475.35,479.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:483.46,484.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:484.15,486.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:487.2,489.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:493.57,495.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:498.50,499.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:499.15,501.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:502.2,504.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:508.65,510.30 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:510.30,513.3 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:514.2,514.22 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:514.22,518.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:522.58,523.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:523.15,525.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:526.2,528.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:532.51,534.25 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:534.25,538.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:542.44,543.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:543.15,545.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:546.2,548.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:552.49,558.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:561.42,562.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:562.15,564.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:565.2,567.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:571.53,572.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:572.34,574.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:575.2,575.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:579.61,581.28 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:581.28,585.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:589.54,590.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:590.15,592.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:593.2,595.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:599.57,603.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:603.21,606.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:606.22,608.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:613.50,614.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:614.15,616.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:617.2,619.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:623.57,624.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:624.34,626.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:627.2,627.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:631.59,633.20 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:633.20,637.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:638.2,638.20 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:638.20,642.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:646.52,647.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:647.15,649.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:650.2,652.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:656.59,658.23 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:658.23,661.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:661.22,663.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:665.2,665.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:665.23,668.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:668.22,670.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:675.52,676.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:676.15,678.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:679.2,681.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:685.57,688.25 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:688.25,692.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:693.2,693.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:693.27,696.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:696.22,698.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:700.2,700.21 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:700.21,703.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:703.22,705.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:710.50,711.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:711.15,713.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:714.2,716.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:720.61,722.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:725.54,726.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:726.15,728.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:729.2,731.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:735.73,737.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:740.66,741.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:741.15,743.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:744.2,746.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:750.41,752.19 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:752.19,756.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:760.34,761.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:761.15,763.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:764.2,766.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:770.39,772.24 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:772.24,776.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:777.2,777.24 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:777.24,781.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:785.32,786.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:786.15,788.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:789.2,791.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:795.51,797.34 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:797.34,801.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:805.44,806.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:806.15,808.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:809.2,811.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:815.63,817.34 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:817.34,820.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:820.22,821.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:821.23,825.5 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:828.2,828.26 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:828.26,831.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:831.22,832.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:832.23,836.5 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:839.2,839.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:839.29,842.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:842.22,843.23 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:843.23,847.5 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:853.56,854.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:854.15,856.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:857.2,859.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:863.53,865.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:868.46,869.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:869.15,871.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:872.2,874.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:878.53,880.35 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:880.35,884.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:885.2,885.36 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:885.36,889.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:890.2,890.32 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:890.32,894.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:895.2,895.26 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:895.26,899.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:903.46,904.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:904.15,906.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:907.2,909.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:913.49,915.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:918.42,919.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:919.15,921.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:922.2,924.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:928.51,930.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:933.44,934.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:934.15,936.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:937.2,939.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:943.71,945.20 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:945.20,949.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:950.2,950.27 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:950.27,954.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:958.64,959.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:959.15,961.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:962.2,964.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:968.55,974.2 5 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:977.48,978.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:978.15,980.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:981.2,983.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:987.56,988.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:988.34,990.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:991.2,991.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:995.63,999.21 4 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:999.21,1002.22 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1002.22,1004.4 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1009.56,1010.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1010.15,1012.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1013.2,1015.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1019.60,1020.34 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1020.34,1022.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1023.2,1023.12 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1027.63,1029.35 2 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1029.35,1033.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1034.2,1034.29 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1034.29,1037.18 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1037.18,1041.4 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1043.2,1043.25 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1043.25,1047.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1048.2,1048.28 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1048.28,1052.3 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1056.56,1057.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1057.15,1059.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1060.2,1062.12 3 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1066.67,1068.2 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1071.60,1072.15 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1072.15,1074.3 1 0 +github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go:1075.2,1077.12 3 0 +github.com/wso2/apk/common-go-libs/controllers/dp/api_controller.go:50.95,56.2 2 0 +github.com/wso2/apk/common-go-libs/controllers/dp/api_controller.go:59.66,63.2 1 0 diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/APIFactory.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/APIFactory.java index 58c9c3dd2..0b21aaf78 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/APIFactory.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/APIFactory.java @@ -78,6 +78,11 @@ public void addApis(List apis) { graphQLAPI.init(api); String apiKey = getApiKey(graphQLAPI); newApis.put(apiKey, graphQLAPI); + } else if (APIConstants.ApiType.GRPC.equals(api.getApiType())) { + GRPCAPI grpcAPI = new GRPCAPI(); + grpcAPI.init(api); + String apiKey = getApiKey(grpcAPI); + newApis.put(apiKey, grpcAPI); } else { RestAPI enforcerApi = new RestAPI(); enforcerApi.init(api); @@ -133,6 +138,11 @@ public byte[] getAPIDefinition(final String basePath, final String version, fina public ResourceConfig getMatchedResource(API api, String matchedResourcePath, String method) { List resourceConfigList = api.getAPIConfig().getResources(); + if (APIConstants.ApiType.GRPC.equals(api.getAPIConfig().getApiType())) { + return resourceConfigList.stream() + .filter(resourceConfig -> resourceConfig.getPath().equals(matchedResourcePath)) + .findFirst().orElse(null); + } return resourceConfigList.stream() .filter(resourceConfig -> resourceConfig.getPath().equals(matchedResourcePath)). filter(resourceConfig -> (method == null) || resourceConfig.getMethod() diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/GRPCAPI.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/GRPCAPI.java new file mode 100644 index 000000000..0ec44ae71 --- /dev/null +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/GRPCAPI.java @@ -0,0 +1,212 @@ +package org.wso2.apk.enforcer.api; + +import graphql.schema.idl.SchemaParser; +import graphql.schema.idl.TypeDefinitionRegistry; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.wso2.apk.enforcer.analytics.AnalyticsFilter; +import org.wso2.apk.enforcer.commons.Filter; +import org.wso2.apk.enforcer.commons.dto.ClaimValueDTO; +import org.wso2.apk.enforcer.commons.dto.JWTConfigurationDto; +import org.wso2.apk.enforcer.commons.model.APIConfig; +import org.wso2.apk.enforcer.commons.model.ResourceConfig; +import org.wso2.apk.enforcer.commons.model.EndpointSecurity; +import org.wso2.apk.enforcer.commons.model.RequestContext; +import org.wso2.apk.enforcer.commons.model.EndpointCluster; +import org.wso2.apk.enforcer.config.ConfigHolder; +import org.wso2.apk.enforcer.config.EnforcerConfig; +import org.wso2.apk.enforcer.constants.APIConstants; +import org.wso2.apk.enforcer.constants.HttpConstants; +import org.wso2.apk.enforcer.cors.CorsFilter; +import org.wso2.apk.enforcer.discovery.api.Api; +import org.wso2.apk.enforcer.discovery.api.Resource; +import org.wso2.apk.enforcer.discovery.api.Operation; +import org.wso2.apk.enforcer.discovery.api.BackendJWTTokenInfo; +import org.wso2.apk.enforcer.discovery.api.Claim; +import org.wso2.apk.enforcer.security.AuthFilter; +import org.wso2.apk.enforcer.security.mtls.MtlsUtils; +import org.wso2.apk.enforcer.server.swagger.APIDefinitionUtils; +import org.wso2.apk.enforcer.util.EndpointUtils; +import org.wso2.apk.enforcer.util.FilterUtils; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GRPCAPI implements API{ + + private static final Logger logger = LogManager.getLogger(GRPCAPI.class); + private final List filters = new ArrayList<>(); + private APIConfig apiConfig; + @Override + public List getFilters() { + return filters; + } + + @Override + public String init(Api api) { + String vhost = api.getVhost(); + String basePath = api.getBasePath(); + String name = api.getTitle(); + String version = api.getVersion(); + String apiType = api.getApiType(); + List resources = new ArrayList<>(); + Map mtlsCertificateTiers = new HashMap<>(); + String mutualSSL = api.getMutualSSL(); + boolean applicationSecurity = api.getApplicationSecurity(); + + EndpointCluster endpoints = Utils.processEndpoints(api.getEndpoints()); + EndpointSecurity[] endpointSecurity = APIProcessUtils.convertProtoEndpointSecurity( + api.getEndpointSecurityList()); + + for (Resource res : api.getResourcesList()) { + for (Operation operation : res.getMethodsList()) { + ResourceConfig resConfig = Utils.buildResource(operation, res.getPath(), endpointSecurity); + resConfig.setEndpoints(endpoints); + resConfig.setPolicyConfig(Utils.genPolicyConfig(operation.getPolicies())); + resources.add(resConfig); + } + } + + KeyStore trustStore; + try { + trustStore = MtlsUtils.createTrustStore(api.getClientCertificatesList()); + } catch (KeyStoreException e) { + throw new SecurityException(e); + } + + BackendJWTTokenInfo backendJWTTokenInfo = api.getBackendJWTTokenInfo(); + JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); + + // If backendJWTTokeInfo is available + if (api.hasBackendJWTTokenInfo()) { + Map claims = backendJWTTokenInfo.getCustomClaimsMap(); + Map claimsMap = new HashMap<>(); + for (Map.Entry claimEntry : claims.entrySet()) { + Claim claim = claimEntry.getValue(); + ClaimValueDTO claimVal = new ClaimValueDTO(claim.getValue(), claim.getType()); + claimsMap.put(claimEntry.getKey(), claimVal); + } + EnforcerConfig enforcerConfig = ConfigHolder.getInstance().getConfig(); + jwtConfigurationDto.populateConfigValues(backendJWTTokenInfo.getEnabled(), + backendJWTTokenInfo.getHeader(), backendJWTTokenInfo.getSigningAlgorithm(), + backendJWTTokenInfo.getEncoding(), enforcerConfig.getJwtConfigurationDto().getPublicCert(), + enforcerConfig.getJwtConfigurationDto().getPrivateKey(), backendJWTTokenInfo.getTokenTTL(), + claimsMap, enforcerConfig.getJwtConfigurationDto().useKid(), + enforcerConfig.getJwtConfigurationDto().getKidValue()); + } + + + SchemaParser schemaParser = new SchemaParser(); + + byte[] apiDefinition = api.getApiDefinitionFile().toByteArray(); + TypeDefinitionRegistry registry; + + + String apiLifeCycleState = api.getApiLifeCycleState(); + this.apiConfig = new APIConfig.Builder(name).uuid(api.getId()).vhost(vhost).basePath(basePath).version(version) + .resources(resources).apiType(apiType).apiLifeCycleState(apiLifeCycleState).tier(api.getTier()) + .envType(api.getEnvType()).disableAuthentication(api.getDisableAuthentications()) + .disableScopes(api.getDisableScopes()).trustStore(trustStore).organizationId(api.getOrganizationId()) + .mutualSSL(mutualSSL) + .applicationSecurity(applicationSecurity).jwtConfigurationDto(jwtConfigurationDto) + .apiDefinition(apiDefinition).environment(api.getEnvironment()) + .environment(api.getEnvironment()) + .subscriptionValidation(api.getSubscriptionValidation()).build(); + initFilters(); + logger.info("APIConfig: " + this.apiConfig); + return basePath; + } + + @Override + public ResponseObject process(RequestContext requestContext) { + + ResponseObject responseObject = new ResponseObject(requestContext.getRequestID()); + responseObject.setRequestPath(requestContext.getRequestPath()); + boolean analyticsEnabled = ConfigHolder.getInstance().getConfig().getAnalyticsConfig().isEnabled(); + + Utils.handleCommonHeaders(requestContext); + boolean isExistsMatchedOperations = requestContext.getMatchedResourcePaths() != null && + requestContext.getMatchedResourcePaths().size() > 0; + // This flag is used to apply CORS filter + boolean isOptionCall = requestContext.getRequestMethod().contains(HttpConstants.OPTIONS); + + // handle other not allowed && non option request && not yet handled error + // scenarios. + if ((!isOptionCall && !isExistsMatchedOperations) && !requestContext.getProperties() + .containsKey(APIConstants.MessageFormat.ERROR_CODE)) { + requestContext.getProperties() + .put(APIConstants.MessageFormat.STATUS_CODE, APIConstants.StatusCodes.NOTFOUND.getCode()); + requestContext.getProperties().put(APIConstants.MessageFormat.ERROR_CODE, + APIConstants.StatusCodes.NOTFOUND.getValue()); + requestContext.getProperties().put(APIConstants.MessageFormat.ERROR_MESSAGE, + APIConstants.NOT_FOUND_MESSAGE); + requestContext.getProperties().put(APIConstants.MessageFormat.ERROR_DESCRIPTION, + APIConstants.NOT_FOUND_DESCRIPTION); + } + + if ((isExistsMatchedOperations || isOptionCall) && executeFilterChain(requestContext)) { + EndpointUtils.updateClusterHeaderAndCheckEnv(requestContext); + responseObject.setOrganizationId(requestContext.getMatchedAPI().getOrganizationId()); + responseObject.setRemoveHeaderMap(requestContext.getRemoveHeaders()); + responseObject.setQueryParamsToRemove(requestContext.getQueryParamsToRemove()); + responseObject.setRemoveAllQueryParams(requestContext.isRemoveAllQueryParams()); + responseObject.setQueryParamsToAdd(requestContext.getQueryParamsToAdd()); + responseObject.setQueryParamMap(requestContext.getQueryParameters()); + responseObject.setStatusCode(APIConstants.StatusCodes.OK.getCode()); + if (requestContext.getAddHeaders() != null && requestContext.getAddHeaders().size() > 0) { + responseObject.setHeaderMap(requestContext.getAddHeaders()); + } + if (analyticsEnabled) { + AnalyticsFilter.getInstance().handleSuccessRequest(requestContext); + } + // set metadata for interceptors + responseObject.setMetaDataMap(requestContext.getMetadataMap()); + } else { + // If enforcer stops with a false, it will be passed directly to the client. + responseObject.setDirectResponse(true); + responseObject.setStatusCode(Integer.parseInt( + requestContext.getProperties().get(APIConstants.MessageFormat.STATUS_CODE).toString())); + if (requestContext.getProperties().containsKey(APIConstants.MessageFormat.ERROR_CODE)) { + responseObject.setErrorCode( + requestContext.getProperties().get(APIConstants.MessageFormat.ERROR_CODE).toString()); + } + if (requestContext.getProperties().get(APIConstants.MessageFormat.ERROR_MESSAGE) != null) { + responseObject.setErrorMessage(requestContext.getProperties() + .get(APIConstants.MessageFormat.ERROR_MESSAGE).toString()); + } + if (requestContext.getProperties().get(APIConstants.MessageFormat.ERROR_DESCRIPTION) != null) { + responseObject.setErrorDescription(requestContext.getProperties() + .get(APIConstants.MessageFormat.ERROR_DESCRIPTION).toString()); + } + if (requestContext.getAddHeaders() != null && requestContext.getAddHeaders().size() > 0) { + responseObject.setHeaderMap(requestContext.getAddHeaders()); + } + if (analyticsEnabled && !FilterUtils.isSkippedAnalyticsFaultEvent(responseObject.getErrorCode())) { + AnalyticsFilter.getInstance().handleFailureRequest(requestContext); + responseObject.setMetaDataMap(new HashMap<>(0)); + } + } + + return responseObject; + } + + @Override + public APIConfig getAPIConfig() { + return this.apiConfig; + } + + private void initFilters() { + AuthFilter authFilter = new AuthFilter(); + authFilter.init(apiConfig, null); + this.filters.add(authFilter); + + // CORS filter is added as the first filter, and it is not customizable. + CorsFilter corsFilter = new CorsFilter(); + this.filters.add(0, corsFilter); + } +} diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/constants/APIConstants.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/constants/APIConstants.java index 348f29150..a911a06af 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/constants/APIConstants.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/constants/APIConstants.java @@ -270,6 +270,7 @@ public static class ApiType { public static final String WEB_SOCKET = "WS"; public static final String GRAPHQL = "GraphQL"; + public static final String GRPC = "GRPC"; } /** diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/server/swagger/SwaggerServerHandler.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/server/swagger/SwaggerServerHandler.java index 16538f4d0..04d6cd220 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/server/swagger/SwaggerServerHandler.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/server/swagger/SwaggerServerHandler.java @@ -16,8 +16,11 @@ import org.wso2.apk.enforcer.constants.AdminConstants; import org.wso2.apk.enforcer.constants.HttpConstants; import org.wso2.apk.enforcer.models.ResponsePayload; + import java.util.HashMap; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class SwaggerServerHandler extends SimpleChannelInboundHandler { @@ -43,17 +46,34 @@ public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Excep boolean isSwagger = false; - String [] params = request.uri().split("/"); - final String basePath = "/" + params[1] + "/" + params[2]; - final String vHost = params[3].split("\\?")[0]; - final String queryParam = params[3].split("\\?")[1]; + //check if it's GRPC request using the header + String header = request.headers().get("ApiType"); + String[] params = request.uri().split("/"); + final String basePath; + final String vHost; + final String queryParam; + final String version; + //if len params is 3, then it's a GRPC request else other + final String type = params.length == 3 ? "GRPC" : "REST"; + if (type.equals("GRPC")) { + basePath = "/" + params[1]; + vHost = params[2].split("\\?")[0]; + queryParam = params[2].split("\\?")[1]; + version = extractVersionFromGrpcBasePath(params[1]); + } else { + basePath = "/" + params[1] + "/" + params[2]; + vHost = params[3].split("\\?")[0]; + queryParam = params[3].split("\\?")[1]; + version = params[2]; + } + if (APIDefinitionConstants.SWAGGER_DEFINITION.equalsIgnoreCase(queryParam)) { isSwagger = true; } if(isSwagger){ // load the corresponding swagger definition from the API name - byte[] apiDefinition = apiFactory.getAPIDefinition(basePath, params[2], vHost); + byte[] apiDefinition = apiFactory.getAPIDefinition(basePath, version, vHost); if (apiDefinition == null || apiDefinition.length == 0) { String error = AdminConstants.ErrorMessages.NOT_FOUND; responsePayload = new ResponsePayload(); @@ -91,4 +111,15 @@ private void buildAndSendResponse(ChannelHandlerContext ctx, ResponsePayload res httpResponse.headers().set(HTTP.CONTENT_LEN, httpResponse.content().readableBytes()); ctx.writeAndFlush(httpResponse); } + + private static String extractVersionFromGrpcBasePath(String input) { + // Pattern to match '.v' followed by digits and optional periods followed by more digits + Pattern pattern = Pattern.compile("\\.v\\d+(\\.\\d+)*"); + Matcher matcher = pattern.matcher(input); + + if (matcher.find()) { + return matcher.group().substring(1); // Returns the matched version + } + return ""; + } } diff --git a/gateway/router/.gitignore b/gateway/router/.gitignore new file mode 100644 index 000000000..e47e1b33a --- /dev/null +++ b/gateway/router/.gitignore @@ -0,0 +1 @@ +/resources diff --git a/helm-charts/templates/crds/dp.wso2.com_apis.yaml b/helm-charts/templates/crds/dp.wso2.com_apis.yaml index 399c0c01f..600b6cf8f 100644 --- a/helm-charts/templates/crds/dp.wso2.com_apis.yaml +++ b/helm-charts/templates/crds/dp.wso2.com_apis.yaml @@ -256,10 +256,11 @@ spec: type: array apiType: description: APIType denotes the type of the API. Possible values - could be REST, GraphQL, Async + could be REST, GraphQL, Async, GRPC etc. enum: - REST - GraphQL + - GRPC type: string apiVersion: description: APIVersion is the version number of the API. @@ -373,6 +374,183 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.apiName + name: API Name + type: string + - jsonPath: .spec.apiVersion + name: Version + type: string + - jsonPath: .spec.basePath + name: BasePath + type: string + - jsonPath: .spec.organization + name: Organization + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: API is the Schema for the apis API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APISpec defines the desired state of API + properties: + apiName: + description: APIName is the unique name of the API can be used to + uniquely identify an API. + maxLength: 60 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&$\[\]\/]*$ + type: string + apiProperties: + description: APIProperties denotes the custom properties of the API. + items: + description: Property holds key value pair of APIProperties + properties: + name: + type: string + value: + type: string + type: object + nullable: true + type: array + apiType: + description: APIType denotes the type of the API. Possible values + could be REST, GraphQL, Async, GRPC etc. + enum: + - REST + - GraphQL + - GRPC + type: string + apiVersion: + description: APIVersion is the version number of the API. + maxLength: 30 + minLength: 1 + pattern: ^[^~!@#;:%^*()+={}|\<>"'',&/$\[\]\s+\/]+$ + type: string + basePath: + description: 'BasePath denotes the basepath of the API. e.g: /pet-store-api/1.0.6' + type: string + definitionFileRef: + description: DefinitionFileRef contains the definition of the API + in a ConfigMap. + type: string + definitionPath: + default: /api-definition + description: DefinitionPath contains the path to expose the API definition. + minLength: 1 + type: string + environment: + description: Environment denotes the environment of the API. + nullable: true + type: string + isDefaultVersion: + description: IsDefaultVersion indicates whether this API version should + be used as a default API + type: boolean + organization: + description: Organization denotes the organization. related to the + API + type: string + production: + description: 'Production contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + routeRefs: + description: RouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - routeRefs + type: object + maxItems: 1 + nullable: true + type: array + sandbox: + description: 'Sandbox contains a list of references to HttpRoutes + of type HttpRoute. xref: https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/httproute_types.go' + items: + description: EnvConfig contains the environment specific configuration + properties: + routeRefs: + description: RouteRefs denotes the environment of the API. + items: + type: string + type: array + required: + - routeRefs + type: object + maxItems: 1 + nullable: true + type: array + systemAPI: + description: SystemAPI denotes if it is an internal system API. + type: boolean + required: + - apiName + - apiType + - apiVersion + - basePath + - definitionPath + type: object + status: + description: APIStatus defines the observed state of API + properties: + deploymentStatus: + description: DeploymentStatus denotes the deployment status of the + API + properties: + accepted: + description: Accepted represents whether the API is accepted or + not. + type: boolean + events: + description: Events contains a list of events related to the API. + items: + type: string + type: array + message: + description: Message represents a user friendly message that explains + the current state of the API. + type: string + status: + description: Status denotes the state of the API in its lifecycle. + Possible values could be Accepted, Invalid, Deploy etc. + type: string + transitionTime: + description: TransitionTime represents the last known transition + timestamp. + format: date-time + type: string + required: + - accepted + - status + - transitionTime + type: object + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-deployer-api.yaml b/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-deployer-api.yaml index 63185b014..f81c8731d 100644 --- a/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-deployer-api.yaml +++ b/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-deployer-api.yaml @@ -15,7 +15,7 @@ # under the License. {{- if and .Values.wso2.apk.dp.enabled .Values.wso2.apk.dp.configdeployer.enabled }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: "{{ template "apk-helm.resource.prefix" . }}-wso2-apk-config-deployer-api" namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-generator-api.yaml b/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-generator-api.yaml index 708e3f87f..3835db775 100644 --- a/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-generator-api.yaml +++ b/helm-charts/templates/data-plane/config-deployer/wso2-apk-config-generator-api.yaml @@ -15,7 +15,7 @@ # under the License. {{- if and .Values.wso2.apk.dp.enabled .Values.wso2.apk.dp.configdeployer.enabled }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: "{{ template "apk-helm.resource.prefix" . }}-wso2-apk-config-generator-api" namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/data-plane/gateway-components/common-controller/api/notification-api.yaml b/helm-charts/templates/data-plane/gateway-components/common-controller/api/notification-api.yaml index c9cc6f773..46e2f7469 100644 --- a/helm-charts/templates/data-plane/gateway-components/common-controller/api/notification-api.yaml +++ b/helm-charts/templates/data-plane/gateway-components/common-controller/api/notification-api.yaml @@ -16,7 +16,7 @@ {{- if and .Values.wso2.apk.dp.enabled .Values.wso2.apk.dp.commonController }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: "{{ template "apk-helm.resource.prefix" . }}-wso2-apk-notification-api" namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml index 6cdd00e77..46462931a 100644 --- a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml +++ b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml @@ -31,14 +31,14 @@ webhooks: service: name: {{ template "apk-helm.resource.prefix" . }}-common-controller-service namespace: {{ .Release.Namespace }} - path: /mutate-dp-wso2-com-v1alpha2-api + path: /mutate-dp-wso2-com-v1beta1-api failurePolicy: Fail name: mapi.kb.io rules: - apiGroups: - dp.wso2.com apiVersions: - - v1alpha2 + - v1beta1 operations: - CREATE - UPDATE diff --git a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml index e29b5a8a4..3ef9ca6f2 100644 --- a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml +++ b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml @@ -51,14 +51,14 @@ webhooks: service: name: {{ template "apk-helm.resource.prefix" . }}-common-controller-service namespace: {{ .Release.Namespace }} - path: /validate-dp-wso2-com-v1alpha2-api + path: /validate-dp-wso2-com-v1beta1-api failurePolicy: Fail name: vapi.kb.io rules: - apiGroups: - dp.wso2.com apiVersions: - - v1alpha2 + - v1beta1 operations: - CREATE - UPDATE diff --git a/helm-charts/templates/data-plane/gateway-components/gateway-runtime/jwks-domain-api.yaml b/helm-charts/templates/data-plane/gateway-components/gateway-runtime/jwks-domain-api.yaml index 5da3d8295..4e97cb924 100644 --- a/helm-charts/templates/data-plane/gateway-components/gateway-runtime/jwks-domain-api.yaml +++ b/helm-charts/templates/data-plane/gateway-components/gateway-runtime/jwks-domain-api.yaml @@ -15,7 +15,7 @@ # under the License. {{- if .Values.idp.enabled }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: {{ template "apk-helm.resource.prefix" . }}-jwks-endpoint-ds-api namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/idp/authenticationEndpoint-domain-api.yaml b/helm-charts/templates/idp/authenticationEndpoint-domain-api.yaml index 0929f1658..4d4325330 100644 --- a/helm-charts/templates/idp/authenticationEndpoint-domain-api.yaml +++ b/helm-charts/templates/idp/authenticationEndpoint-domain-api.yaml @@ -15,7 +15,7 @@ # under the License. {{- if .Values.idp.enabled }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: {{ template "apk-helm.resource.prefix" . }}-authentication-endpoint-ds-api namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/idp/commonoauth-domain-api.yaml b/helm-charts/templates/idp/commonoauth-domain-api.yaml index a538daa85..cdd7a2a6d 100644 --- a/helm-charts/templates/idp/commonoauth-domain-api.yaml +++ b/helm-charts/templates/idp/commonoauth-domain-api.yaml @@ -15,7 +15,7 @@ # under the License. {{- if .Values.idp.enabled }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: {{ template "apk-helm.resource.prefix" . }}-commonoauth-api namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/idp/dcr-domain-api.yaml b/helm-charts/templates/idp/dcr-domain-api.yaml index fba48631a..aa6d70eb3 100644 --- a/helm-charts/templates/idp/dcr-domain-api.yaml +++ b/helm-charts/templates/idp/dcr-domain-api.yaml @@ -15,7 +15,7 @@ # under the License. {{- if .Values.idp.enabled }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: {{ template "apk-helm.resource.prefix" . }}-dcr-api namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/idp/oauth-domain-api.yaml b/helm-charts/templates/idp/oauth-domain-api.yaml index a4c4214e1..f67fecbb4 100644 --- a/helm-charts/templates/idp/oauth-domain-api.yaml +++ b/helm-charts/templates/idp/oauth-domain-api.yaml @@ -15,7 +15,7 @@ # under the License. {{- if .Values.idp.enabled }} kind: "API" -apiVersion: "dp.wso2.com/v1alpha2" +apiVersion: "dp.wso2.com/v1beta1" metadata: name: {{ template "apk-helm.resource.prefix" . }}-oauth-api namespace: {{ .Release.Namespace }} diff --git a/helm-charts/templates/serviceAccount/apk-cluster-role.yaml b/helm-charts/templates/serviceAccount/apk-cluster-role.yaml index ccbb849a5..428ce7abf 100644 --- a/helm-charts/templates/serviceAccount/apk-cluster-role.yaml +++ b/helm-charts/templates/serviceAccount/apk-cluster-role.yaml @@ -24,7 +24,7 @@ rules: resources: ["services","configmaps","secrets"] verbs: ["get","list","watch","update","delete","create"] - apiGroups: ["gateway.networking.k8s.io"] - resources: ["httproutes","gateways","gatewayclasses"] + resources: ["httproutes","gateways","grpcroutes","gatewayclasses"] verbs: ["get","list","watch","update","delete","create"] - apiGroups: [ "gateway.networking.k8s.io" ] resources: [ "gateways/status","gatewayclasses/status","httproutes/status" ] @@ -122,6 +122,15 @@ rules: - apiGroups: ["dp.wso2.com"] resources: ["gqlroutes/status"] verbs: ["get","patch","update"] + - apiGroups: ["dp.wso2.com"] + resources: ["grpcroutes"] + verbs: ["get","list","watch","update","delete","create"] + - apiGroups: ["dp.wso2.com"] + resources: ["grpcroutes/finalizers"] + verbs: ["update"] + - apiGroups: ["dp.wso2.com"] + resources: ["grpcroutes/status"] + verbs: ["get","patch","update"] - apiGroups: ["cp.wso2.com"] resources: ["applications"] verbs: ["get","list","watch","update","delete","create"] diff --git a/runtime/config-deployer-service/ballerina/APIClient.bal b/runtime/config-deployer-service/ballerina/APIClient.bal index 5a18714d6..30749e3b0 100644 --- a/runtime/config-deployer-service/ballerina/APIClient.bal +++ b/runtime/config-deployer-service/ballerina/APIClient.bal @@ -46,7 +46,7 @@ public class APIClient { encodedString = encodedString.substring(0, encodedString.length() - 1); } APKConf apkConf = { - name: api.getName(), + name: api.getType() == API_TYPE_GRPC ? self.getUniqueNameForGrpcApi(api.getName()) : api.getName(), basePath: api.getBasePath().length() > 0 ? api.getBasePath() : encodedString, version: api.getVersion(), 'type: api.getType() == "" ? API_TYPE_REST : api.getType().toUpperAscii() @@ -280,6 +280,14 @@ public class APIClient { return fullBasePath; } + isolated function returnFullGRPCBasePath(string basePath, string 'version) returns string { + string fullBasePath = basePath; + if (!string:endsWith(basePath, 'version)) { + fullBasePath = string:'join(".", basePath, 'version); + } + return fullBasePath; + } + private isolated function constructURlFromK8sService(K8sService 'k8sService) returns string { return k8sService.protocol + "://" + string:'join(".", k8sService.name, k8sService.namespace, "svc.cluster.local") + ":" + k8sService.port.toString(); } @@ -448,6 +456,19 @@ public class APIClient { sandboxRoutes.push(gqlRoute.metadata.name); } } + } else if apkConf.'type == API_TYPE_GRPC{ + k8sAPI.spec.basePath = self.returnFullGRPCBasePath(apkConf.basePath, apkConf.'version); + foreach model:GRPCRoute grpcRoute in apiArtifact.productionGrpcRoutes { + if grpcRoute.spec.rules.length() > 0 { + productionRoutes.push(grpcRoute.metadata.name); + } + } + foreach model:GRPCRoute grpcRoute in apiArtifact.sandboxGrpcRoutes { + if grpcRoute.spec.rules.length() > 0 { + sandboxRoutes.push(grpcRoute.metadata.name); + } + } + } else { foreach model:HTTPRoute httpRoute in apiArtifact.productionHttpRoutes { if httpRoute.spec.rules.length() > 0 { @@ -538,6 +559,26 @@ public class APIClient { apiArtifact.sandboxGqlRoutes.push(gqlRoute); } } + } else if apkConf.'type == API_TYPE_GRPC { + model:GRPCRoute grpcRoute = { + metadata: + { + name: uniqueId + "-" + endpointType + "-grpcroute-" + count.toString(), + labels: self.getLabels(apkConf, organization) + }, + spec: { + parentRefs: self.generateAndRetrieveParentRefs(apkConf, uniqueId), + rules: check self.generateGRPCRouteRules(apiArtifact, apkConf, endpoint, endpointType, organization), + hostnames: self.getHostNames(apkConf, uniqueId, endpointType, organization) + } + }; + if grpcRoute.spec.rules.length() > 0 { + if endpointType == PRODUCTION_TYPE { + apiArtifact.productionGrpcRoutes.push(grpcRoute); + } else { + apiArtifact.sandboxGrpcRoutes.push(grpcRoute); + } + } } else { model:HTTPRoute httpRoute = { metadata: @@ -559,10 +600,10 @@ public class APIClient { } } } - return; } + private isolated function generateAndRetrieveParentRefs(APKConf apkConf, string uniqueId) returns model:ParentReference[] { string gatewayName = gatewayConfiguration.name; string listenerName = gatewayConfiguration.listenerName; @@ -577,7 +618,7 @@ public class APIClient { APKOperations[]? operations = apkConf.operations; if operations is APKOperations[] { foreach APKOperations operation in operations { - model:HTTPRouteRule|model:GQLRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); + model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); if routeRule is model:HTTPRouteRule { model:HTTPRouteFilter[]? filters = routeRule.filters; if filters is () { @@ -631,12 +672,72 @@ public class APIClient { return httpRouteRules; } + private isolated function generateGRPCRouteRules(model:APIArtifact apiArtifact, APKConf apkConf, model:Endpoint? endpoint, string endpointType, commons:Organization organization) returns model:GRPCRouteRule[]|commons:APKError|error { + model:GRPCRouteRule[] grpcRouteRules = []; + APKOperations[]? operations = apkConf.operations; + if operations is APKOperations[] { + foreach APKOperations operation in operations { + model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); + if routeRule is model:GRPCRouteRule { + model:GRPCRouteFilter[]? filters = routeRule.filters; + if filters is () { + filters = []; + routeRule.filters = filters; + } + string disableAuthenticationRefName = self.retrieveDisableAuthenticationRefName(apkConf, endpointType, organization); + if !(operation.secured ?: true) { + if !apiArtifact.authenticationMap.hasKey(disableAuthenticationRefName) { + model:Authentication generateDisableAuthenticationCR = self.generateDisableAuthenticationCR(apiArtifact, apkConf, endpointType, organization); + apiArtifact.authenticationMap[disableAuthenticationRefName] = generateDisableAuthenticationCR; + } + model:GRPCRouteFilter disableAuthenticationFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: "Authentication", name: disableAuthenticationRefName}}; + (filters).push(disableAuthenticationFilter); + } + string[]? scopes = operation.scopes; + if scopes is string[] { + int count = 1; + foreach string scope in scopes { + model:Scope scopeCr; + if apiArtifact.scopes.hasKey(scope) { + scopeCr = apiArtifact.scopes.get(scope); + } else { + scopeCr = self.generateScopeCR(operation, apiArtifact, apkConf, organization, scope, count); + count = count + 1; + } + model:GRPCRouteFilter scopeFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: scopeCr.kind, name: scopeCr.metadata.name}}; + (filters).push(scopeFilter); + } + } + if operation.rateLimit != () { + model:RateLimitPolicy? rateLimitPolicyCR = self.generateRateLimitPolicyCR(apkConf, operation.rateLimit, apiArtifact.uniqueId, operation, organization); + if rateLimitPolicyCR != () { + apiArtifact.rateLimitPolicies[rateLimitPolicyCR.metadata.name] = rateLimitPolicyCR; + model:GRPCRouteFilter rateLimitPolicyFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: "RateLimitPolicy", name: rateLimitPolicyCR.metadata.name}}; + (filters).push(rateLimitPolicyFilter); + } + } + if operation.operationPolicies != () { + model:APIPolicy? apiPolicyCR = check self.generateAPIPolicyAndBackendCR(apiArtifact, apkConf, operation, operation.operationPolicies, organization, apiArtifact.uniqueId); + if apiPolicyCR != () { + apiArtifact.apiPolicies[apiPolicyCR.metadata.name] = apiPolicyCR; + model:GRPCRouteFilter apiPolicyFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: "APIPolicy", name: apiPolicyCR.metadata.name}}; + (filters).push(apiPolicyFilter); + } + } + grpcRouteRules.push(routeRule); + } + } + } + return grpcRouteRules; + } + + private isolated function generateGQLRouteRules(model:APIArtifact apiArtifact, APKConf apkConf, model:Endpoint? endpoint, string endpointType, commons:Organization organization) returns model:GQLRouteRule[]|commons:APKError|error { model:GQLRouteRule[] gqlRouteRules = []; APKOperations[]? operations = apkConf.operations; if operations is APKOperations[] { foreach APKOperations operation in operations { - model:HTTPRouteRule|model:GQLRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); + model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); if routeRule is model:GQLRouteRule { model:GQLRouteFilter[]? filters = routeRule.filters; if filters is () { @@ -760,7 +861,7 @@ public class APIClient { return authentication; } - private isolated function generateRouteRule(model:APIArtifact apiArtifact, APKConf apkConf, model:Endpoint? endpoint, APKOperations operation, string endpointType, commons:Organization organization) returns model:HTTPRouteRule|model:GQLRouteRule|()|commons:APKError { + private isolated function generateRouteRule(model:APIArtifact apiArtifact, APKConf apkConf, model:Endpoint? endpoint, APKOperations operation, string endpointType, commons:Organization organization) returns model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|()|commons:APKError { do { EndpointConfigurations? endpointConfig = operation.endpointConfigurations; model:Endpoint? endpointToUse = (); @@ -784,7 +885,16 @@ public class APIClient { } else { return e909022("Provided Type currently not supported for GraphQL APIs.", error("Provided Type currently not supported for GraphQL APIs.")); } - } else { + } else if apkConf.'type == API_TYPE_GRPC { + model:GRPCRouteMatch[]|error routeMatches = self.retrieveGRPCMatches(apkConf, operation, organization); + if routeMatches is model:GRPCRouteMatch[] && routeMatches.length() > 0 { + model:GRPCRouteRule grpcRouteRule = {matches: routeMatches, backendRefs: self.retrieveGeneratedBackend(apkConf, endpointToUse, endpointType)}; + return grpcRouteRule; + } else { + return e909022("Provided Type currently not supported for GRPC APIs.", error("Provided Type currently not supported for GRPC APIs.")); + } + } + else { model:HTTPRouteRule httpRouteRule = {matches: self.retrieveHTTPMatches(apkConf, operation, organization), backendRefs: self.retrieveGeneratedBackend(apkConf, endpointToUse, endpointType), filters: self.generateFilters(apiArtifact, apkConf, endpointToUse, operation, endpointType, organization)}; return httpRouteRule; } @@ -929,6 +1039,13 @@ public class APIClient { return gqlRouteMatch; } + + private isolated function retrieveGRPCMatches(APKConf apkConf, APKOperations apiOperation, commons:Organization organization) returns model:GRPCRouteMatch[] { + model:GRPCRouteMatch[] grpcRouteMatch = []; + model:GRPCRouteMatch grpcRoute = self.retrieveGRPCRouteMatch(apiOperation); + grpcRouteMatch.push(grpcRoute); + return grpcRouteMatch; + } private isolated function retrieveHttpRouteMatch(APKConf apkConf, APKOperations apiOperation, commons:Organization organization) returns model:HTTPRouteMatch { return {method: apiOperation.verb, path: {'type: "RegularExpression", value: self.retrievePathPrefix(apkConf.basePath, apkConf.'version, apiOperation.target ?: "/*", organization)}}; @@ -943,6 +1060,17 @@ public class APIClient { } } + private isolated function retrieveGRPCRouteMatch(APKOperations apiOperation) returns model:GRPCRouteMatch { + model:GRPCRouteMatch grpcRouteMatch = { + method: { + 'type: "Exact", + 'service: apiOperation.target, + method: apiOperation.verb + } + }; + return grpcRouteMatch; + } + isolated function retrieveGeneratedSwaggerDefinition(APKConf apkConf, string? definition) returns string|json|commons:APKError|error { runtimeModels:API api1 = runtimeModels:newAPI1(); api1.setName(apkConf.name); @@ -979,6 +1107,10 @@ public class APIClient { api1.setGraphQLSchema(definition); return definition; } + if apkConf.'type == API_TYPE_GRPC && definition is string { + api1.setProtoDefinition(definition); + return definition; + } if definition is string && definition.toString().trim().length() > 0 { retrievedDefinition = runtimeUtil:RuntimeAPICommonUtil_generateDefinition2(api1, definition); } else { @@ -1564,6 +1696,11 @@ public class APIClient { return hashedValue.toBase16(); } + public isolated function getUniqueNameForGrpcApi(string concatanatedServices) returns string { + byte[] hashedValue = crypto:hashSha1(concatanatedServices.toBytes()); + return hashedValue.toBase16(); + } + public isolated function retrieveHttpRouteRefName(APKConf apkConf, string 'type, commons:Organization organization) returns string { return uuid:createType1AsString(); } @@ -1661,7 +1798,7 @@ public class APIClient { } else if definitionFile.fileName.endsWith(".json") { apiDefinition = definitionFileContent; } - } else if apiType == API_TYPE_GRAPHQL { + } else if apiType == API_TYPE_GRAPHQL || apiType == API_TYPE_GRPC { apiDefinition = definitionFileContent; } if apkConf is () { diff --git a/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal b/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal index e410cdb51..5ca4070f1 100644 --- a/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal +++ b/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal @@ -93,7 +93,7 @@ public class ConfigGeneratorClient { private isolated function validateAndRetrieveDefinition(string 'type, string? url, byte[]? content, string? fileName) returns runtimeapi:APIDefinitionValidationResponse|runtimeapi:APIManagementException|error|commons:APKError { runtimeapi:APIDefinitionValidationResponse|runtimeapi:APIManagementException|error validationResponse; boolean typeAvailable = 'type.length() > 0; - string[] ALLOWED_API_DEFINITION_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL, "ASYNC"]; + string[] ALLOWED_API_DEFINITION_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL, "ASYNC",API_TYPE_GRPC]; if !typeAvailable { return e909005("type"); } @@ -187,6 +187,14 @@ public class ConfigGeneratorClient { string yamlString = check self.convertJsonToYaml(gqlRoute.toJsonString()); _ = check self.storeFile(yamlString, gqlRoute.metadata.name, zipDir); } + foreach model:GRPCRoute grpcRoute in apiArtifact.productionGrpcRoutes { + string yamlString = check self.convertJsonToYaml(grpcRoute.toJsonString()); + _ = check self.storeFile(yamlString, grpcRoute.metadata.name, zipDir); + } + foreach model:GRPCRoute grpcRoute in apiArtifact.sandboxGrpcRoutes { + string yamlString = check self.convertJsonToYaml(grpcRoute.toJsonString()); + _ = check self.storeFile(yamlString, grpcRoute.metadata.name, zipDir); + } foreach model:Backend backend in apiArtifact.backendServices { string yamlString = check self.convertJsonToYaml(backend.toJsonString()); _ = check self.storeFile(yamlString, backend.metadata.name, zipDir); diff --git a/runtime/config-deployer-service/ballerina/Dependencies.toml b/runtime/config-deployer-service/ballerina/Dependencies.toml index cb855bd71..747d44537 100644 --- a/runtime/config-deployer-service/ballerina/Dependencies.toml +++ b/runtime/config-deployer-service/ballerina/Dependencies.toml @@ -5,7 +5,7 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.8.5" +distribution-version = "2201.8.4" [[package]] org = "ballerina" @@ -273,7 +273,7 @@ dependencies = [ [[package]] org = "ballerina" name = "observe" -version = "1.2.2" +version = "1.2.3" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -424,8 +424,7 @@ dependencies = [ modules = [ {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, - {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"}, - {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.org.wso2.apk.common"} + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} ] [[package]] diff --git a/runtime/config-deployer-service/ballerina/DeployerClient.bal b/runtime/config-deployer-service/ballerina/DeployerClient.bal index e5beb5d2d..3bcfb20e6 100644 --- a/runtime/config-deployer-service/ballerina/DeployerClient.bal +++ b/runtime/config-deployer-service/ballerina/DeployerClient.bal @@ -95,6 +95,7 @@ public class DeployerClient { apiArtifact.namespace = apiPartition.namespace; if existingAPI is model:API { check self.deleteHttpRoutes(existingAPI, apiArtifact?.organization); + check self.deleteGrpcRoutes(existingAPI, apiArtifact?.organization); check self.deleteAuthenticationCRs(existingAPI, apiArtifact?.organization); _ = check self.deleteScopeCrsForAPI(existingAPI, apiArtifact?.organization); check self.deleteBackends(existingAPI, apiArtifact?.organization); @@ -122,8 +123,8 @@ public class DeployerClient { check self.deployBackendJWTConfigs(apiArtifact, ownerReference); check self.deployAPIPolicyCRs(apiArtifact, ownerReference); - check self.deployRoutes(apiArtifact.productionHttpRoutes, apiArtifact.productionGqlRoutes, apiArtifact?.namespace, ownerReference); - check self.deployRoutes(apiArtifact.sandboxHttpRoutes, apiArtifact.sandboxGqlRoutes, apiArtifact?.namespace, ownerReference); + check self.deployRoutes(apiArtifact.productionHttpRoutes, apiArtifact.productionGqlRoutes,apiArtifact.productionGrpcRoutes, apiArtifact?.namespace, ownerReference); + check self.deployRoutes(apiArtifact.sandboxHttpRoutes, apiArtifact.sandboxGqlRoutes,apiArtifact.sandboxGrpcRoutes, apiArtifact?.namespace, ownerReference); return deployK8sAPICrResult; } on fail var e { @@ -173,6 +174,30 @@ public class DeployerClient { } } + private isolated function deleteGrpcRoutes(model:API api, string organization) returns commons:APKError? { + do { + model:GRPCRouteList|http:ClientError grpcRouteListResponse = check getGrpcRoutesForAPIs(api.spec.apiName, api.spec.apiVersion, api.metadata?.namespace, organization); + if grpcRouteListResponse is model:GRPCRouteList { + foreach model:GRPCRoute item in grpcRouteListResponse.items { + http:Response|http:ClientError grpcRouteDeletionResponse = deleteGrpcRoute(item.metadata.name, api.metadata?.namespace); + if grpcRouteDeletionResponse is http:Response { + if grpcRouteDeletionResponse.statusCode != http:STATUS_OK { + json responsePayLoad = check grpcRouteDeletionResponse.getJsonPayload(); + model:Status statusResponse = check responsePayLoad.cloneWithType(model:Status); + check self.handleK8sTimeout(statusResponse); + } + } else { + log:printError("Error occured while deleting GrpcRoute", grpcRouteDeletionResponse); + } + } + return; + } + } on fail var e { + log:printError("Error occured deleting grpcRoutes", e); + return e909022("Error occured deleting grpcRoutes", e); + } + } + private isolated function deleteHttpRoutes(model:API api, string organization) returns commons:APKError? { do { model:HTTPRouteList|http:ClientError httpRouteListResponse = check getHttproutesForAPIS(api.spec.apiName, api.spec.apiVersion, api.metadata?.namespace, organization); @@ -312,8 +337,10 @@ public class DeployerClient { model:StatusCause[] 'causes = details.'causes; foreach model:StatusCause 'cause in 'causes { if 'cause.'field == "spec.basePath" { + log:printError("Error occured while updating K8sAPI due to basePath ", e909015(k8sAPI.spec.basePath)); return e909015(k8sAPI.spec.basePath); } else if 'cause.'field == "spec.apiName" { + log:printError("Error occured while updating K8sAPI due to apiName ", e909016(k8sAPI.spec.apiName)); return e909016(k8sAPI.spec.apiName); } } @@ -349,7 +376,7 @@ public class DeployerClient { return e909022("Internal error occured", e = error("Internal error occured")); } } - private isolated function deployRoutes(model:HTTPRoute[]? httproutes, model:GQLRoute[]? gqlroutes, string namespace, model:OwnerReference ownerReference) returns error? { + private isolated function deployRoutes(model:HTTPRoute[]? httproutes, model:GQLRoute[]? gqlroutes,model:GRPCRoute[]? grpcroutes, string namespace, model:OwnerReference ownerReference) returns error? { if httproutes is model:HTTPRoute[] && httproutes.length() > 0 { model:HTTPRoute[] deployReadyHttproutes = httproutes; model:HTTPRoute[]|commons:APKError orderedHttproutes = self.createHttpRoutesOrder(httproutes); @@ -408,6 +435,35 @@ public class DeployerClient { } } } + } else if grpcroutes is model:GRPCRoute[] && grpcroutes.length() > 0 { + model:GRPCRoute[] deployReadyGrpcRoutes = grpcroutes; + model:GRPCRoute[]|commons:APKError orderedGrpcRoutes = self.createGrpcRoutesOrder(grpcroutes); + if orderedGrpcRoutes is model:GRPCRoute[] { + deployReadyGrpcRoutes = orderedGrpcRoutes; + } + foreach model:GRPCRoute grpcRoute in deployReadyGrpcRoutes { + grpcRoute.metadata.ownerReferences = [ownerReference]; + if grpcRoute.spec.rules.length() > 0 { + http:Response deployGrpcRouteResult = check deployGrpcRoute(grpcRoute, namespace); + if deployGrpcRouteResult.statusCode == http:STATUS_CREATED { + log:printDebug("Deployed GrpcRoute Successfully" + grpcRoute.toString()); + } else if deployGrpcRouteResult.statusCode == http:STATUS_CONFLICT { + log:printDebug("GrpcRoute already exists" + grpcRoute.toString()); + model:GRPCRoute grpcRouteFromK8s = check getGrpcRoute(grpcRoute.metadata.name, namespace); + grpcRoute.metadata.resourceVersion = grpcRouteFromK8s.metadata.resourceVersion; + http:Response grpcRouteCR = check updateGrpcRoute(grpcRoute, namespace); + if grpcRouteCR.statusCode != http:STATUS_OK { + json responsePayLoad = check grpcRouteCR.getJsonPayload(); + model:Status statusResponse = check responsePayLoad.cloneWithType(model:Status); + check self.handleK8sTimeout(statusResponse); + } + } else { + json responsePayLoad = check deployGrpcRouteResult.getJsonPayload(); + model:Status statusResponse = check responsePayLoad.cloneWithType(model:Status); + check self.handleK8sTimeout(statusResponse); + } + } + } } } @@ -442,6 +498,21 @@ public class DeployerClient { return e909022("Error occured while sorting gqlRoutes", e); } } + public isolated function createGrpcRoutesOrder(model:GRPCRoute[] grpcRoutes) returns model:GRPCRoute[]|commons:APKError { + do { + foreach model:GRPCRoute route in grpcRoutes { + model:GRPCRouteRule[] routeRules = route.spec.rules; + model:GRPCRouteRule[] sortedRouteRules = from var routeRule in routeRules + order by (routeRule.matches[0].method.'service) descending + select routeRule; + route.spec.rules = sortedRouteRules; + } + return grpcRoutes; + } on fail var e { + log:printError("Error occured while sorting grpcRoutes", e); + return e909022("Error occured while sorting grpcRoutes", e); + } + } private isolated function deployAuthenticationCRs(model:APIArtifact apiArtifact, model:OwnerReference ownerReference) returns error? { string[] keys = apiArtifact.authenticationMap.keys(); diff --git a/runtime/config-deployer-service/ballerina/K8sClient.bal b/runtime/config-deployer-service/ballerina/K8sClient.bal index 5e7757206..3b298edc3 100644 --- a/runtime/config-deployer-service/ballerina/K8sClient.bal +++ b/runtime/config-deployer-service/ballerina/K8sClient.bal @@ -56,7 +56,7 @@ isolated function getConfigMapValueFromNameAndNamespace(string name, string name } isolated function deleteAPICR(string name, string namespace) returns http:Response|http:ClientError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis/" + name; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis/" + name; return k8sApiServerEp->delete(endpoint, targetType = http:Response); } @@ -100,6 +100,16 @@ isolated function deleteGqlRoute(string name, string namespace) returns http:Res return k8sApiServerEp->delete(endpoint, targetType = http:Response); } +isolated function getGrpcRoute(string name, string namespace) returns model:GRPCRoute|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/" + name; + return k8sApiServerEp->get(endpoint, targetType = model:GRPCRoute); +} + +isolated function deleteGrpcRoute(string name, string namespace) returns http:Response|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/" + name; + return k8sApiServerEp->delete(endpoint, targetType = http:Response); +} + isolated function getConfigMap(string name, string namespace) returns model:ConfigMap|http:ClientError { string endpoint = "/api/v1/namespaces/" + namespace + "/configmaps/" + name; return k8sApiServerEp->get(endpoint, targetType = model:ConfigMap); @@ -111,12 +121,12 @@ isolated function deleteConfigMap(string name, string namespace) returns http:Re } isolated function deployAPICR(model:API api, string namespace) returns http:Response|http:ClientError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis"; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis"; return k8sApiServerEp->post(endpoint, api, targetType = http:Response); } isolated function updateAPICR(model:API api, string namespace) returns http:Response|http:ClientError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis/" + api.metadata.name; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis/" + api.metadata.name; return k8sApiServerEp->put(endpoint, api, targetType = http:Response); } @@ -150,8 +160,18 @@ isolated function updateGqlRoute(model:GQLRoute gqlroute, string namespace) retu return k8sApiServerEp->put(endpoint, gqlroute, targetType = http:Response); } +isolated function deployGrpcRoute(model:GRPCRoute grpcRoute, string namespace) returns http:Response|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes"; + return k8sApiServerEp->post(endpoint, grpcRoute, targetType = http:Response); +} + +isolated function updateGrpcRoute(model:GRPCRoute grpcRoute, string namespace) returns http:Response|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/" + grpcRoute.metadata.name; + return k8sApiServerEp->put(endpoint, grpcRoute, targetType = http:Response); +} + public isolated function getK8sAPIByNameAndNamespace(string name, string namespace) returns model:API?|commons:APKError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis/" + name; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis/" + name; do { http:Response response = check k8sApiServerEp->get(endpoint); if response.statusCode == 200 { @@ -244,7 +264,10 @@ public isolated function getGqlRoutesForAPIs(string apiName, string apiVersion, string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/gqlroutes/?labelSelector=" + check generateUrlEncodedLabelSelector(apiName, apiVersion, organization); return k8sApiServerEp->get(endpoint, targetType = model:GQLRouteList); } - +public isolated function getGrpcRoutesForAPIs(string apiName, string apiVersion, string namespace, string organization) returns model:GRPCRouteList|http:ClientError|error { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/?labelSelector=" + check generateUrlEncodedLabelSelector(apiName, apiVersion, organization); + return k8sApiServerEp->get(endpoint, targetType = model:GRPCRouteList); +} isolated function deployRateLimitPolicyCR(model:RateLimitPolicy rateLimitPolicy, string namespace) returns http:Response|http:ClientError { string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/ratelimitpolicies"; return k8sApiServerEp->post(endpoint, rateLimitPolicy, targetType = http:Response); diff --git a/runtime/config-deployer-service/ballerina/constants.bal b/runtime/config-deployer-service/ballerina/constants.bal index 66f523456..ed2ad0f6f 100644 --- a/runtime/config-deployer-service/ballerina/constants.bal +++ b/runtime/config-deployer-service/ballerina/constants.bal @@ -11,6 +11,7 @@ public final string[] WS_SUPPORTED_METHODS = ["subscribe", "publish"]; const string API_TYPE_REST = "REST"; const string API_TYPE_GRAPHQL = "GRAPHQL"; +const string API_TYPE_GRPC = "GRPC"; const string API_TYPE_SOAP = "SOAP"; const string API_TYPE_SSE = "SSE"; const string API_TYPE_WS = "WS"; @@ -52,7 +53,7 @@ const string ENDPOINT_SECURITY_PASSWORD = "password"; const string ZIP_FILE_EXTENSTION = ".zip"; const string PROTOCOL_HTTP = "http"; const string PROTOCOL_HTTPS = "https"; -final string[] & readonly ALLOWED_API_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL]; +final string[] & readonly ALLOWED_API_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL, API_TYPE_GRPC]; const string MEDIATION_POLICY_TYPE_REQUEST_HEADER_MODIFIER = "RequestHeaderModifier"; const string MEDIATION_POLICY_TYPE_RESPONSE_HEADER_MODIFIER = "ResponseHeaderModifier"; diff --git a/runtime/config-deployer-service/ballerina/modules/model/API.bal b/runtime/config-deployer-service/ballerina/modules/model/API.bal index 25d7bd40c..d7f6008b8 100644 --- a/runtime/config-deployer-service/ballerina/modules/model/API.bal +++ b/runtime/config-deployer-service/ballerina/modules/model/API.bal @@ -18,7 +18,7 @@ public type API record { string kind = "API"; - string apiVersion = "dp.wso2.com/v1alpha2"; + string apiVersion = "dp.wso2.com/v1beta1"; Metadata metadata; APISpec spec; APIStatus? status = (); @@ -62,7 +62,7 @@ public type EnvConfig record { }; public type APIList record { - string apiVersion = "dp.wso2.com/v1alpha2"; + string apiVersion = "dp.wso2.com/v1beta1"; string kind = "APIList"; API[] items; ListMeta metadata; diff --git a/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal b/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal index 7f272176a..b40f95448 100644 --- a/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal +++ b/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal @@ -6,6 +6,8 @@ public type APIArtifact record {| HTTPRoute[] sandboxHttpRoutes = []; GQLRoute[] productionGqlRoutes = []; GQLRoute[] sandboxGqlRoutes = []; + GRPCRoute[] productionGrpcRoutes = []; + GRPCRoute[] sandboxGrpcRoutes = []; ConfigMap definition?; map endpointCertificates = {}; map certificateMap = {}; diff --git a/runtime/config-deployer-service/ballerina/modules/model/GRPCRoute.bal b/runtime/config-deployer-service/ballerina/modules/model/GRPCRoute.bal new file mode 100644 index 000000000..4087ea485 --- /dev/null +++ b/runtime/config-deployer-service/ballerina/modules/model/GRPCRoute.bal @@ -0,0 +1,75 @@ +// +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. 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. +// + +public type GRPCRouteSpec record { + *CommonRouteSpec; + string[] hostnames?; + GRPCRouteRule[] rules = []; +}; + +public type GRPCRouteRule record { + GRPCRouteMatch[] matches; + GRPCRouteFilter[] filters?; + GRPCBackendRef[] backendRefs?; +}; +public type GRPCRouteMatch record { + GRPCMethodMatch method; + GRPCHeaderMatch[] headers?; +}; + +public type GRPCHeaderMatch record { + string 'type; + string name; + string value; +}; + +public type GRPCMethodMatch record { + string 'type; + string 'service; + string method; +}; + +public type GRPCRouteFilter record { + string 'type; + HTTPHeaderFilter requestHeaderModifier?; + HTTPHeaderFilter responseHeaderModifier?; + HTTPRequestMirrorFilter requestMirror?; + LocalObjectReference extensionRef?; +}; + +public type GRPCBackendRef record { + *BackendRef; + GRPCRouteFilter[] filters?; +}; + +public type GRPCRoute record {| + string apiVersion = "gateway.networking.k8s.io/v1alpha2"; + string kind = "GRPCRoute"; + Metadata metadata; + GRPCRouteSpec spec; +|}; + + +public type GRPCRouteList record {| + string apiVersion = "gateway.networking.k8s.io/v1alpha2"; + string kind = "GRPCRouteList"; + ListMeta metadata; + GRPCRoute[] items; +|}; + + diff --git a/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config.model/API.bal b/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config.model/API.bal index 8638e05be..42470efc5 100644 --- a/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config.model/API.bal +++ b/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config.model/API.bal @@ -183,6 +183,13 @@ public distinct class API { org_wso2_apk_config_model_API_setGraphQLSchema(self.jObj, java:fromString(arg0)); } + # The function that maps to the `setProtoDefinition` method of `org.wso2.apk.config.model.API`. + # + // # + arg0 - The `string` value required to map with the Java method parameter. + public isolated function setProtoDefinition(string arg0) { + org_wso2_apk_config_model_API_setProtoDefinition(self.jObj, java:fromString(arg0)); + } + # The function that maps to the `setName` method of `org.wso2.apk.config.model.API`. # # + arg0 - The `string` value required to map with the Java method parameter. @@ -328,6 +335,13 @@ isolated function org_wso2_apk_config_model_API_getGraphQLSchema(handle receiver paramTypes: [] } external; + +isolated function org_wso2_apk_config_model_API_getProtoDefinition(handle receiver) returns handle = @java:Method { + name: "getProtoDefinition", + 'class: "org.wso2.apk.config.model.API", + paramTypes: [] +} external; + isolated function org_wso2_apk_config_model_API_getName(handle receiver) returns handle = @java:Method { name: "getName", 'class: "org.wso2.apk.config.model.API", @@ -412,6 +426,12 @@ isolated function org_wso2_apk_config_model_API_setGraphQLSchema(handle receiver paramTypes: ["java.lang.String"] } external; +isolated function org_wso2_apk_config_model_API_setProtoDefinition(handle receiver, handle arg0) = @java:Method { + name: "setProtoDefinition", + 'class: "org.wso2.apk.config.model.API", + paramTypes: ["java.lang.String"] +} external; + isolated function org_wso2_apk_config_model_API_setName(handle receiver, handle arg0) = @java:Method { name: "setName", 'class: "org.wso2.apk.config.model.API", diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java index ed4a91e2a..1fcaaadb0 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java @@ -49,6 +49,7 @@ public final class APIConstants { public static final String OBJECT = "object"; public static final String GRAPHQL_API = "GRAPHQL"; + public static final String GRPC_API = "GRPC"; public static final String APPLICATION_JSON_MEDIA_TYPE = "application/json"; // registry location for OpenAPI files @@ -90,7 +91,7 @@ public final class APIConstants { public static final String GRAPHQL_QUERY = "QUERY"; public enum ParserType { - REST, ASYNC, GRAPHQL + REST, ASYNC, GRAPHQL, GRPC } public static class OperationParameter { diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java index 8cfb71084..585e1010e 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java @@ -21,7 +21,8 @@ private DefinitionParserFactory() { public static APIDefinition getParser(API api) { if (APIConstants.ParserType.REST.name().equals(api.getType()) - || APIConstants.ParserType.GRAPHQL.name().equals(api.getType())) { + || APIConstants.ParserType.GRAPHQL.name().equals(api.getType()) + || APIConstants.ParserType.GRPC.name().equals(api.getType())) { return new OAS3Parser(); } else if (APIConstants.ParserType.ASYNC.name().equals(api.getType())) { return new AsyncApiParser(); diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java index 03f043359..c93073e6d 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java @@ -6,6 +6,7 @@ import org.wso2.apk.config.api.ExceptionCodes; import org.wso2.apk.config.definitions.GraphQLSchemaDefinition; import org.wso2.apk.config.definitions.OASParserUtil; +import org.wso2.apk.config.definitions.ProtoParser; import org.wso2.apk.config.model.API; import org.wso2.apk.config.model.URITemplate; @@ -66,7 +67,18 @@ public static APIDefinitionValidationResponse validateOpenAPIDefinition(String t OASParserUtil.addErrorToValidationResponse(validationResponse, "Invalid definition file type provided."); } + } else if (APIConstants.ParserType.GRPC.name().equals(type.toUpperCase())) { + if (fileName.endsWith(".proto")) { + validationResponse = OASParserUtil.validateProtoDefinition( + new String(inputByteArray, StandardCharsets.UTF_8), + returnContent); + } else { + OASParserUtil.addErrorToValidationResponse(validationResponse, + "Invalid definition file type provided."); + } } + + return validationResponse; } @@ -99,6 +111,8 @@ public static API getAPIFromDefinition(String definition, String apiType) throws if (apiType.toUpperCase().equals(APIConstants.GRAPHQL_API)) { return getGQLAPIFromDefinition(definition); + } else if (apiType.toUpperCase().equals(APIConstants.GRPC_API)) { + return getGRPCAPIFromProtoDefinition(definition); } else { APIDefinition parser = DefinitionParserFactory.getParser(apiType); if (parser != null) { @@ -128,6 +142,35 @@ private static API getGQLAPIFromDefinition(String definition) { return api; } + private static API getGRPCAPIFromProtoDefinition(String definition) { + ProtoParser protoParser = new ProtoParser(definition); + List uriTemplates = new ArrayList<>(); + API api = new API(); + api.setBasePath("/"+protoParser.protoFile.basePath); + api.setVersion(protoParser.protoFile.version); + StringBuilder apiName = new StringBuilder(); + List sortedServices = new ArrayList<>(); + + for (ProtoParser.Service service : protoParser.getServices()) { + sortedServices.add(service.name); + for (String method : service.methods) { + URITemplate uriTemplate = new URITemplate(); + uriTemplate.setUriTemplate(protoParser.protoFile.packageName + "." + service.name); + uriTemplate.setVerb(method); + uriTemplates.add(uriTemplate); + } + } + sortedServices.sort(String::compareTo); + for (String service : sortedServices) { + apiName.append(service).append("-"); + } + apiName.deleteCharAt(apiName.length() - 1); + api.setName(apiName.toString()); + api.setUriTemplates(uriTemplates.toArray(new URITemplate[uriTemplates.size()])); + + return api; + } + private RuntimeAPICommonUtil() { } diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java index f24a3a2fe..6324d8700 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java @@ -361,6 +361,10 @@ public enum ExceptionCodes implements ErrorHandler { UNSUPPORTED_GRAPHQL_FILE_EXTENSION(900802, "Unsupported GraphQL Schema File Extension", 400, "Unsupported extension. Only supported extensions are .graphql, .txt and .sdl"), + //GRPC API related codes + GRPC_PROTO_DEFINTION_CANNOT_BE_NULL(900803, "gRPC Proto Definition cannot be empty or null", 400, + "gRPC Proto Definition cannot be empty or null"), + // Oauth related codes AUTH_GENERAL_ERROR(900900, "Authorization Error", 403, " Error in authorization"), INVALID_CREDENTIALS(900901, "Invalid Credentials", 401, " Invalid username or password"), diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java index 66eae511c..4ec23b7df 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java @@ -668,6 +668,34 @@ public static APIDefinitionValidationResponse validateGraphQLSchema(String apiDe return validationResponse; } + /** + * Validate gRPC proto definition + * + * @return Validation response + */ + public static APIDefinitionValidationResponse validateProtoDefinition(String apiDefinition, + boolean returnContent) { + APIDefinitionValidationResponse validationResponse = new APIDefinitionValidationResponse(); + ArrayList errors = new ArrayList<>(); + try { + if (apiDefinition.isBlank()) { + validationResponse.setValid(false); + errors.add(ExceptionCodes.GRPC_PROTO_DEFINTION_CANNOT_BE_NULL); + validationResponse.setErrorItems(errors); + } else { + validationResponse.setValid(true); + validationResponse.setContent(apiDefinition); + } + } catch (Exception e) { + OASParserUtil.addErrorToValidationResponse(validationResponse, e.getMessage()); + validationResponse.setValid(false); + errors.add(new ErrorItem("API Definition Validation Error", "API Definition is invalid", 400, 400)); + validationResponse.setErrorItems(errors); + } + return validationResponse; + + } + /** * This method removes the unsupported json blocks from the given json string. * diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParser.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParser.java new file mode 100644 index 000000000..2f371f420 --- /dev/null +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParser.java @@ -0,0 +1,165 @@ +package org.wso2.apk.config.definitions; + +import java.util.List; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ProtoParser { + + public ProtoFile protoFile; + public ProtoParser(String content) { + protoFile = parseProtoContent(content); + } + + public String getPackageString(String content) { + Pattern packagePattern = Pattern.compile("package\\s+([\\w\\.]+);"); + Matcher packageMatcher = packagePattern.matcher(content); + if (packageMatcher.find()) { + return packageMatcher.group(1); + } + return null; + } + public String getVersion(String packageString) { + Pattern versionPattern = Pattern.compile("v\\d+(\\.\\d+)*"); + Matcher versionMatcher = versionPattern.matcher(packageString); + if (versionMatcher.find()) { + return versionMatcher.group(0); + } + System.out.println("No version found"); + return null; + } + public String getPackageName(String packageString){ + Pattern namePattern = Pattern.compile("v\\d+(\\.\\d+)*\\.(\\w+)"); + Matcher nameMatcher = namePattern.matcher(packageString); + if (nameMatcher.find()) { + return nameMatcher.group(2); + } + System.out.println("No name found"); + return null; + } + + public String getBasePath(String packageString){ + Pattern basePathPattern = Pattern.compile("^(.*?)v\\d"); + + Matcher basePathMatcher = basePathPattern.matcher(packageString); + if (basePathMatcher.find()) { + String basePath = basePathMatcher.group(1); + if(basePath.charAt(basePath.length()-1) == '.'){ + basePath = basePath.substring(0, basePath.length()-1); + } + return basePath; + } + System.out.println("No base path found"); + return null; + } + + // Method to extract service blocks from a given text + public List extractServiceBlocks(String text) { + // Regular expression pattern to match the service blocks + String patternString = "service\\s+\\w+\\s*\\{[^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\}"; + + // Compile the regular expression + Pattern pattern = Pattern.compile(patternString, Pattern.DOTALL); + Matcher matcher = pattern.matcher(text); + + // Find all matches and append them to the result + List result = new ArrayList<>(); + while (matcher.find()) { + result.add(matcher.group()); + } + return result; + } + + public List extractMethodNames(String serviceBlock) { + // Regular expression pattern to match the method names + String patternString = "(?<=rpc\\s)\\w+"; + + // Compile the regular expression + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(serviceBlock); + + // Find all matches and append them to the result + List result = new ArrayList<>(); + while (matcher.find()) { + result.add(matcher.group()); + } + return result; + } + + public String getServiceName(String serviceBlock) { + // Regular expression pattern to match the service name + String patternString = "(?<=service\\s)\\w+"; + + // Compile the regular expression + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(serviceBlock); + + // Find the first match and return it + if (matcher.find()) { + return matcher.group(); + } + return null; + } + + public ProtoFile parseProtoContent(String content) { + ProtoFile protoFile = new ProtoFile(); + protoFile.services = new ArrayList<>(); + + List serviceBlocks = extractServiceBlocks(content); + for (String serviceBlock : serviceBlocks) { + Service service = new Service(); + service.name = getServiceName(serviceBlock); + service.methods = new ArrayList<>(); + service.methods.addAll(extractMethodNames(serviceBlock)); + protoFile.services.add(service); + } + + // Extract package name + String packageName = getPackageString(content); + protoFile.packageName = getPackageName(packageName); + protoFile.version = getVersion(packageName); + protoFile.basePath = getBasePath(packageName); + +// System.out.println(protoFile); + + return protoFile; + } + + public List getMethods(Service Service){ + return Service.methods; + } + public List getServices(){ + return this.protoFile.services; + } + public class ProtoFile { + public String packageName; + public String basePath; + public String version; + public List services; + + @Override + public String toString() { + return "ProtoFile{" + + "packageName='" + packageName + '\'' + + ", basePath='" + basePath + '\'' + + ", version='" + version + '\'' + + ", services=" + services + + '}'; + } + + } + + public class Service { + public String name; + public List methods; + + @Override + public String toString() { + return " Service{" + + "name='" + name + '\'' + + ", methods=" + methods + + '}'; + } + } +} \ No newline at end of file diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java index d2715d77b..a88c2508f 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java @@ -11,6 +11,7 @@ public class API { private String apiSecurity; private String[] scopes; private String graphQLSchema; + private String protoDefinition; private String swaggerDefinition; private String environment; @@ -79,6 +80,13 @@ public void setGraphQLSchema(String graphQLSchema) { this.graphQLSchema = graphQLSchema; } + public void setProtoDefinition(String protoDefinition) { + this.protoDefinition = protoDefinition; + } + + public String getProtoDefinition() { + return protoDefinition; + } public String getSwaggerDefinition() { return swaggerDefinition; } diff --git a/test/cucumber-tests/CRs/artifacts.yaml b/test/cucumber-tests/CRs/artifacts.yaml index cf592dad8..0ee441c99 100644 --- a/test/cucumber-tests/CRs/artifacts.yaml +++ b/test/cucumber-tests/CRs/artifacts.yaml @@ -1154,3 +1154,51 @@ spec: protocol: TCP selector: app: graphql-faker +--- +apiVersion: v1 +kind: Service +metadata: + name: grpc-backend + namespace: apk-integration-test +spec: + selector: + app: grpc-backend + ports: + - protocol: TCP + port: 6565 + targetPort: 6565 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grpc-backend + namespace: apk-integration-test + labels: + app: grpc-backend +spec: + replicas: 1 + selector: + matchLabels: + app: grpc-backend + template: + metadata: + labels: + app: grpc-backend + spec: + containers: + - name: grpc-backend + image: ddh13/dineth-grpc-demo-server:1.0.0 + imagePullPolicy: Always + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + resources: + requests: + cpu: 10m +--- \ No newline at end of file diff --git a/test/cucumber-tests/build.gradle b/test/cucumber-tests/build.gradle index dba839001..294ec7b49 100644 --- a/test/cucumber-tests/build.gradle +++ b/test/cucumber-tests/build.gradle @@ -40,6 +40,14 @@ dependencies { testImplementation 'io.cucumber:cucumber-testng:7.13.0' testImplementation 'commons-io:commons-io:2.13.0' testImplementation 'com.nimbusds:nimbus-jose-jwt:9.31' + implementation 'javax.annotation:javax.annotation-api:1.3.2' + implementation 'io.grpc:grpc-netty:1.48.0' + implementation 'io.grpc:grpc-protobuf:1.48.0' + implementation 'io.grpc:grpc-stub:1.48.0' + implementation 'io.grpc:grpc-auth:1.48.0' + implementation 'io.grpc:grpc-netty-shaded:1.57.0' + implementation 'io.grpc:grpc-protobuf:1.57.0' + implementation 'io.grpc:grpc-stub:1.57.0' testImplementation 'com.googlecode.json-simple:json-simple:1.1.1' } diff --git a/test/cucumber-tests/scripts/setup-hosts.sh b/test/cucumber-tests/scripts/setup-hosts.sh index 5fb451248..2f541a7b5 100644 --- a/test/cucumber-tests/scripts/setup-hosts.sh +++ b/test/cucumber-tests/scripts/setup-hosts.sh @@ -6,6 +6,7 @@ kubectl wait deployment/backend-retry-deployment -n apk-integration-test --for=c kubectl wait deployment/dynamic-backend -n apk-integration-test --for=condition=available --timeout=600s kubectl wait deployment/interceptor-service-deployment -n apk-integration-test --for=condition=available --timeout=600s kubectl wait deployment/graphql-faker -n apk-integration-test --for=condition=available --timeout=600s +kubectl wait deployment/grpc-backend -n apk-integration-test --for=condition=available --timeout=600s kubectl wait --timeout=5m -n apk-integration-test deployment/apk-test-setup-wso2-apk-adapter-deployment --for=condition=Available kubectl wait --timeout=15m -n apk-integration-test deployment/apk-test-setup-wso2-apk-gateway-runtime-deployment --for=condition=Available IP=$(kubectl get svc apk-test-setup-wso2-apk-gateway-service -n apk-integration-test --output jsonpath='{.status.loadBalancer.ingress[0].ip}') diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/BaseSteps.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/BaseSteps.java index de5b55014..4ab924238 100644 --- a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/BaseSteps.java +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/BaseSteps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC (http://www.wso2.com). * * WSO2 LLC licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -39,6 +39,8 @@ import io.cucumber.java.Before; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -50,10 +52,12 @@ import org.testng.Assert; import org.wso2.apk.integration.utils.Constants; import org.wso2.apk.integration.utils.Utils; +import org.wso2.apk.integration.utils.clients.SimpleGRPCStudentClient; import org.wso2.apk.integration.utils.clients.SimpleHTTPClient; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.ContentType; +import org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentResponse; import java.io.IOException; import java.io.InputStream; @@ -96,10 +100,27 @@ public void systemIsReady() { } + @Then("the student response body should contain name: {string} age: {int}") + public void theStudentResponseBodyShouldContainNameAndAge(String arg0, int arg1) { + StudentResponse studentResponse = sharedContext.getStudentResponse(); + if (studentResponse == null) { + Assert.fail("Student response is null."); + } + int age = studentResponse.getAge(); + String name = studentResponse.getName(); + Assert.assertEquals(name, arg0); + Assert.assertEquals(age, arg1); + } + @Then("the response body should contain {string}") public void theResponseBodyShouldContain(String expectedText) throws IOException { Assert.assertTrue(sharedContext.getResponseBody().contains(expectedText), "Actual response body: " + sharedContext.getResponseBody()); } + @Then("the response body should contain endpoint definition for student.proto") + public void theResponseBodyShouldContainEndpointDefinition() throws IOException { + String expectedText = "{\"apiDefinition\":\"syntax = \\\"proto3\\\";\\n\\noption java_multiple_files = true;\\noption java_package = \\\"org.example\\\";\\npackage dineth.grpc.api.v1.student;\\n\\nservice StudentService {\\n rpc GetStudent(StudentRequest) returns (StudentResponse) {};\\n rpc GetStudentStream(StudentRequest) returns (stream StudentResponse) {};\\n rpc SendStudentStream(stream StudentRequest) returns (StudentResponse) {};\\n rpc SendAndGetStudentStream(stream StudentRequest) returns (stream StudentResponse) {}\\n}\\n\\nmessage StudentRequest {\\n int32 id = 3;\\n}\\n\\nmessage StudentResponse {\\n string name = 1;\\n int32 age = 2;\\n}\\n\"}"; + Assert.assertTrue(sharedContext.getResponseBody().contains(expectedText), "Actual response body: " + sharedContext.getResponseBody()); + } @Then("the response body should not contain {string}") public void theResponseBodyShouldNotContain(String expectedText) throws IOException { Assert.assertFalse(sharedContext.getResponseBody().contains(expectedText), "Actual response body: " + sharedContext.getResponseBody()); @@ -121,6 +142,12 @@ public void theResponseStatusCodeShouldBe(int expectedStatusCode) throws IOExcep Assert.assertEquals(actualStatusCode, expectedStatusCode); } + @Then("the gRPC response status code should be {int}") + public void theGrpcResponseStatusCodeShouldBe(int expectedStatusCode) throws IOException { + int actualStatusCode = sharedContext.getGrpcStatusCode(); + Assert.assertEquals(actualStatusCode, expectedStatusCode); + } + @Then("I send {string} request to {string} with body {string}") public void sendHttpRequest(String httpMethod, String url, String body) throws IOException { body = Utils.resolveVariables(body, sharedContext.getValueStore()); @@ -144,6 +171,30 @@ public void sendHttpRequest(String httpMethod, String url, String body) throws I } } + @Then("I make grpc request GetStudent to {string} with port {int}") + public void GetStudent(String arg0, int arg1) throws StatusRuntimeException { + try { + SimpleGRPCStudentClient grpcStudentClient = new SimpleGRPCStudentClient(arg0, arg1); + sharedContext.setStudentResponse(grpcStudentClient.GetStudent(sharedContext.getHeaders())); + sharedContext.setGrpcStatusCode(0); + } catch (StatusRuntimeException e) { + sharedContext.setGrpcStatusCode(e.getStatus().getCode().value()); + logger.error(e.getMessage() + " Status code: " + e.getStatus().getCode().value()) ; + } + } + + @Then("I make grpc request GetStudent default version to {string} with port {int}") + public void GetStudentDefaultVersion(String arg0, int arg1) throws StatusRuntimeException { + try { + SimpleGRPCStudentClient grpcStudentClient = new SimpleGRPCStudentClient(arg0, arg1); + sharedContext.setStudentResponse(grpcStudentClient.GetStudentDefaultVersion(sharedContext.getHeaders())); + sharedContext.setGrpcStatusCode(0); + } catch (StatusRuntimeException e) { + sharedContext.setGrpcStatusCode(e.getStatus().getCode().value()); + logger.error(e.getMessage() + " Status code: " + e.getStatus().getCode().value()) ; + } + } + // It will send request using a new thread and forget about the response @Then("I send {string} async request to {string} with body {string}") public void sendAsyncHttpRequest(String httpMethod, String url, String body) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/SharedContext.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/SharedContext.java index 85dd45b44..e481c15ed 100644 --- a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/SharedContext.java +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/SharedContext.java @@ -19,11 +19,11 @@ import org.apache.http.HttpResponse; import org.wso2.apk.integration.utils.clients.SimpleHTTPClient; +import org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentResponse; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -31,9 +31,12 @@ public class SharedContext { private SimpleHTTPClient httpClient; + private StudentResponse studentResponse; private String accessToken; private HttpResponse response; private String responseBody; + private int grpcStatusCode; + private int grpcErrorCode; private String publisherAccessToken; private String devportalAccessToken; private String adminportalAccessToken; @@ -73,12 +76,28 @@ public void setAccessToken(String accessToken) { this.accessToken = accessToken; } + public int getGrpcStatusCode() { + return grpcStatusCode; + } + public void setGrpcStatusCode(int grpcStatusCode) { + this.grpcStatusCode = grpcStatusCode; + } public HttpResponse getResponse() { return response; } + public StudentResponse getStudentResponse() { + + return studentResponse; + } + + public void setStudentResponse(StudentResponse studentResponse) { + + this.studentResponse = studentResponse; + } + public void setResponse(HttpResponse response) { this.response = response; @@ -217,7 +236,7 @@ public String getAPIInternalKey(){ } public String getConsumerSecret(String keyType) { - if ("production".equals(keyType)) + if ("production".equals(keyType)) return consumerSecret; else if ("sandbox".equals(keyType)) return sandboxConsumerSecret; @@ -225,14 +244,14 @@ else if ("sandbox".equals(keyType)) } public void setConsumerSecret(String consumerSecret, String keyType) { - if ("production".equals(keyType)) + if ("production".equals(keyType)) this.consumerSecret = consumerSecret; else if ("sandbox".equals(keyType)) this.sandboxConsumerSecret = consumerSecret; } public String getConsumerKey(String keyType) { - if ("production".equals(keyType)) + if ("production".equals(keyType)) return consumerKey; else if ("sandbox".equals(keyType)) return sandboxConsumerKey; @@ -240,25 +259,25 @@ else if ("sandbox".equals(keyType)) } public void setConsumerKey(String consumerKey, String keyType) { - if ("production".equals(keyType)) + if ("production".equals(keyType)) this.consumerKey = consumerKey; else if ("sandbox".equals(keyType)) this.sandboxConsumerKey = consumerKey; } public void setKeyMappingID(String keyMappingID, String keyType){ - if ("production".equals(keyType)) + if ("production".equals(keyType)) this.prodKeyMappingID = keyMappingID; else if ("sandbox".equals(keyType)) this.sandboxKeyMappingID = keyMappingID; } public String getKeyMappingID(String keyType){ - if ("production".equals(keyType)) + if ("production".equals(keyType)) return prodKeyMappingID; else if ("sandbox".equals(keyType)) return sandboxKeyMappingID; - return ""; + return ""; } public String getApiAccessToken() { diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/GenericClientInterceptor.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/GenericClientInterceptor.java new file mode 100644 index 000000000..17ab5702e --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/GenericClientInterceptor.java @@ -0,0 +1,39 @@ +package org.wso2.apk.integration.utils; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; +import io.grpc.CallOptions; +import io.grpc.ClientCall; +import io.grpc.Channel; +import java.util.Map; + + +import java.util.Map; + +public class GenericClientInterceptor implements ClientInterceptor { + + private Map headers; + + public GenericClientInterceptor(Map headers) { + this.headers = headers; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor method, CallOptions callOptions, Channel next) { + return new ForwardingClientCall.SimpleForwardingClientCall( + next.newCall(method, callOptions)) { + + @Override + public void start(Listener responseListener, Metadata headersMetadata) { + // Set each header in the map to the Metadata headers + headers.forEach((key, value) -> headersMetadata.put( + Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER), value)); + + super.start(responseListener, headersMetadata); + } + }; + } +} + diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/SimpleGRPCStudentClient.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/SimpleGRPCStudentClient.java new file mode 100644 index 000000000..0f7ba0b98 --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/SimpleGRPCStudentClient.java @@ -0,0 +1,115 @@ +package org.wso2.apk.integration.utils.clients; + +import io.grpc.StatusRuntimeException; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NettyChannelBuilder; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import io.grpc.ManagedChannel; +import org.wso2.apk.integration.utils.GenericClientInterceptor; +import org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentRequest; +import org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentResponse; +import org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentServiceDefaultVersionGrpc; +import org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentServiceGrpc; + +import javax.net.ssl.SSLException; +import java.util.Map; +import java.util.concurrent.TimeUnit; + + +public class SimpleGRPCStudentClient { + protected Log log = LogFactory.getLog(SimpleGRPCStudentClient.class); + private static final int EVENTUAL_SUCCESS_RESPONSE_TIMEOUT_IN_SECONDS = 10; + private final String host; + private final int port; + + public SimpleGRPCStudentClient(String host, int port) { + this.host = host; + this.port = port; + } + + public StudentResponse GetStudent(Map headers) throws StatusRuntimeException{ + ManagedChannel managedChannel = null; + try { + SslContext sslContext = GrpcSslContexts.forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + + GenericClientInterceptor interceptor = new GenericClientInterceptor(headers); + managedChannel = NettyChannelBuilder.forAddress(host, port) + .sslContext(sslContext) + .intercept(interceptor) + .build(); + StudentServiceGrpc.StudentServiceBlockingStub blockingStub = StudentServiceGrpc.newBlockingStub(managedChannel); + if (blockingStub == null) { + log.error("Failed to create blocking stub"); + throw new RuntimeException("Failed to create blocking stub"); + } + StudentResponse response = blockingStub.getStudent(StudentRequest.newBuilder().setId(1).build()); + if (response == null) { + log.error("Failed to get student"); + throw new RuntimeException("Failed to get student"); + } + return response; + }catch (SSLException e) { + throw new RuntimeException("Failed to create SSL context", e); + } finally { + // Shut down the channel to release resources + if (managedChannel != null) { + managedChannel.shutdown(); // Initiates a graceful shutdown + try { + // Wait at most 5 seconds for the channel to terminate + if (!managedChannel.awaitTermination(5, TimeUnit.SECONDS)) { + managedChannel.shutdownNow(); // Force shutdown if it does not complete within the timeout + } + } catch (InterruptedException ie) { + managedChannel.shutdownNow(); // Force shutdown if the thread is interrupted + } + } + } + } + public StudentResponse GetStudentDefaultVersion(Map headers) throws StatusRuntimeException{ + ManagedChannel managedChannel = null; + try { + SslContext sslContext = GrpcSslContexts.forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + + GenericClientInterceptor interceptor = new GenericClientInterceptor(headers); + managedChannel = NettyChannelBuilder.forAddress(host, port) + .sslContext(sslContext) + .intercept(interceptor) + .build(); + StudentServiceDefaultVersionGrpc.StudentServiceBlockingStub blockingStub = StudentServiceDefaultVersionGrpc.newBlockingStub(managedChannel); + if (blockingStub == null) { + log.error("Failed to create blocking stub"); + throw new RuntimeException("Failed to create blocking stub"); + } + StudentResponse response = blockingStub.getStudent(StudentRequest.newBuilder().setId(1).build()); + if (response == null) { + log.error("Failed to get student"); + throw new RuntimeException("Failed to get student"); + } + return response; + }catch (SSLException e) { + throw new RuntimeException("Failed to create SSL context", e); + } finally { + // Shut down the channel to release resources + if (managedChannel != null) { + managedChannel.shutdown(); // Initiates a graceful shutdown + try { + // Wait at most 5 seconds for the channel to terminate + if (!managedChannel.awaitTermination(5, TimeUnit.SECONDS)) { + managedChannel.shutdownNow(); // Force shutdown if it does not complete within the timeout + } + } catch (InterruptedException ie) { + managedChannel.shutdownNow(); // Force shutdown if the thread is interrupted + } + } + } + } + +} + diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/Student.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/Student.java new file mode 100644 index 000000000..8ec85fec1 --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/Student.java @@ -0,0 +1,72 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: student.proto + +package org.wso2.apk.integration.utils.clients.studentGrpcClient; + +public final class Student { + private Student() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_dineth_grpc_v1_student_StudentRequest_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_dineth_grpc_v1_student_StudentRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_dineth_grpc_v1_student_StudentResponse_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_dineth_grpc_v1_student_StudentResponse_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + String[] descriptorData = { + "\n\rstudent.proto\022\026dineth.grpc.v1.student\"" + + "\034\n\016StudentRequest\022\n\n\002id\030\003 \001(\005\",\n\017Student" + + "Response\022\014\n\004name\030\001 \001(\t\022\013\n\003age\030\002 \001(\0052\266\003\n\016" + + "StudentService\022_\n\nGetStudent\022&.dineth.gr" + + "pc.v1.student.StudentRequest\032\'.dineth.gr" + + "pc.v1.student.StudentResponse\"\000\022g\n\020GetSt" + + "udentStream\022&.dineth.grpc.v1.student.Stu" + + "dentRequest\032\'.dineth.grpc.v1.student.Stu" + + "dentResponse\"\0000\001\022h\n\021SendStudentStream\022&." + + "dineth.grpc.v1.student.StudentRequest\032\'." + + "dineth.grpc.v1.student.StudentResponse\"\000" + + "(\001\022p\n\027SendAndGetStudentStream\022&.dineth.g" + + "rpc.v1.student.StudentRequest\032\'.dineth.g" + + "rpc.v1.student.StudentResponse\"\000(\0010\001B<\n8" + + "org.wso2.apk.integration.utils.clients.s" + + "tudentGrpcClientP\001b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_dineth_grpc_v1_student_StudentRequest_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_dineth_grpc_v1_student_StudentRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_dineth_grpc_v1_student_StudentRequest_descriptor, + new String[] { "Id", }); + internal_static_dineth_grpc_v1_student_StudentResponse_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_dineth_grpc_v1_student_StudentResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_dineth_grpc_v1_student_StudentResponse_descriptor, + new String[] { "Name", "Age", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentRequest.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentRequest.java new file mode 100644 index 000000000..c487c6567 --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentRequest.java @@ -0,0 +1,483 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: student.proto + +package org.wso2.apk.integration.utils.clients.studentGrpcClient; + +/** + * Protobuf type {@code dineth.grpc.v1.student.StudentRequest} + */ +public final class StudentRequest extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:dineth.grpc.v1.student.StudentRequest) + StudentRequestOrBuilder { +private static final long serialVersionUID = 0L; + // Use StudentRequest.newBuilder() to construct. + private StudentRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private StudentRequest() { + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new StudentRequest(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private StudentRequest( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 24: { + + id_ = input.readInt32(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return Student.internal_static_dineth_grpc_v1_student_StudentRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return Student.internal_static_dineth_grpc_v1_student_StudentRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + StudentRequest.class, Builder.class); + } + + public static final int ID_FIELD_NUMBER = 3; + private int id_; + /** + * int32 id = 3; + * @return The id. + */ + @Override + public int getId() { + return id_; + } + + private byte memoizedIsInitialized = -1; + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (id_ != 0) { + output.writeInt32(3, id_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (id_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(3, id_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof StudentRequest)) { + return super.equals(obj); + } + StudentRequest other = (StudentRequest) obj; + + if (getId() + != other.getId()) return false; + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static StudentRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static StudentRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static StudentRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static StudentRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static StudentRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static StudentRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static StudentRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static StudentRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static StudentRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static StudentRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static StudentRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static StudentRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(StudentRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code dineth.grpc.v1.student.StudentRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:dineth.grpc.v1.student.StudentRequest) + StudentRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return Student.internal_static_dineth_grpc_v1_student_StudentRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return Student.internal_static_dineth_grpc_v1_student_StudentRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + StudentRequest.class, Builder.class); + } + + // Construct using org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @Override + public Builder clear() { + super.clear(); + id_ = 0; + + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return Student.internal_static_dineth_grpc_v1_student_StudentRequest_descriptor; + } + + @Override + public StudentRequest getDefaultInstanceForType() { + return StudentRequest.getDefaultInstance(); + } + + @Override + public StudentRequest build() { + StudentRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public StudentRequest buildPartial() { + StudentRequest result = new StudentRequest(this); + result.id_ = id_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof StudentRequest) { + return mergeFrom((StudentRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(StudentRequest other) { + if (other == StudentRequest.getDefaultInstance()) return this; + if (other.getId() != 0) { + setId(other.getId()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + StudentRequest parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (StudentRequest) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private int id_ ; + /** + * int32 id = 3; + * @return The id. + */ + @Override + public int getId() { + return id_; + } + /** + * int32 id = 3; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId(int value) { + + id_ = value; + onChanged(); + return this; + } + /** + * int32 id = 3; + * @return This builder for chaining. + */ + public Builder clearId() { + + id_ = 0; + onChanged(); + return this; + } + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:dineth.grpc.v1.student.StudentRequest) + } + + // @@protoc_insertion_point(class_scope:dineth.grpc.v1.student.StudentRequest) + private static final StudentRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new StudentRequest(); + } + + public static StudentRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public StudentRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new StudentRequest(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public StudentRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentRequestOrBuilder.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentRequestOrBuilder.java new file mode 100644 index 000000000..62c36bc77 --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentRequestOrBuilder.java @@ -0,0 +1,15 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: student.proto + +package org.wso2.apk.integration.utils.clients.studentGrpcClient; + +public interface StudentRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:dineth.grpc.v1.student.StudentRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * int32 id = 3; + * @return The id. + */ + int getId(); +} diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentResponse.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentResponse.java new file mode 100644 index 000000000..33e343eba --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentResponse.java @@ -0,0 +1,621 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: student.proto + +package org.wso2.apk.integration.utils.clients.studentGrpcClient; + +/** + * Protobuf type {@code dineth.grpc.v1.student.StudentResponse} + */ +public final class StudentResponse extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:dineth.grpc.v1.student.StudentResponse) + StudentResponseOrBuilder { +private static final long serialVersionUID = 0L; + // Use StudentResponse.newBuilder() to construct. + private StudentResponse(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private StudentResponse() { + name_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new StudentResponse(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private StudentResponse( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + String s = input.readStringRequireUtf8(); + + name_ = s; + break; + } + case 16: { + + age_ = input.readInt32(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return Student.internal_static_dineth_grpc_v1_student_StudentResponse_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return Student.internal_static_dineth_grpc_v1_student_StudentResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + StudentResponse.class, Builder.class); + } + + public static final int NAME_FIELD_NUMBER = 1; + private volatile Object name_; + /** + * string name = 1; + * @return The name. + */ + @Override + public String getName() { + Object ref = name_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + * string name = 1; + * @return The bytes for name. + */ + @Override + public com.google.protobuf.ByteString + getNameBytes() { + Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int AGE_FIELD_NUMBER = 2; + private int age_; + /** + * int32 age = 2; + * @return The age. + */ + @Override + public int getAge() { + return age_; + } + + private byte memoizedIsInitialized = -1; + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getNameBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, name_); + } + if (age_ != 0) { + output.writeInt32(2, age_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getNameBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, name_); + } + if (age_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, age_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof StudentResponse)) { + return super.equals(obj); + } + StudentResponse other = (StudentResponse) obj; + + if (!getName() + .equals(other.getName())) return false; + if (getAge() + != other.getAge()) return false; + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + AGE_FIELD_NUMBER; + hash = (53 * hash) + getAge(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static StudentResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static StudentResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static StudentResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static StudentResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static StudentResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static StudentResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static StudentResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static StudentResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static StudentResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static StudentResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static StudentResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static StudentResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(StudentResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code dineth.grpc.v1.student.StudentResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:dineth.grpc.v1.student.StudentResponse) + StudentResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return Student.internal_static_dineth_grpc_v1_student_StudentResponse_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return Student.internal_static_dineth_grpc_v1_student_StudentResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + StudentResponse.class, Builder.class); + } + + // Construct using org.wso2.apk.integration.utils.clients.studentGrpcClient.StudentResponse.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @Override + public Builder clear() { + super.clear(); + name_ = ""; + + age_ = 0; + + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return Student.internal_static_dineth_grpc_v1_student_StudentResponse_descriptor; + } + + @Override + public StudentResponse getDefaultInstanceForType() { + return StudentResponse.getDefaultInstance(); + } + + @Override + public StudentResponse build() { + StudentResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public StudentResponse buildPartial() { + StudentResponse result = new StudentResponse(this); + result.name_ = name_; + result.age_ = age_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof StudentResponse) { + return mergeFrom((StudentResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(StudentResponse other) { + if (other == StudentResponse.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + onChanged(); + } + if (other.getAge() != 0) { + setAge(other.getAge()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + StudentResponse parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (StudentResponse) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private Object name_ = ""; + /** + * string name = 1; + * @return The name. + */ + public String getName() { + Object ref = name_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (String) ref; + } + } + /** + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + name_ = value; + onChanged(); + return this; + } + /** + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + /** + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + name_ = value; + onChanged(); + return this; + } + + private int age_ ; + /** + * int32 age = 2; + * @return The age. + */ + @Override + public int getAge() { + return age_; + } + /** + * int32 age = 2; + * @param value The age to set. + * @return This builder for chaining. + */ + public Builder setAge(int value) { + + age_ = value; + onChanged(); + return this; + } + /** + * int32 age = 2; + * @return This builder for chaining. + */ + public Builder clearAge() { + + age_ = 0; + onChanged(); + return this; + } + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:dineth.grpc.v1.student.StudentResponse) + } + + // @@protoc_insertion_point(class_scope:dineth.grpc.v1.student.StudentResponse) + private static final StudentResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new StudentResponse(); + } + + public static StudentResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public StudentResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new StudentResponse(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public StudentResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentResponseOrBuilder.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentResponseOrBuilder.java new file mode 100644 index 000000000..08946635c --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentResponseOrBuilder.java @@ -0,0 +1,27 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: student.proto + +package org.wso2.apk.integration.utils.clients.studentGrpcClient; + +public interface StudentResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:dineth.grpc.v1.student.StudentResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * string name = 1; + * @return The name. + */ + String getName(); + /** + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + * int32 age = 2; + * @return The age. + */ + int getAge(); +} diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentServiceDefaultVersionGrpc.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentServiceDefaultVersionGrpc.java new file mode 100644 index 000000000..9a2878343 --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentServiceDefaultVersionGrpc.java @@ -0,0 +1,458 @@ +package org.wso2.apk.integration.utils.clients.studentGrpcClient; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.39.0)", + comments = "Source: student.proto") +public final class StudentServiceDefaultVersionGrpc { + + private StudentServiceDefaultVersionGrpc() {} + + public static final String SERVICE_NAME = "dineth.grpc.api.student.StudentService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getGetStudentMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetStudent", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetStudentMethod() { + io.grpc.MethodDescriptor getGetStudentMethod; + if ((getGetStudentMethod = StudentServiceDefaultVersionGrpc.getGetStudentMethod) == null) { + synchronized (StudentServiceDefaultVersionGrpc.class) { + if ((getGetStudentMethod = StudentServiceDefaultVersionGrpc.getGetStudentMethod) == null) { + StudentServiceDefaultVersionGrpc.getGetStudentMethod = getGetStudentMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetStudent")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("GetStudent")) + .build(); + } + } + } + return getGetStudentMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetStudentStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetStudentStream", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + public static io.grpc.MethodDescriptor getGetStudentStreamMethod() { + io.grpc.MethodDescriptor getGetStudentStreamMethod; + if ((getGetStudentStreamMethod = StudentServiceDefaultVersionGrpc.getGetStudentStreamMethod) == null) { + synchronized (StudentServiceDefaultVersionGrpc.class) { + if ((getGetStudentStreamMethod = StudentServiceDefaultVersionGrpc.getGetStudentStreamMethod) == null) { + StudentServiceDefaultVersionGrpc.getGetStudentStreamMethod = getGetStudentStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetStudentStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("GetStudentStream")) + .build(); + } + } + } + return getGetStudentStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getSendStudentStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendStudentStream", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.CLIENT_STREAMING) + public static io.grpc.MethodDescriptor getSendStudentStreamMethod() { + io.grpc.MethodDescriptor getSendStudentStreamMethod; + if ((getSendStudentStreamMethod = StudentServiceDefaultVersionGrpc.getSendStudentStreamMethod) == null) { + synchronized (StudentServiceDefaultVersionGrpc.class) { + if ((getSendStudentStreamMethod = StudentServiceDefaultVersionGrpc.getSendStudentStreamMethod) == null) { + StudentServiceDefaultVersionGrpc.getSendStudentStreamMethod = getSendStudentStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.CLIENT_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendStudentStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("SendStudentStream")) + .build(); + } + } + } + return getSendStudentStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getSendAndGetStudentStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendAndGetStudentStream", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getSendAndGetStudentStreamMethod() { + io.grpc.MethodDescriptor getSendAndGetStudentStreamMethod; + if ((getSendAndGetStudentStreamMethod = StudentServiceDefaultVersionGrpc.getSendAndGetStudentStreamMethod) == null) { + synchronized (StudentServiceDefaultVersionGrpc.class) { + if ((getSendAndGetStudentStreamMethod = StudentServiceDefaultVersionGrpc.getSendAndGetStudentStreamMethod) == null) { + StudentServiceDefaultVersionGrpc.getSendAndGetStudentStreamMethod = getSendAndGetStudentStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendAndGetStudentStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("SendAndGetStudentStream")) + .build(); + } + } + } + return getSendAndGetStudentStreamMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static StudentServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public StudentServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceStub(channel, callOptions); + } + }; + return StudentServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static StudentServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public StudentServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceBlockingStub(channel, callOptions); + } + }; + return StudentServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static StudentServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public StudentServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceFutureStub(channel, callOptions); + } + }; + return StudentServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public static abstract class StudentServiceImplBase implements io.grpc.BindableService { + + /** + */ + public void getStudent(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetStudentMethod(), responseObserver); + } + + /** + */ + public void getStudentStream(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetStudentStreamMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getSendStudentStreamMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendAndGetStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getSendAndGetStudentStreamMethod(), responseObserver); + } + + @Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getGetStudentMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_GET_STUDENT))) + .addMethod( + getGetStudentStreamMethod(), + io.grpc.stub.ServerCalls.asyncServerStreamingCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_GET_STUDENT_STREAM))) + .addMethod( + getSendStudentStreamMethod(), + io.grpc.stub.ServerCalls.asyncClientStreamingCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_SEND_STUDENT_STREAM))) + .addMethod( + getSendAndGetStudentStreamMethod(), + io.grpc.stub.ServerCalls.asyncBidiStreamingCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_SEND_AND_GET_STUDENT_STREAM))) + .build(); + } + } + + /** + */ + public static final class StudentServiceStub extends io.grpc.stub.AbstractAsyncStub { + private StudentServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected StudentServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceStub(channel, callOptions); + } + + /** + */ + public void getStudent(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetStudentMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getStudentStream(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncServerStreamingCall( + getChannel().newCall(getGetStudentStreamMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncClientStreamingCall( + getChannel().newCall(getSendStudentStreamMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendAndGetStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncBidiStreamingCall( + getChannel().newCall(getSendAndGetStudentStreamMethod(), getCallOptions()), responseObserver); + } + } + + /** + */ + public static final class StudentServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private StudentServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected StudentServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceBlockingStub(channel, callOptions); + } + + /** + */ + public StudentResponse getStudent(StudentRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetStudentMethod(), getCallOptions(), request); + } + + /** + */ + public java.util.Iterator getStudentStream( + StudentRequest request) { + return io.grpc.stub.ClientCalls.blockingServerStreamingCall( + getChannel(), getGetStudentStreamMethod(), getCallOptions(), request); + } + } + + /** + */ + public static final class StudentServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private StudentServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected StudentServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getStudent( + StudentRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetStudentMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_GET_STUDENT = 0; + private static final int METHODID_GET_STUDENT_STREAM = 1; + private static final int METHODID_SEND_STUDENT_STREAM = 2; + private static final int METHODID_SEND_AND_GET_STUDENT_STREAM = 3; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final StudentServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(StudentServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_GET_STUDENT: + serviceImpl.getStudent((StudentRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_STUDENT_STREAM: + serviceImpl.getStudentStream((StudentRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_SEND_STUDENT_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.sendStudentStream( + (io.grpc.stub.StreamObserver) responseObserver); + case METHODID_SEND_AND_GET_STUDENT_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.sendAndGetStudentStream( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class StudentServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + StudentServiceBaseDescriptorSupplier() {} + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return Student.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("StudentService"); + } + } + + private static final class StudentServiceFileDescriptorSupplier + extends StudentServiceBaseDescriptorSupplier { + StudentServiceFileDescriptorSupplier() {} + } + + private static final class StudentServiceMethodDescriptorSupplier + extends StudentServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + StudentServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (StudentServiceDefaultVersionGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new StudentServiceFileDescriptorSupplier()) + .addMethod(getGetStudentMethod()) + .addMethod(getGetStudentStreamMethod()) + .addMethod(getSendStudentStreamMethod()) + .addMethod(getSendAndGetStudentStreamMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentServiceGrpc.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentServiceGrpc.java new file mode 100644 index 000000000..b9b158c0f --- /dev/null +++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/utils/clients/studentGrpcClient/StudentServiceGrpc.java @@ -0,0 +1,458 @@ +package org.wso2.apk.integration.utils.clients.studentGrpcClient; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.39.0)", + comments = "Source: student.proto") +public final class StudentServiceGrpc { + + private StudentServiceGrpc() {} + + public static final String SERVICE_NAME = "dineth.grpc.api.v1.student.StudentService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getGetStudentMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetStudent", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetStudentMethod() { + io.grpc.MethodDescriptor getGetStudentMethod; + if ((getGetStudentMethod = StudentServiceGrpc.getGetStudentMethod) == null) { + synchronized (StudentServiceGrpc.class) { + if ((getGetStudentMethod = StudentServiceGrpc.getGetStudentMethod) == null) { + StudentServiceGrpc.getGetStudentMethod = getGetStudentMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetStudent")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("GetStudent")) + .build(); + } + } + } + return getGetStudentMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetStudentStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetStudentStream", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + public static io.grpc.MethodDescriptor getGetStudentStreamMethod() { + io.grpc.MethodDescriptor getGetStudentStreamMethod; + if ((getGetStudentStreamMethod = StudentServiceGrpc.getGetStudentStreamMethod) == null) { + synchronized (StudentServiceGrpc.class) { + if ((getGetStudentStreamMethod = StudentServiceGrpc.getGetStudentStreamMethod) == null) { + StudentServiceGrpc.getGetStudentStreamMethod = getGetStudentStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetStudentStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("GetStudentStream")) + .build(); + } + } + } + return getGetStudentStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getSendStudentStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendStudentStream", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.CLIENT_STREAMING) + public static io.grpc.MethodDescriptor getSendStudentStreamMethod() { + io.grpc.MethodDescriptor getSendStudentStreamMethod; + if ((getSendStudentStreamMethod = StudentServiceGrpc.getSendStudentStreamMethod) == null) { + synchronized (StudentServiceGrpc.class) { + if ((getSendStudentStreamMethod = StudentServiceGrpc.getSendStudentStreamMethod) == null) { + StudentServiceGrpc.getSendStudentStreamMethod = getSendStudentStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.CLIENT_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendStudentStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("SendStudentStream")) + .build(); + } + } + } + return getSendStudentStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getSendAndGetStudentStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendAndGetStudentStream", + requestType = StudentRequest.class, + responseType = StudentResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getSendAndGetStudentStreamMethod() { + io.grpc.MethodDescriptor getSendAndGetStudentStreamMethod; + if ((getSendAndGetStudentStreamMethod = StudentServiceGrpc.getSendAndGetStudentStreamMethod) == null) { + synchronized (StudentServiceGrpc.class) { + if ((getSendAndGetStudentStreamMethod = StudentServiceGrpc.getSendAndGetStudentStreamMethod) == null) { + StudentServiceGrpc.getSendAndGetStudentStreamMethod = getSendAndGetStudentStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendAndGetStudentStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + StudentResponse.getDefaultInstance())) + .setSchemaDescriptor(new StudentServiceMethodDescriptorSupplier("SendAndGetStudentStream")) + .build(); + } + } + } + return getSendAndGetStudentStreamMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static StudentServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public StudentServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceStub(channel, callOptions); + } + }; + return StudentServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static StudentServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public StudentServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceBlockingStub(channel, callOptions); + } + }; + return StudentServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static StudentServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public StudentServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceFutureStub(channel, callOptions); + } + }; + return StudentServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public static abstract class StudentServiceImplBase implements io.grpc.BindableService { + + /** + */ + public void getStudent(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetStudentMethod(), responseObserver); + } + + /** + */ + public void getStudentStream(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetStudentStreamMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getSendStudentStreamMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendAndGetStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getSendAndGetStudentStreamMethod(), responseObserver); + } + + @Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getGetStudentMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_GET_STUDENT))) + .addMethod( + getGetStudentStreamMethod(), + io.grpc.stub.ServerCalls.asyncServerStreamingCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_GET_STUDENT_STREAM))) + .addMethod( + getSendStudentStreamMethod(), + io.grpc.stub.ServerCalls.asyncClientStreamingCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_SEND_STUDENT_STREAM))) + .addMethod( + getSendAndGetStudentStreamMethod(), + io.grpc.stub.ServerCalls.asyncBidiStreamingCall( + new MethodHandlers< + StudentRequest, + StudentResponse>( + this, METHODID_SEND_AND_GET_STUDENT_STREAM))) + .build(); + } + } + + /** + */ + public static final class StudentServiceStub extends io.grpc.stub.AbstractAsyncStub { + private StudentServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected StudentServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceStub(channel, callOptions); + } + + /** + */ + public void getStudent(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetStudentMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getStudentStream(StudentRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncServerStreamingCall( + getChannel().newCall(getGetStudentStreamMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncClientStreamingCall( + getChannel().newCall(getSendStudentStreamMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver sendAndGetStudentStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncBidiStreamingCall( + getChannel().newCall(getSendAndGetStudentStreamMethod(), getCallOptions()), responseObserver); + } + } + + /** + */ + public static final class StudentServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private StudentServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected StudentServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceBlockingStub(channel, callOptions); + } + + /** + */ + public StudentResponse getStudent(StudentRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetStudentMethod(), getCallOptions(), request); + } + + /** + */ + public java.util.Iterator getStudentStream( + StudentRequest request) { + return io.grpc.stub.ClientCalls.blockingServerStreamingCall( + getChannel(), getGetStudentStreamMethod(), getCallOptions(), request); + } + } + + /** + */ + public static final class StudentServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private StudentServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected StudentServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new StudentServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getStudent( + StudentRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetStudentMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_GET_STUDENT = 0; + private static final int METHODID_GET_STUDENT_STREAM = 1; + private static final int METHODID_SEND_STUDENT_STREAM = 2; + private static final int METHODID_SEND_AND_GET_STUDENT_STREAM = 3; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final StudentServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(StudentServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_GET_STUDENT: + serviceImpl.getStudent((StudentRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_STUDENT_STREAM: + serviceImpl.getStudentStream((StudentRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_SEND_STUDENT_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.sendStudentStream( + (io.grpc.stub.StreamObserver) responseObserver); + case METHODID_SEND_AND_GET_STUDENT_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.sendAndGetStudentStream( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class StudentServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + StudentServiceBaseDescriptorSupplier() {} + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return Student.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("StudentService"); + } + } + + private static final class StudentServiceFileDescriptorSupplier + extends StudentServiceBaseDescriptorSupplier { + StudentServiceFileDescriptorSupplier() {} + } + + private static final class StudentServiceMethodDescriptorSupplier + extends StudentServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + StudentServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (StudentServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new StudentServiceFileDescriptorSupplier()) + .addMethod(getGetStudentMethod()) + .addMethod(getGetStudentStreamMethod()) + .addMethod(getSendStudentStreamMethod()) + .addMethod(getSendAndGetStudentStreamMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc.apk-conf new file mode 100644 index 000000000..4d291742b --- /dev/null +++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc.apk-conf @@ -0,0 +1,28 @@ +--- +name: "demo-grpc-api" +basePath: "/dineth.grpc.api" +version: "v1" +type: "GRPC" +id: "grpc-basic-api" +endpointConfigurations: + production: + endpoint: "http://grpc-backend:6565" +defaultVersion: false +subscriptionValidation: false +operations: +- target: "student.StudentService" + verb: "GetStudent" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "GetStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendAndGetStudentStream" + secured: true + scopes: [] \ No newline at end of file diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_scopes.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_scopes.apk-conf new file mode 100644 index 000000000..c4edb6983 --- /dev/null +++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_scopes.apk-conf @@ -0,0 +1,28 @@ +--- +name: "demo-grpc-api" +basePath: "/dineth.grpc.api" +version: "v1" +type: "GRPC" +id: "grpc-scopes" +endpointConfigurations: + production: + endpoint: "http://grpc-backend:6565" +defaultVersion: false +subscriptionValidation: false +operations: +- target: "student.StudentService" + verb: "GetStudent" + secured: true + scopes: ["wso2"] +- target: "student.StudentService" + verb: "GetStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendAndGetStudentStream" + secured: true + scopes: [] \ No newline at end of file diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_default_version.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_default_version.apk-conf new file mode 100644 index 000000000..2c2f88441 --- /dev/null +++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_default_version.apk-conf @@ -0,0 +1,28 @@ +--- +name: "demo-grpc-api" +basePath: "/dineth.grpc.api" +version: "v1" +type: "GRPC" +id: "grpc-default-version-api" +endpointConfigurations: + production: + endpoint: "http://grpc-backend:6565" +defaultVersion: true +subscriptionValidation: false +operations: +- target: "student.StudentService" + verb: "GetStudent" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "GetStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendAndGetStudentStream" + secured: true + scopes: [] \ No newline at end of file diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_disabled_auth.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_disabled_auth.apk-conf new file mode 100644 index 000000000..50bdc465b --- /dev/null +++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_disabled_auth.apk-conf @@ -0,0 +1,32 @@ +--- +name: "demo-grpc-api" +basePath: "/dineth.grpc.api" +version: "v1" +type: "GRPC" +id: "grpc-auth-disabled-api" +endpointConfigurations: + production: + endpoint: "http://grpc-backend:6565" +defaultVersion: false +subscriptionValidation: false +operations: +- target: "student.StudentService" + verb: "GetStudent" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "GetStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendAndGetStudentStream" + secured: true + scopes: [] +authentication: + - authType: OAuth2 + required: mandatory + enabled: false diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_mtls_mandatory_oauth2_disabled.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_mtls_mandatory_oauth2_disabled.apk-conf new file mode 100644 index 000000000..8341e9095 --- /dev/null +++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_mtls_mandatory_oauth2_disabled.apk-conf @@ -0,0 +1,36 @@ +--- +name: "demo-grpc-api" +basePath: "/dineth.grpc.api" +version: "v1" +type: "GRPC" +id: "grpc-mtls-mandatory-oauth2-disabled" +endpointConfigurations: + production: + endpoint: "http://grpc-backend:6565" +defaultVersion: false +subscriptionValidation: false +operations: +- target: "student.StudentService" + verb: "GetStudent" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "GetStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendAndGetStudentStream" + secured: true + scopes: [] +authentication: + - authType: OAuth2 + enabled: false + - authType: mTLS + required: mandatory + certificates: + - name: mtls-test-configmap + key: tls.crt diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_mtls_optional_oauth2_optional.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_mtls_optional_oauth2_optional.apk-conf new file mode 100644 index 000000000..57a849c5a --- /dev/null +++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/grpc/grpc_with_mtls_optional_oauth2_optional.apk-conf @@ -0,0 +1,36 @@ +--- +name: "demo-grpc-api" +basePath: "/dineth.grpc.api" +version: "v1" +type: "GRPC" +id: "grpc-mtls-optional-oauth2-optional" +endpointConfigurations: + production: + endpoint: "http://grpc-backend:6565" +defaultVersion: false +subscriptionValidation: false +operations: +- target: "student.StudentService" + verb: "GetStudent" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "GetStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendStudentStream" + secured: true + scopes: [] +- target: "student.StudentService" + verb: "SendAndGetStudentStream" + secured: true + scopes: [] +authentication: + - authType: OAuth2 + required: optional + - authType: mTLS + required: optional + certificates: + - name: mtls-test-configmap + key: tls.crt diff --git a/test/cucumber-tests/src/test/resources/artifacts/definitions/student.proto b/test/cucumber-tests/src/test/resources/artifacts/definitions/student.proto new file mode 100644 index 000000000..885c45cfb --- /dev/null +++ b/test/cucumber-tests/src/test/resources/artifacts/definitions/student.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.example"; +package dineth.grpc.api.v1.student; + +service StudentService { + rpc GetStudent(StudentRequest) returns (StudentResponse) {}; + rpc GetStudentStream(StudentRequest) returns (stream StudentResponse) {}; + rpc SendStudentStream(stream StudentRequest) returns (StudentResponse) {}; + rpc SendAndGetStudentStream(stream StudentRequest) returns (stream StudentResponse) {} +} + +message StudentRequest { + int32 id = 3; +} + +message StudentResponse { + string name = 1; + int32 age = 2; +} diff --git a/test/cucumber-tests/src/test/resources/tests/api/GRPC.feature b/test/cucumber-tests/src/test/resources/tests/api/GRPC.feature new file mode 100644 index 000000000..873ad7c48 --- /dev/null +++ b/test/cucumber-tests/src/test/resources/tests/api/GRPC.feature @@ -0,0 +1,115 @@ +Feature: Generating APK conf for gRPC API + Scenario: Generating APK conf using a valid GRPC API definition + Given The system is ready + When I use the definition file "artifacts/definitions/student.proto" in resources + And generate the APK conf file for a "gRPC" API + Then the response status code should be 200 + + Scenario: Deploying APK conf using a valid gRPC API definition + Given The system is ready + And I have a valid subscription + When I use the APK Conf file "artifacts/apk-confs/grpc/grpc.apk-conf" + And the definition file "artifacts/definitions/student.proto" + And make the API deployment request + Then the response status code should be 200 + Then I set headers + | Authorization | bearer ${accessToken} | + And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 0 + And the student response body should contain name: "Dineth" age: 10 + + Scenario: Undeploy API + Given The system is ready + And I have a valid subscription + When I undeploy the API whose ID is "grpc-basic-api" + Then the response status code should be 202 + + Scenario: Checking api-definition endpoint to get proto file + Given The system is ready + And I have a valid subscription + When I use the APK Conf file "artifacts/apk-confs/grpc/grpc.apk-conf" + And the definition file "artifacts/definitions/student.proto" + And make the API deployment request + Then the response status code should be 200 + Then I set headers + | Authorization | bearer ${accessToken} | + | Host | default.gw.wso2.com | + And I send "GET" request to "https://default.gw.wso2.com:9095/dineth.grpc.api.v1/api-definition/" with body "" + And I eventually receive 200 response code, not accepting + | 429 | + | 500 | + And the response body should contain endpoint definition for student.proto + + + Scenario: Undeploy API + Given The system is ready + And I have a valid subscription + When I undeploy the API whose ID is "grpc-basic-api" + Then the response status code should be 202 + + Scenario: Deploying gRPC API with OAuth2 disabled + Given The system is ready + And I have a valid subscription + When I use the APK Conf file "artifacts/apk-confs/grpc/grpc_with_disabled_auth.apk-conf" + And the definition file "artifacts/definitions/student.proto" + And make the API deployment request + Then the response status code should be 200 + And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 0 + And the student response body should contain name: "Dineth" age: 10 + + Scenario: Undeploy API + Given The system is ready + And I have a valid subscription + When I undeploy the API whose ID is "grpc-auth-disabled-api" + Then the response status code should be 202 + + Scenario: Deploying gRPC API with scopes + Given The system is ready + And I have a valid subscription + When I use the APK Conf file "artifacts/apk-confs/grpc/grpc_scopes.apk-conf" + And the definition file "artifacts/definitions/student.proto" + And make the API deployment request + Then the response status code should be 200 + Then I set headers + | Authorization | bearer ${accessToken} | + And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 7 + Given I have a valid subscription with scopes + | wso2 | + Then I set headers + | Authorization | bearer ${accessToken} | + And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 0 + And the student response body should contain name: "Dineth" age: 10 + + Scenario: Undeploy API + Given The system is ready + And I have a valid subscription + When I undeploy the API whose ID is "grpc-scopes" + Then the response status code should be 202 + + Scenario: Deploying gRPC API with default version enabled + Given The system is ready + And I have a valid subscription + When I use the APK Conf file "artifacts/apk-confs/grpc/grpc_with_default_version.apk-conf" + And the definition file "artifacts/definitions/student.proto" + And make the API deployment request + Then the response status code should be 200 + Then I set headers + | Authorization | bearer ${accessToken} | + And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 0 + And the student response body should contain name: "Dineth" age: 10 + Given I have a valid subscription + Then I set headers + | Authorization | bearer ${accessToken} | + And I make grpc request GetStudent default version to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 0 + And the student response body should contain name: "Dineth" age: 10 + + Scenario: Undeploy API + Given The system is ready + And I have a valid subscription + When I undeploy the API whose ID is "grpc-default-version-api" + Then the response status code should be 202 \ No newline at end of file diff --git a/test/cucumber-tests/src/test/resources/tests/api/GRPCMTLS.feature b/test/cucumber-tests/src/test/resources/tests/api/GRPCMTLS.feature new file mode 100644 index 000000000..87fa0fac0 --- /dev/null +++ b/test/cucumber-tests/src/test/resources/tests/api/GRPCMTLS.feature @@ -0,0 +1,38 @@ +Feature: Test mTLS between client and gateway with client certificate sent in header + Scenario: Test API with mandatory mTLS and OAuth2 disabled + Given The system is ready + And I have a valid token with a client certificate "invalid-cert.txt" + When I use the APK Conf file "artifacts/apk-confs/grpc/grpc_with_mtls_mandatory_oauth2_disabled.apk-conf" + And the definition file "artifacts/definitions/student.proto" + And make the API deployment request + Then the response status code should be 200 + Then I set headers + | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate} | + And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 0 + And the student response body should contain name: "Dineth" age: 10 + + Scenario: Undeploy API + Given The system is ready + And I have a valid subscription + When I undeploy the API whose ID is "grpc-mtls-mandatory-oauth2-disabled" + Then the response status code should be 202 + + Scenario: Test optional mTLS and optional OAuth2 with an invalid client certificate and invalid token in header + Given The system is ready + And I have a valid token with a client certificate "invalid-cert.txt" + When I use the APK Conf file "artifacts/apk-confs/grpc/grpc_with_mtls_optional_oauth2_optional.apk-conf" + And the definition file "artifacts/definitions/student.proto" + And make the API deployment request + Then the response status code should be 200 + Then I set headers + | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate} | + | Authorization | bearer {accessToken} | + And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095 + And the gRPC response status code should be 16 + + Scenario: Undeploy API + Given The system is ready + And I have a valid subscription + When I undeploy the API whose ID is "grpc-mtls-optional-oauth2-optional" + Then the response status code should be 202 diff --git a/test/integration/integration/tests/grpc-api.go b/test/integration/integration/tests/grpc-api.go new file mode 100644 index 000000000..43632c1f9 --- /dev/null +++ b/test/integration/integration/tests/grpc-api.go @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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 tests + +import ( + "github.com/wso2/apk/test/integration/integration/utils/grpc-code/student" + "github.com/wso2/apk/test/integration/integration/utils/grpc-code/student_default_version" + "github.com/wso2/apk/test/integration/integration/utils/grpcutils" + "github.com/wso2/apk/test/integration/integration/utils/suite" + "testing" +) + +func init() { + IntegrationTests = append(IntegrationTests, GRPCAPI) +} + +// GRPCAPI tests gRPC API +var GRPCAPI = suite.IntegrationTest{ + ShortName: "GRPCAPI", + Description: "Tests gRPC API", + Manifests: []string{"tests/grpc-api.yaml"}, + Test: func(t *testing.T, suite *suite.IntegrationTestSuite) { + gwAddr := "grpc.test.gw.wso2.com:9095" + + testCases := []grpcutils.GRPCTestCase{ + { + ExpectedResponse: grpcutils.ExpectedResponse{ + Out: &student.StudentResponse{ + Name: "Dineth", + Age: 10, + }, + Err: nil, + }, + ActualResponse: &student.StudentResponse{}, + Name: "Get Student Details", + Method: student.GetStudent, + Satisfier: student.StudentResponseSatisfier{}, + }, + { + ExpectedResponse: grpcutils.ExpectedResponse{ + Out: &student_default_version.StudentResponse{ + Name: "Dineth", + Age: 10, + }, + Err: nil, + }, + ActualResponse: &student_default_version.StudentResponse{}, + Name: "Get Student Details (Default API Version)", + Method: student_default_version.GetStudent, + Satisfier: student_default_version.StudentResponseSatisfier{}, + }, + } + for i := range testCases { + tc := testCases[i] + t.Run("Invoke gRPC API", func(t *testing.T) { + t.Parallel() + grpcutils.InvokeGRPCClientUntilSatisfied(gwAddr, t, tc, tc.Satisfier, tc.Method) + }) + } + }, +} diff --git a/test/integration/integration/tests/resources/base/manifests.yaml b/test/integration/integration/tests/resources/base/manifests.yaml index 5d4ef2460..58883fa98 100644 --- a/test/integration/integration/tests/resources/base/manifests.yaml +++ b/test/integration/integration/tests/resources/base/manifests.yaml @@ -113,6 +113,53 @@ spec: --- apiVersion: v1 kind: Service +metadata: + name: grpc-backend-v1 + namespace: gateway-integration-test-infra +spec: + selector: + app: grpc-backend-v1 + ports: + - protocol: TCP + port: 6565 + targetPort: 6565 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grpc-backend-v1 + namespace: gateway-integration-test-infra + labels: + app: grpc-backend-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: grpc-backend-v1 + template: + metadata: + labels: + app: grpc-backend-v1 + spec: + containers: + - name: grpc-backend-v1 + image: ddh13/dineth-grpc-demo-server:1.0.0 + imagePullPolicy: Always + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + resources: + requests: + cpu: 10m +--- +apiVersion: v1 +kind: Service metadata: name: infra-backend-v2 namespace: gateway-integration-test-infra diff --git a/test/integration/integration/tests/resources/tests/grpc-api.yaml b/test/integration/integration/tests/resources/tests/grpc-api.yaml new file mode 100644 index 000000000..359b00a49 --- /dev/null +++ b/test/integration/integration/tests/resources/tests/grpc-api.yaml @@ -0,0 +1,109 @@ +# Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. 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. + +apiVersion: dp.wso2.com/v1beta1 +kind: API +metadata: + name: grpc-api + namespace: gateway-integration-test-infra +spec: + apiName: GRPC API + apiType: GRPC + apiVersion: v1 + basePath: /dineth.grpc.api.v1 + isDefaultVersion: true + production: + - routeRefs: + - grpc-api-grpcroute + organization: wso2-org + +--- + +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: GRPCRoute +metadata: + name: grpc-api-grpcroute + namespace: gateway-integration-test-infra +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: wso2-apk-default + namespace: apk-integration-test + sectionName: httpslistener + hostnames: + - grpc.test.gw.wso2.com + rules: + - matches: + - method: + service: student.StudentService + method: GetStudent + backendRefs: + - name: grpc-backend-v1 + kind: Backend + port: 6565 + - matches: + - method: + service: student.StudentService + method: SendStudentStream + backendRefs: + - name: grpc-backend-v1 + kind: Backend + port: 6565 + - matches: + - method: + service: student.StudentService + method: GetStudentStream + backendRefs: + - name: grpc-backend-v1 + kind: Backend + port: 6565 + - matches: + - method: + service: student.StudentService + method: SendAndGetStudentStream + backendRefs: + - name: grpc-backend-v1 + kind: Backend + port: 6565 + +--- + +apiVersion: dp.wso2.com/v1alpha1 +kind: Authentication +metadata: + name: disable-grpc-api-security + namespace: gateway-integration-test-infra +spec: + override: + disabled: true + targetRef: + group: gateway.networking.k8s.io + kind: API + namespace: gateway-integration-test-infra + name: grpc-api +--- +apiVersion: dp.wso2.com/v1alpha1 +kind: Backend +metadata: + name: grpc-backend-v1 + namespace: gateway-integration-test-infra +spec: + services: + - host: grpc-backend-v1.gateway-integration-test-infra + port: 6565 + basePath: "" + protocol: http diff --git a/test/integration/integration/utils/grpc-code/student/student.go b/test/integration/integration/utils/grpc-code/student/student.go new file mode 100644 index 000000000..36143eb56 --- /dev/null +++ b/test/integration/integration/utils/grpc-code/student/student.go @@ -0,0 +1,46 @@ +package student + +import ( + "context" + "github.com/wso2/apk/test/integration/integration/utils/grpcutils" + "google.golang.org/grpc" + "log" + "time" +) + +type StudentResponseSatisfier struct{} + +// IsSatisfactory checks if the given response is satisfactory based on the expected response. +func (srs StudentResponseSatisfier) IsSatisfactory(response any, expectedResponse grpcutils.ExpectedResponse) bool { + // Type assert the response to *student.StudentResponse + resp, respOk := response.(*StudentResponse) + if !respOk { + log.Println("Failed to assert response as *student.StudentResponse") + return false + } + // Type assert the expected output to *student.StudentResponse + expectedResp, expOk := expectedResponse.Out.(*StudentResponse) + if !expOk { + log.Println("Failed to assert expectedResponse.Out as *student.StudentResponse") + return false + } + + // Compare the actual response with the expected response + if resp.Name == expectedResp.Name && resp.Age == expectedResp.Age { + return true + } else { + log.Println("Response does not match the expected output") + return false + } +} +func GetStudent(conn *grpc.ClientConn) (any, error) { + c := NewStudentServiceClient(conn) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + r := &StudentRequest{Id: 1234} + response, err := c.GetStudent(ctx, r) + if err != nil { + return nil, err + } + return response, nil +} diff --git a/test/integration/integration/utils/grpc-code/student/student.pb.go b/test/integration/integration/utils/grpc-code/student/student.pb.go new file mode 100644 index 000000000..c8efeffa3 --- /dev/null +++ b/test/integration/integration/utils/grpc-code/student/student.pb.go @@ -0,0 +1,254 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v3.12.4 +// source: student.proto + +package student + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type StudentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,3,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *StudentRequest) Reset() { + *x = StudentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_student_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StudentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StudentRequest) ProtoMessage() {} + +func (x *StudentRequest) ProtoReflect() protoreflect.Message { + mi := &file_student_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StudentRequest.ProtoReflect.Descriptor instead. +func (*StudentRequest) Descriptor() ([]byte, []int) { + return file_student_proto_rawDescGZIP(), []int{0} +} + +func (x *StudentRequest) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +type StudentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` +} + +func (x *StudentResponse) Reset() { + *x = StudentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_student_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StudentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StudentResponse) ProtoMessage() {} + +func (x *StudentResponse) ProtoReflect() protoreflect.Message { + mi := &file_student_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StudentResponse.ProtoReflect.Descriptor instead. +func (*StudentResponse) Descriptor() ([]byte, []int) { + return file_student_proto_rawDescGZIP(), []int{1} +} + +func (x *StudentResponse) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *StudentResponse) GetAge() int32 { + if x != nil { + return x.Age + } + return 0 +} + +var File_student_proto protoreflect.FileDescriptor + +var file_student_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x1a, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x22, 0x20, 0x0a, 0x0e, 0x53, + 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x22, 0x37, 0x0a, + 0x0f, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x32, 0xd6, 0x03, 0x0a, 0x0e, 0x53, 0x74, 0x75, 0x64, 0x65, + 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x67, 0x0a, 0x0a, 0x47, 0x65, 0x74, + 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, 0x75, + 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, + 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x6f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2a, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, 0x75, 0x64, + 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, + 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x30, 0x01, 0x12, 0x70, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x75, 0x64, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2a, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, + 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, + 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, + 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x78, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x6e, 0x64, + 0x47, 0x65, 0x74, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x12, 0x2a, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, + 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x64, + 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, + 0x30, 0x5a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2f, 0x73, 0x63, 0x68, 0x6f, 0x6f, 0x6c, 0x2f, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, + 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_student_proto_rawDescOnce sync.Once + file_student_proto_rawDescData = file_student_proto_rawDesc +) + +func file_student_proto_rawDescGZIP() []byte { + file_student_proto_rawDescOnce.Do(func() { + file_student_proto_rawDescData = protoimpl.X.CompressGZIP(file_student_proto_rawDescData) + }) + return file_student_proto_rawDescData +} + +var file_student_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_student_proto_goTypes = []interface{}{ + (*StudentRequest)(nil), // 0: dineth.grpc.api.v1.student.StudentRequest + (*StudentResponse)(nil), // 1: dineth.grpc.api.v1.student.StudentResponse +} +var file_student_proto_depIdxs = []int32{ + 0, // 0: dineth.grpc.api.v1.student.StudentService.GetStudent:input_type -> dineth.grpc.api.v1.student.StudentRequest + 0, // 1: dineth.grpc.api.v1.student.StudentService.GetStudentStream:input_type -> dineth.grpc.api.v1.student.StudentRequest + 0, // 2: dineth.grpc.api.v1.student.StudentService.SendStudentStream:input_type -> dineth.grpc.api.v1.student.StudentRequest + 0, // 3: dineth.grpc.api.v1.student.StudentService.SendAndGetStudentStream:input_type -> dineth.grpc.api.v1.student.StudentRequest + 1, // 4: dineth.grpc.api.v1.student.StudentService.GetStudent:output_type -> dineth.grpc.api.v1.student.StudentResponse + 1, // 5: dineth.grpc.api.v1.student.StudentService.GetStudentStream:output_type -> dineth.grpc.api.v1.student.StudentResponse + 1, // 6: dineth.grpc.api.v1.student.StudentService.SendStudentStream:output_type -> dineth.grpc.api.v1.student.StudentResponse + 1, // 7: dineth.grpc.api.v1.student.StudentService.SendAndGetStudentStream:output_type -> dineth.grpc.api.v1.student.StudentResponse + 4, // [4:8] is the sub-list for method output_type + 0, // [0:4] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_student_proto_init() } +func file_student_proto_init() { + if File_student_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_student_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StudentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_student_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StudentResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_student_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_student_proto_goTypes, + DependencyIndexes: file_student_proto_depIdxs, + MessageInfos: file_student_proto_msgTypes, + }.Build() + File_student_proto = out.File + file_student_proto_rawDesc = nil + file_student_proto_goTypes = nil + file_student_proto_depIdxs = nil +} diff --git a/test/integration/integration/utils/grpc-code/student/student_grpc.pb.go b/test/integration/integration/utils/grpc-code/student/student_grpc.pb.go new file mode 100644 index 000000000..be4b29e7d --- /dev/null +++ b/test/integration/integration/utils/grpc-code/student/student_grpc.pb.go @@ -0,0 +1,314 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.12.4 +// source: student.proto + +package student + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + StudentService_GetStudent_FullMethodName = "/dineth.grpc.api.v1.student.StudentService/GetStudent" + StudentService_GetStudentStream_FullMethodName = "/dineth.grpc.api.v1.student.StudentService/GetStudentStream" + StudentService_SendStudentStream_FullMethodName = "/dineth.grpc.api.v1.student.StudentService/SendStudentStream" + StudentService_SendAndGetStudentStream_FullMethodName = "/dineth.grpc.api.v1.student.StudentService/SendAndGetStudentStream" +) + +// StudentServiceClient is the client API for StudentService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type StudentServiceClient interface { + GetStudent(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (*StudentResponse, error) + GetStudentStream(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (StudentService_GetStudentStreamClient, error) + SendStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendStudentStreamClient, error) + SendAndGetStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendAndGetStudentStreamClient, error) +} + +type studentServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewStudentServiceClient(cc grpc.ClientConnInterface) StudentServiceClient { + return &studentServiceClient{cc} +} + +func (c *studentServiceClient) GetStudent(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (*StudentResponse, error) { + out := new(StudentResponse) + err := c.cc.Invoke(ctx, StudentService_GetStudent_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *studentServiceClient) GetStudentStream(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (StudentService_GetStudentStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &StudentService_ServiceDesc.Streams[0], StudentService_GetStudentStream_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &studentServiceGetStudentStreamClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type StudentService_GetStudentStreamClient interface { + Recv() (*StudentResponse, error) + grpc.ClientStream +} + +type studentServiceGetStudentStreamClient struct { + grpc.ClientStream +} + +func (x *studentServiceGetStudentStreamClient) Recv() (*StudentResponse, error) { + m := new(StudentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *studentServiceClient) SendStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendStudentStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &StudentService_ServiceDesc.Streams[1], StudentService_SendStudentStream_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &studentServiceSendStudentStreamClient{stream} + return x, nil +} + +type StudentService_SendStudentStreamClient interface { + Send(*StudentRequest) error + CloseAndRecv() (*StudentResponse, error) + grpc.ClientStream +} + +type studentServiceSendStudentStreamClient struct { + grpc.ClientStream +} + +func (x *studentServiceSendStudentStreamClient) Send(m *StudentRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *studentServiceSendStudentStreamClient) CloseAndRecv() (*StudentResponse, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(StudentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *studentServiceClient) SendAndGetStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendAndGetStudentStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &StudentService_ServiceDesc.Streams[2], StudentService_SendAndGetStudentStream_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &studentServiceSendAndGetStudentStreamClient{stream} + return x, nil +} + +type StudentService_SendAndGetStudentStreamClient interface { + Send(*StudentRequest) error + Recv() (*StudentResponse, error) + grpc.ClientStream +} + +type studentServiceSendAndGetStudentStreamClient struct { + grpc.ClientStream +} + +func (x *studentServiceSendAndGetStudentStreamClient) Send(m *StudentRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *studentServiceSendAndGetStudentStreamClient) Recv() (*StudentResponse, error) { + m := new(StudentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// StudentServiceServer is the server API for StudentService service. +// All implementations must embed UnimplementedStudentServiceServer +// for forward compatibility +type StudentServiceServer interface { + GetStudent(context.Context, *StudentRequest) (*StudentResponse, error) + GetStudentStream(*StudentRequest, StudentService_GetStudentStreamServer) error + SendStudentStream(StudentService_SendStudentStreamServer) error + SendAndGetStudentStream(StudentService_SendAndGetStudentStreamServer) error + mustEmbedUnimplementedStudentServiceServer() +} + +// UnimplementedStudentServiceServer must be embedded to have forward compatible implementations. +type UnimplementedStudentServiceServer struct { +} + +func (UnimplementedStudentServiceServer) GetStudent(context.Context, *StudentRequest) (*StudentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStudent not implemented") +} +func (UnimplementedStudentServiceServer) GetStudentStream(*StudentRequest, StudentService_GetStudentStreamServer) error { + return status.Errorf(codes.Unimplemented, "method GetStudentStream not implemented") +} +func (UnimplementedStudentServiceServer) SendStudentStream(StudentService_SendStudentStreamServer) error { + return status.Errorf(codes.Unimplemented, "method SendStudentStream not implemented") +} +func (UnimplementedStudentServiceServer) SendAndGetStudentStream(StudentService_SendAndGetStudentStreamServer) error { + return status.Errorf(codes.Unimplemented, "method SendAndGetStudentStream not implemented") +} +func (UnimplementedStudentServiceServer) mustEmbedUnimplementedStudentServiceServer() {} + +// UnsafeStudentServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StudentServiceServer will +// result in compilation errors. +type UnsafeStudentServiceServer interface { + mustEmbedUnimplementedStudentServiceServer() +} + +func RegisterStudentServiceServer(s grpc.ServiceRegistrar, srv StudentServiceServer) { + s.RegisterService(&StudentService_ServiceDesc, srv) +} + +func _StudentService_GetStudent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StudentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StudentServiceServer).GetStudent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StudentService_GetStudent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StudentServiceServer).GetStudent(ctx, req.(*StudentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StudentService_GetStudentStream_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(StudentRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StudentServiceServer).GetStudentStream(m, &studentServiceGetStudentStreamServer{stream}) +} + +type StudentService_GetStudentStreamServer interface { + Send(*StudentResponse) error + grpc.ServerStream +} + +type studentServiceGetStudentStreamServer struct { + grpc.ServerStream +} + +func (x *studentServiceGetStudentStreamServer) Send(m *StudentResponse) error { + return x.ServerStream.SendMsg(m) +} + +func _StudentService_SendStudentStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StudentServiceServer).SendStudentStream(&studentServiceSendStudentStreamServer{stream}) +} + +type StudentService_SendStudentStreamServer interface { + SendAndClose(*StudentResponse) error + Recv() (*StudentRequest, error) + grpc.ServerStream +} + +type studentServiceSendStudentStreamServer struct { + grpc.ServerStream +} + +func (x *studentServiceSendStudentStreamServer) SendAndClose(m *StudentResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *studentServiceSendStudentStreamServer) Recv() (*StudentRequest, error) { + m := new(StudentRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _StudentService_SendAndGetStudentStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StudentServiceServer).SendAndGetStudentStream(&studentServiceSendAndGetStudentStreamServer{stream}) +} + +type StudentService_SendAndGetStudentStreamServer interface { + Send(*StudentResponse) error + Recv() (*StudentRequest, error) + grpc.ServerStream +} + +type studentServiceSendAndGetStudentStreamServer struct { + grpc.ServerStream +} + +func (x *studentServiceSendAndGetStudentStreamServer) Send(m *StudentResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *studentServiceSendAndGetStudentStreamServer) Recv() (*StudentRequest, error) { + m := new(StudentRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// StudentService_ServiceDesc is the grpc.ServiceDesc for StudentService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StudentService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "dineth.grpc.api.v1.student.StudentService", + HandlerType: (*StudentServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetStudent", + Handler: _StudentService_GetStudent_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "GetStudentStream", + Handler: _StudentService_GetStudentStream_Handler, + ServerStreams: true, + }, + { + StreamName: "SendStudentStream", + Handler: _StudentService_SendStudentStream_Handler, + ClientStreams: true, + }, + { + StreamName: "SendAndGetStudentStream", + Handler: _StudentService_SendAndGetStudentStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "student.proto", +} diff --git a/test/integration/integration/utils/grpc-code/student_default_version/student2.go b/test/integration/integration/utils/grpc-code/student_default_version/student2.go new file mode 100644 index 000000000..939bb3b90 --- /dev/null +++ b/test/integration/integration/utils/grpc-code/student_default_version/student2.go @@ -0,0 +1,46 @@ +package student_default_version + +import ( + "context" + "github.com/wso2/apk/test/integration/integration/utils/grpcutils" + "google.golang.org/grpc" + "log" + "time" +) + +type StudentResponseSatisfier struct{} + +// IsSatisfactory checks if the given response is satisfactory based on the expected response. +func (srs StudentResponseSatisfier) IsSatisfactory(response any, expectedResponse grpcutils.ExpectedResponse) bool { + // Type assert the response to *student.StudentResponse + resp, respOk := response.(*StudentResponse) + if !respOk { + log.Println("Failed to assert response as *student.StudentResponse") + return false + } + // Type assert the expected output to *student.StudentResponse + expectedResp, expOk := expectedResponse.Out.(*StudentResponse) + if !expOk { + log.Println("Failed to assert expectedResponse.Out as *student.StudentResponse") + return false + } + + // Compare the actual response with the expected response + if resp.Name == expectedResp.Name && resp.Age == expectedResp.Age { + return true + } else { + log.Println("Response does not match the expected output") + return false + } +} +func GetStudent(conn *grpc.ClientConn) (any, error) { + c := NewStudentServiceClient(conn) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + r := &StudentRequest{Id: 1234} + response, err := c.GetStudent(ctx, r) + if err != nil { + return nil, err + } + return response, nil +} diff --git a/test/integration/integration/utils/grpc-code/student_default_version/student_default_version.pb.go b/test/integration/integration/utils/grpc-code/student_default_version/student_default_version.pb.go new file mode 100644 index 000000000..a006069e8 --- /dev/null +++ b/test/integration/integration/utils/grpc-code/student_default_version/student_default_version.pb.go @@ -0,0 +1,251 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v3.12.4 +// source: student_default_version.proto + +package student_default_version + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type StudentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,3,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *StudentRequest) Reset() { + *x = StudentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_student_default_version_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StudentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StudentRequest) ProtoMessage() {} + +func (x *StudentRequest) ProtoReflect() protoreflect.Message { + mi := &file_student_default_version_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StudentRequest.ProtoReflect.Descriptor instead. +func (*StudentRequest) Descriptor() ([]byte, []int) { + return file_student_default_version_proto_rawDescGZIP(), []int{0} +} + +func (x *StudentRequest) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +type StudentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` +} + +func (x *StudentResponse) Reset() { + *x = StudentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_student_default_version_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StudentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StudentResponse) ProtoMessage() {} + +func (x *StudentResponse) ProtoReflect() protoreflect.Message { + mi := &file_student_default_version_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StudentResponse.ProtoReflect.Descriptor instead. +func (*StudentResponse) Descriptor() ([]byte, []int) { + return file_student_default_version_proto_rawDescGZIP(), []int{1} +} + +func (x *StudentResponse) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *StudentResponse) GetAge() int32 { + if x != nil { + return x.Age + } + return 0 +} + +var File_student_default_version_proto protoreflect.FileDescriptor + +var file_student_default_version_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x17, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x22, 0x20, 0x0a, 0x0e, 0x53, 0x74, 0x75, 0x64, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x22, 0x37, 0x0a, 0x0f, 0x53, 0x74, + 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, + 0x61, 0x67, 0x65, 0x32, 0xbe, 0x03, 0x0a, 0x0e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x74, 0x75, + 0x64, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, + 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, + 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x69, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x27, 0x2e, + 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, + 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x30, 0x01, 0x12, 0x6a, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x75, 0x64, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x27, 0x2e, 0x64, 0x69, 0x6e, 0x65, + 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x74, 0x75, 0x64, + 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, + 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, + 0x12, 0x72, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x53, 0x74, + 0x75, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x27, 0x2e, 0x64, 0x69, + 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x74, + 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x64, 0x69, 0x6e, 0x65, 0x74, 0x68, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, + 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x28, 0x01, 0x30, 0x01, 0x42, 0x0f, 0x0a, 0x0b, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x50, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_student_default_version_proto_rawDescOnce sync.Once + file_student_default_version_proto_rawDescData = file_student_default_version_proto_rawDesc +) + +func file_student_default_version_proto_rawDescGZIP() []byte { + file_student_default_version_proto_rawDescOnce.Do(func() { + file_student_default_version_proto_rawDescData = protoimpl.X.CompressGZIP(file_student_default_version_proto_rawDescData) + }) + return file_student_default_version_proto_rawDescData +} + +var file_student_default_version_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_student_default_version_proto_goTypes = []interface{}{ + (*StudentRequest)(nil), // 0: dineth.grpc.api.student.StudentRequest + (*StudentResponse)(nil), // 1: dineth.grpc.api.student.StudentResponse +} +var file_student_default_version_proto_depIdxs = []int32{ + 0, // 0: dineth.grpc.api.student.StudentService.GetStudent:input_type -> dineth.grpc.api.student.StudentRequest + 0, // 1: dineth.grpc.api.student.StudentService.GetStudentStream:input_type -> dineth.grpc.api.student.StudentRequest + 0, // 2: dineth.grpc.api.student.StudentService.SendStudentStream:input_type -> dineth.grpc.api.student.StudentRequest + 0, // 3: dineth.grpc.api.student.StudentService.SendAndGetStudentStream:input_type -> dineth.grpc.api.student.StudentRequest + 1, // 4: dineth.grpc.api.student.StudentService.GetStudent:output_type -> dineth.grpc.api.student.StudentResponse + 1, // 5: dineth.grpc.api.student.StudentService.GetStudentStream:output_type -> dineth.grpc.api.student.StudentResponse + 1, // 6: dineth.grpc.api.student.StudentService.SendStudentStream:output_type -> dineth.grpc.api.student.StudentResponse + 1, // 7: dineth.grpc.api.student.StudentService.SendAndGetStudentStream:output_type -> dineth.grpc.api.student.StudentResponse + 4, // [4:8] is the sub-list for method output_type + 0, // [0:4] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_student_default_version_proto_init() } +func file_student_default_version_proto_init() { + if File_student_default_version_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_student_default_version_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StudentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_student_default_version_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StudentResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_student_default_version_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_student_default_version_proto_goTypes, + DependencyIndexes: file_student_default_version_proto_depIdxs, + MessageInfos: file_student_default_version_proto_msgTypes, + }.Build() + File_student_default_version_proto = out.File + file_student_default_version_proto_rawDesc = nil + file_student_default_version_proto_goTypes = nil + file_student_default_version_proto_depIdxs = nil +} diff --git a/test/integration/integration/utils/grpc-code/student_default_version/student_default_version_grpc.pb.go b/test/integration/integration/utils/grpc-code/student_default_version/student_default_version_grpc.pb.go new file mode 100644 index 000000000..b3fe9b74b --- /dev/null +++ b/test/integration/integration/utils/grpc-code/student_default_version/student_default_version_grpc.pb.go @@ -0,0 +1,314 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.12.4 +// source: student_default_version.proto + +package student_default_version + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + StudentService_GetStudent_FullMethodName = "/dineth.grpc.api.student.StudentService/GetStudent" + StudentService_GetStudentStream_FullMethodName = "/dineth.grpc.api.student.StudentService/GetStudentStream" + StudentService_SendStudentStream_FullMethodName = "/dineth.grpc.api.student.StudentService/SendStudentStream" + StudentService_SendAndGetStudentStream_FullMethodName = "/dineth.grpc.api.student.StudentService/SendAndGetStudentStream" +) + +// StudentServiceClient is the client API for StudentService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type StudentServiceClient interface { + GetStudent(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (*StudentResponse, error) + GetStudentStream(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (StudentService_GetStudentStreamClient, error) + SendStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendStudentStreamClient, error) + SendAndGetStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendAndGetStudentStreamClient, error) +} + +type studentServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewStudentServiceClient(cc grpc.ClientConnInterface) StudentServiceClient { + return &studentServiceClient{cc} +} + +func (c *studentServiceClient) GetStudent(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (*StudentResponse, error) { + out := new(StudentResponse) + err := c.cc.Invoke(ctx, StudentService_GetStudent_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *studentServiceClient) GetStudentStream(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (StudentService_GetStudentStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &StudentService_ServiceDesc.Streams[0], StudentService_GetStudentStream_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &studentServiceGetStudentStreamClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type StudentService_GetStudentStreamClient interface { + Recv() (*StudentResponse, error) + grpc.ClientStream +} + +type studentServiceGetStudentStreamClient struct { + grpc.ClientStream +} + +func (x *studentServiceGetStudentStreamClient) Recv() (*StudentResponse, error) { + m := new(StudentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *studentServiceClient) SendStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendStudentStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &StudentService_ServiceDesc.Streams[1], StudentService_SendStudentStream_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &studentServiceSendStudentStreamClient{stream} + return x, nil +} + +type StudentService_SendStudentStreamClient interface { + Send(*StudentRequest) error + CloseAndRecv() (*StudentResponse, error) + grpc.ClientStream +} + +type studentServiceSendStudentStreamClient struct { + grpc.ClientStream +} + +func (x *studentServiceSendStudentStreamClient) Send(m *StudentRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *studentServiceSendStudentStreamClient) CloseAndRecv() (*StudentResponse, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(StudentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *studentServiceClient) SendAndGetStudentStream(ctx context.Context, opts ...grpc.CallOption) (StudentService_SendAndGetStudentStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &StudentService_ServiceDesc.Streams[2], StudentService_SendAndGetStudentStream_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &studentServiceSendAndGetStudentStreamClient{stream} + return x, nil +} + +type StudentService_SendAndGetStudentStreamClient interface { + Send(*StudentRequest) error + Recv() (*StudentResponse, error) + grpc.ClientStream +} + +type studentServiceSendAndGetStudentStreamClient struct { + grpc.ClientStream +} + +func (x *studentServiceSendAndGetStudentStreamClient) Send(m *StudentRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *studentServiceSendAndGetStudentStreamClient) Recv() (*StudentResponse, error) { + m := new(StudentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// StudentServiceServer is the server API for StudentService service. +// All implementations must embed UnimplementedStudentServiceServer +// for forward compatibility +type StudentServiceServer interface { + GetStudent(context.Context, *StudentRequest) (*StudentResponse, error) + GetStudentStream(*StudentRequest, StudentService_GetStudentStreamServer) error + SendStudentStream(StudentService_SendStudentStreamServer) error + SendAndGetStudentStream(StudentService_SendAndGetStudentStreamServer) error + mustEmbedUnimplementedStudentServiceServer() +} + +// UnimplementedStudentServiceServer must be embedded to have forward compatible implementations. +type UnimplementedStudentServiceServer struct { +} + +func (UnimplementedStudentServiceServer) GetStudent(context.Context, *StudentRequest) (*StudentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStudent not implemented") +} +func (UnimplementedStudentServiceServer) GetStudentStream(*StudentRequest, StudentService_GetStudentStreamServer) error { + return status.Errorf(codes.Unimplemented, "method GetStudentStream not implemented") +} +func (UnimplementedStudentServiceServer) SendStudentStream(StudentService_SendStudentStreamServer) error { + return status.Errorf(codes.Unimplemented, "method SendStudentStream not implemented") +} +func (UnimplementedStudentServiceServer) SendAndGetStudentStream(StudentService_SendAndGetStudentStreamServer) error { + return status.Errorf(codes.Unimplemented, "method SendAndGetStudentStream not implemented") +} +func (UnimplementedStudentServiceServer) mustEmbedUnimplementedStudentServiceServer() {} + +// UnsafeStudentServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StudentServiceServer will +// result in compilation errors. +type UnsafeStudentServiceServer interface { + mustEmbedUnimplementedStudentServiceServer() +} + +func RegisterStudentServiceServer(s grpc.ServiceRegistrar, srv StudentServiceServer) { + s.RegisterService(&StudentService_ServiceDesc, srv) +} + +func _StudentService_GetStudent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StudentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StudentServiceServer).GetStudent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StudentService_GetStudent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StudentServiceServer).GetStudent(ctx, req.(*StudentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StudentService_GetStudentStream_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(StudentRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StudentServiceServer).GetStudentStream(m, &studentServiceGetStudentStreamServer{stream}) +} + +type StudentService_GetStudentStreamServer interface { + Send(*StudentResponse) error + grpc.ServerStream +} + +type studentServiceGetStudentStreamServer struct { + grpc.ServerStream +} + +func (x *studentServiceGetStudentStreamServer) Send(m *StudentResponse) error { + return x.ServerStream.SendMsg(m) +} + +func _StudentService_SendStudentStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StudentServiceServer).SendStudentStream(&studentServiceSendStudentStreamServer{stream}) +} + +type StudentService_SendStudentStreamServer interface { + SendAndClose(*StudentResponse) error + Recv() (*StudentRequest, error) + grpc.ServerStream +} + +type studentServiceSendStudentStreamServer struct { + grpc.ServerStream +} + +func (x *studentServiceSendStudentStreamServer) SendAndClose(m *StudentResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *studentServiceSendStudentStreamServer) Recv() (*StudentRequest, error) { + m := new(StudentRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _StudentService_SendAndGetStudentStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StudentServiceServer).SendAndGetStudentStream(&studentServiceSendAndGetStudentStreamServer{stream}) +} + +type StudentService_SendAndGetStudentStreamServer interface { + Send(*StudentResponse) error + Recv() (*StudentRequest, error) + grpc.ServerStream +} + +type studentServiceSendAndGetStudentStreamServer struct { + grpc.ServerStream +} + +func (x *studentServiceSendAndGetStudentStreamServer) Send(m *StudentResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *studentServiceSendAndGetStudentStreamServer) Recv() (*StudentRequest, error) { + m := new(StudentRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// StudentService_ServiceDesc is the grpc.ServiceDesc for StudentService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StudentService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "dineth.grpc.api.student.StudentService", + HandlerType: (*StudentServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetStudent", + Handler: _StudentService_GetStudent_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "GetStudentStream", + Handler: _StudentService_GetStudentStream_Handler, + ServerStreams: true, + }, + { + StreamName: "SendStudentStream", + Handler: _StudentService_SendStudentStream_Handler, + ClientStreams: true, + }, + { + StreamName: "SendAndGetStudentStream", + Handler: _StudentService_SendAndGetStudentStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "student_default_version.proto", +} diff --git a/test/integration/integration/utils/grpcutils/helpers.go b/test/integration/integration/utils/grpcutils/helpers.go new file mode 100644 index 000000000..66d339215 --- /dev/null +++ b/test/integration/integration/utils/grpcutils/helpers.go @@ -0,0 +1,90 @@ +package grpcutils + +import ( + "crypto/tls" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "testing" + "time" +) + +type Request struct { + Host string + Headers map[string]string +} +type ClientCreator[T any] func(conn *grpc.ClientConn) T +type ExpectedResponse struct { + Out any + Err error +} + +type GRPCTestCase struct { + Request Request + ExpectedResponse ExpectedResponse + ActualResponse any + Name string + Method func(conn *grpc.ClientConn) (any, error) + Satisfier ResponseSatisfier +} +type ResponseSatisfier interface { + IsSatisfactory(response interface{}, expectedResponse ExpectedResponse) bool +} + +func DialGRPCServer(gwAddr string, t *testing.T) (*grpc.ClientConn, error) { + // Set up a connection to the server. + t.Logf("Dialing gRPC server at %s...", gwAddr) + creds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true}) + conn, err := grpc.Dial(gwAddr, grpc.WithTransportCredentials(creds)) + if err != nil { + t.Fatalf("Could not connect to the server: %v", err) + } + return conn, nil +} +func InvokeGRPCClientUntilSatisfied(gwAddr string, t *testing.T, testCase GRPCTestCase, satisfier ResponseSatisfier, fn ExecuteClientCall) { + //(delay to allow CRs to be applied) + time.Sleep(5 * time.Second) + + var out any + var err error + attempt := 0 + maxAttempts := 4 + expected := testCase.ExpectedResponse + timeoutDuration := 50 * time.Second + for attempt < maxAttempts { + t.Logf("Attempt %d to invoke gRPC client...", attempt+1) + out, err = InvokeGRPCClient(gwAddr, t, fn) + + if err != nil { + t.Logf("Error on attempt %d: %v", attempt+1, err) + } else { + if satisfier.IsSatisfactory(out, expected) { + return + } + } + + if attempt < maxAttempts-1 { + t.Logf("Waiting %s seconds before next attempt...", timeoutDuration) + time.Sleep(timeoutDuration) + } + attempt++ + } + + t.Logf("Failed to receive a satisfactory response after %d attempts", maxAttempts) + t.Fail() +} + +type ExecuteClientCall func(conn *grpc.ClientConn) (any, error) + +func InvokeGRPCClient(gwAddr string, t *testing.T, fn ExecuteClientCall) (any, error) { + + conn, err := DialGRPCServer(gwAddr, t) + if err != nil { + t.Fatalf("Could not connect to the server: %v", err) + } + + response, err := fn(conn) + if err != nil { + return nil, err + } + return response, nil +} diff --git a/test/integration/scripts/run-tests.sh b/test/integration/scripts/run-tests.sh index 7a50bd056..ecdd329ac 100644 --- a/test/integration/scripts/run-tests.sh +++ b/test/integration/scripts/run-tests.sh @@ -79,6 +79,7 @@ sudo echo "$IP ratelimit-priority.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP different-endpoint-with-same-route.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP custom-auth-header.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP gql.test.gw.wso2.com" | sudo tee -a /etc/hosts +sudo echo "$IP grpc.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP api-level-jwt.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP resource-level-jwt.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "255.255.255.255 broadcasthost" | sudo tee -a /etc/hosts diff --git a/test/integration/scripts/setup-hosts.sh b/test/integration/scripts/setup-hosts.sh index 7ff4ff8af..ec36022eb 100644 --- a/test/integration/scripts/setup-hosts.sh +++ b/test/integration/scripts/setup-hosts.sh @@ -38,6 +38,7 @@ sudo echo "$IP ratelimit-priority.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP different-endpoint-with-same-route.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP custom-auth-header.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP gql.test.gw.wso2.com" | sudo tee -a /etc/hosts +sudo echo "$IP grpc.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP api-level-jwt.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "$IP resource-level-jwt.test.gw.wso2.com" | sudo tee -a /etc/hosts sudo echo "255.255.255.255 broadcasthost" | sudo tee -a /etc/hosts