From 2706e381573c1faf32733a1b88c2aa86d7f4b2c5 Mon Sep 17 00:00:00 2001 From: AmaliMatharaarachchi Date: Mon, 22 Jan 2024 12:05:03 +0530 Subject: [PATCH] improve adapter code --- adapter/go.mod | 4 - adapter/go.sum | 20 -- .../envoyconf/routes_with_clusters.go | 2 +- .../envoyconf/routes_with_clusters_test.go | 185 ------------------ .../oasparser/model/adapter_internal_api.go | 23 ++- .../internal/oasparser/model/api_operation.go | 147 +------------- .../internal/oasparser/model/http_route.go | 16 +- .../operator/controllers/dp/api_controller.go | 48 ++--- adapter/internal/operator/operator.go | 2 +- .../operator/synchronizer/synchronizer.go | 176 ++++++----------- 10 files changed, 111 insertions(+), 512 deletions(-) diff --git a/adapter/go.mod b/adapter/go.mod index cc70f65ac..a7a8639b8 100644 --- a/adapter/go.mod +++ b/adapter/go.mod @@ -45,14 +45,12 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/invopop/yaml v0.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -93,9 +91,7 @@ replace github.com/wso2/apk/adapter => ../adapter replace github.com/wso2/apk/common-go-libs => ../common-go-libs require ( - github.com/getkin/kin-openapi v0.107.0 github.com/ghodss/yaml v1.0.0 - github.com/go-openapi/spec v0.20.7 github.com/stretchr/testify v1.8.4 golang.org/x/sys v0.15.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 diff --git a/adapter/go.sum b/adapter/go.sum index 8f0313848..bb2d67ed1 100644 --- a/adapter/go.sum +++ b/adapter/go.sum @@ -44,8 +44,6 @@ github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/getkin/kin-openapi v0.107.0 h1:bxhL6QArW7BXQj8NjXfIJQy680NsMKd25nwhvpCXchg= -github.com/getkin/kin-openapi v0.107.0/go.mod h1:9Dhr+FasATJZjS4iOLvB0hkaxgYdulrNYm2e9epLWOo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -53,17 +51,10 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI= -github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -103,12 +94,9 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc= -github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -124,9 +112,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= @@ -136,11 +121,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= @@ -305,7 +287,6 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -319,7 +300,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/adapter/internal/oasparser/envoyconf/routes_with_clusters.go b/adapter/internal/oasparser/envoyconf/routes_with_clusters.go index aa24bf639..379ba81c9 100644 --- a/adapter/internal/oasparser/envoyconf/routes_with_clusters.go +++ b/adapter/internal/oasparser/envoyconf/routes_with_clusters.go @@ -838,7 +838,7 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error rateLimitPolicyLevel = RateLimitPolicyAPILevel } else { for _, operation := range resource.GetMethod() { - if operation.RateLimitPolicy != nil { + if operation.GetRateLimitPolicy() != nil { rateLimitPolicyLevel = RateLimitPolicyOperationLevel basePathForRLService += resourcePath break diff --git a/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go b/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go index 0d473692d..a341222ec 100644 --- a/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go +++ b/adapter/internal/oasparser/envoyconf/routes_with_clusters_test.go @@ -531,93 +531,6 @@ func createDefaultBackendRef(backendName string) gwapiv1b1.HTTPBackendRef { } } -// func testCreateRoutesWithClustersWebsocket(t *testing.T, apiYamlFilePath string) { -// // If the asyncAPI definition contains the production and sandbox endpoints, they are prioritized over -// // the api.yaml. If the asyncAPI definition does not have any of them, api.yaml's value is assigned. -// apiYamlByteArr, err := ioutil.ReadFile(apiYamlFilePath) -// assert.Nil(t, err, "Error while reading the api.yaml file : %v"+apiYamlFilePath) -// apiYaml, err := model.NewAPIYaml(apiYamlByteArr) -// assert.Nil(t, err, "Error occurred while processing api.yaml") -// var adapterInternalAPI model.AdapterInternalAPI -// err = adapterInternalAPI.PopulateFromAPIYaml(apiYaml) - -// asyncapiFilePath := config.GetApkHome() + "/../adapter/test-resources/envoycodegen/asyncapi_websocket.yaml" -// asyncapiByteArr, err := ioutil.ReadFile(asyncapiFilePath) -// assert.Nil(t, err, "Error while reading file : %v"+asyncapiFilePath) -// apiJsn, conversionErr := utils.ToJSON(asyncapiByteArr) -// assert.Nil(t, conversionErr, "YAML to JSON conversion error : %v"+asyncapiFilePath) - -// var asyncapi model.AsyncAPI -// err = json.Unmarshal(apiJsn, &asyncapi) -// assert.Nil(t, err, "Error occurred while parsing asyncapi_websocket.yaml") - -// err = adapterInternalAPI.SetInfoAsyncAPI(asyncapi) -// assert.Nil(t, err, "Error while populating the AdapterInternalAPI object for web socket APIs") -// routes, clusters, _, _ := envoy.CreateRoutesWithClusters(adapterInternalAPI, nil, nil, "localhost", "carbon.super") - -// if strings.HasSuffix(apiYamlFilePath, "api.yaml") { -// assert.Equal(t, len(clusters), 2, "Number of clusters created incorrect") -// productionCluster := clusters[0] -// sandBoxCluster := clusters[1] -// assert.Equal(t, productionCluster.GetName(), "carbon.super_clusterProd_localhost_EchoWebSocket1.0", "Production cluster name mismatch") -// assert.Equal(t, sandBoxCluster.GetName(), "carbon.super_clusterSand_localhost_EchoWebSocket1.0", "Sandbox cluster name mismatch") - -// productionClusterHost := productionCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// productionClusterPort := productionCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() - -// assert.Equal(t, productionClusterHost, "ws.ifelse.io", "Production cluster host mismatch") -// assert.Equal(t, productionClusterPort, uint32(443), "Production cluster port mismatch") - -// sandBoxClusterHost := sandBoxCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// sandBoxClusterPort := sandBoxCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() - -// assert.Equal(t, sandBoxClusterHost, "echo.websocket.org", "Sandbox cluster host mismatch") -// assert.Equal(t, sandBoxClusterPort, uint32(80), "Sandbox cluster port mismatch") - -// assert.Equal(t, 2, len(routes), "Number of routes incorrect") - -// route := routes[0].GetMatch().GetSafeRegex().Regex -// assert.Equal(t, "^/echowebsocket/1.0/notifications[/]{0,1}", route, "route created mismatch") - -// throttlingPolicy := adapterInternalAPI.GetXWso2ThrottlingTier() -// assert.Equal(t, throttlingPolicy, "5PerMin", "API throttling policy is not assigned.") -// } -// if strings.HasSuffix(apiYamlFilePath, "api_prod.yaml") { -// assert.Equal(t, len(clusters), 1, "Number of clusters created incorrect") -// productionCluster := clusters[0] -// assert.Equal(t, productionCluster.GetName(), "carbon.super_clusterProd_localhost_prodws1.0", "Production cluster name mismatch") - -// productionClusterHost := productionCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// productionClusterPort := productionCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() - -// assert.Equal(t, productionClusterHost, "ws.ifelse.io", "Production cluster host mismatch") -// assert.Equal(t, productionClusterPort, uint32(443), "Production cluster port mismatch") - -// assert.Equal(t, 2, len(routes), "Number of routes incorrect") - -// route := routes[0].GetMatch().GetSafeRegex().Regex -// assert.Equal(t, route, "^/echowebsocketprod/1.0/notifications[/]{0,1}", "route created mismatch") - -// // TODO: (VirajSalaka) add Unit test for second resource too. -// route2 := routes[1].GetMatch().GetSafeRegex().Regex -// assert.Equal(t, route2, "^/echowebsocketprod/1.0/rooms/([^/]+)[/]{0,1}", "route created mismatch") - -// } -// if strings.HasSuffix(apiYamlFilePath, "api_sand.yaml") { -// assert.Equal(t, len(clusters), 2, "Number of clusters created incorrect") -// sandBoxCluster := clusters[1] -// assert.Equal(t, sandBoxCluster.GetName(), "carbon.super_clusterSand_localhost_sandbox1.0", "Sandbox cluster name mismatch") - -// sandBoxClusterHost := sandBoxCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// sandBoxClusterPort := sandBoxCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() - -// assert.Equal(t, sandBoxClusterHost, "echo.websocket.org", "Production cluster host mismatch") -// assert.Equal(t, sandBoxClusterPort, uint32(80), "Production cluster port mismatch") - -// } - -// } - func TestCreateHealthEndpoint(t *testing.T) { route := envoy.CreateHealthEndpoint() assert.NotNil(t, route, "Health Endpoint Route should not be null.") @@ -627,104 +540,6 @@ func TestCreateHealthEndpoint(t *testing.T) { assert.Equal(t, uint32(200), route.GetDirectResponse().GetStatus(), "Health response status is incorrect.") } -// // commonTestForClusterPriorities use to test loadbalance/failover in WS apis -// func commonTestForClusterPrioritiesInWebSocketAPI(t *testing.T, apiYamlFilePath string) { -// apiYamlByteArr, err := ioutil.ReadFile(apiYamlFilePath) -// assert.Nil(t, err, "Error while reading the api.yaml file : %v"+apiYamlFilePath) -// apiYaml, err := model.NewAPIYaml(apiYamlByteArr) -// assert.Nil(t, err, "Error occurred while processing api.yaml") -// var adapterInternalAPI model.AdapterInternalAPI -// err = adapterInternalAPI.PopulateFromAPIYaml(apiYaml) -// assert.Nil(t, err, "Error while populating the AdapterInternalAPI object for web socket APIs") -// _, clusters, _, _ := envoy.CreateRoutesWithClusters(adapterInternalAPI, nil, nil, "localhost", "carbon.super") - -// assert.Equal(t, len(clusters), 1, "Number of clusters created incorrect") -// productionCluster := clusters[0] -// sandBoxCluster := clusters[0] - -// productionClusterHost0 := productionCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// productionClusterPort0 := productionCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() -// productionClusterPriority0 := productionCluster.GetLoadAssignment().GetEndpoints()[0].Priority -// productionClusterHost1 := productionCluster.GetLoadAssignment().GetEndpoints()[1].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// productionClusterPort1 := productionCluster.GetLoadAssignment().GetEndpoints()[1].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() -// productionClusterPriority1 := productionCluster.GetLoadAssignment().GetEndpoints()[1].Priority - -// sandBoxClusterHost0 := sandBoxCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// sandBoxClusterPort0 := sandBoxCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() -// sandBoxClusterPriority0 := sandBoxCluster.GetLoadAssignment().GetEndpoints()[0].Priority -// sandBoxClusterHost1 := sandBoxCluster.GetLoadAssignment().GetEndpoints()[1].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetAddress() -// sandBoxClusterPort1 := sandBoxCluster.GetLoadAssignment().GetEndpoints()[1].GetLbEndpoints()[0].GetEndpoint().GetAddress().GetSocketAddress().GetPortValue() -// sandBoxClusterPriority1 := sandBoxCluster.GetLoadAssignment().GetEndpoints()[1].Priority - -// assert.Equal(t, "primary.websocket.org", productionClusterHost0, "Production endpoint host mismatch") -// assert.Equal(t, uint32(443), productionClusterPort0, "Production endpoint port mismatch") -// assert.Equal(t, uint32(0), productionClusterPriority0, "Production endpoint priority mismatch") - -// assert.Equal(t, "echo.websocket.org", productionClusterHost1, "Second production endpoint host mismatch") -// assert.Equal(t, uint32(80), productionClusterPort1, "Second production endpoint port mismatch") - -// assert.Equal(t, sandBoxClusterHost0, "primary.websocket.org", "Sandbox cluster host mismatch") -// assert.Equal(t, sandBoxClusterPort0, uint32(443), "Sandbox cluster port mismatch") -// assert.Equal(t, uint32(0), sandBoxClusterPriority0, "Sandbox endpoint priority mismatch") - -// assert.Equal(t, sandBoxClusterHost1, "echo.websocket.org", "Sandbox cluster host mismatch") -// assert.Equal(t, sandBoxClusterPort1, uint32(80), "Second sandbox cluster port mismatch") - -// if strings.HasSuffix(apiYamlFilePath, "ws_api_loadbalance.yaml") { -// assert.Equal(t, uint32(0), productionClusterPriority1, "Second production endpoint port mismatch") -// assert.Equal(t, uint32(0), sandBoxClusterPriority1, "Second sandbox endpoint priority mismatch") -// } - -// if strings.HasSuffix(apiYamlFilePath, "ws_api_failover.yaml") { -// assert.Equal(t, uint32(1), productionClusterPriority1, "Second production endpoint port mismatch") -// assert.Equal(t, uint32(1), sandBoxClusterPriority1, "Second sandbox endpoint priority mismatch") -// } -// } - -// todo(amali) add a test similar to the below using crs -// func testCreateRoutesWithClustersAPIClusters(t *testing.T) { -// openapiFilePath := config.GetApkHome() + "/../adapter/test-resources/envoycodegen/openapi_prod_sand_clusters.yaml" -// openapiByteArr, err := ioutil.ReadFile(openapiFilePath) -// assert.Nil(t, err, "Error while reading the openapi file : "+openapiFilePath) -// adapterInternalAPIForOpenapi := model.AdapterInternalAPI{} -// err = adapterInternalAPIForOpenapi.GetAdapterInternalAPI(openapiByteArr) -// assert.Nil(t, err, "Error should not be present when openAPI definition is converted to a AdapterInternalAPI object") -// routes, clusters, _, _ := envoy.CreateRoutesWithClusters(adapterInternalAPIForOpenapi, nil, nil, "localhost", "carbon.super") - -// assert.Equal(t, 2, len(clusters), "Number of production clusters created is incorrect.") -// // As the first cluster is always related to API level cluster -// apiLevelCluster := clusters[0] -// assert.Equal(t, apiLevelCluster.GetName(), "carbon.super_clusterProd_localhost_SwaggerPetstore1.0.0", "API Level cluster name mismatch") - -// apiLevelClusterHost0 := apiLevelCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint(). -// GetAddress().GetSocketAddress().GetAddress() -// apiLevelClusterPort0 := apiLevelCluster.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint(). -// GetAddress().GetSocketAddress().GetPortValue() -// apiLevelClusterPriority0 := apiLevelCluster.GetLoadAssignment().GetEndpoints()[0].Priority - -// assert.NotEmpty(t, apiLevelClusterHost0, "API Level Cluster's assigned host should not be null") -// assert.Equal(t, "apiLevelProdEndpoint", apiLevelClusterHost0, "API Level Cluster's assigned host is incorrect.") -// assert.NotEmpty(t, apiLevelClusterPort0, "API Level Cluster's assigned port should not be null") -// assert.Equal(t, uint32(80), apiLevelClusterPort0, "API Level Cluster's assigned host is incorrect.") -// assert.Equal(t, uint32(0), apiLevelClusterPriority0, "API Level Cluster's assigned Priority is incorrect.") - -// resourceLevelCluster0 := clusters[1] -// assert.Contains(t, resourceLevelCluster0.GetName(), "carbon.super_clusterProd_localhost_SwaggerPetstore1.0.0_", "Resource Level cluster name mismatch") - -// resourceLevelClusterHost0 := resourceLevelCluster0.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint(). -// GetAddress().GetSocketAddress().GetAddress() -// resourceLevelClusterPort0 := resourceLevelCluster0.GetLoadAssignment().GetEndpoints()[0].GetLbEndpoints()[0].GetEndpoint(). -// GetAddress().GetSocketAddress().GetPortValue() -// resourceLevelClusterPriority0 := resourceLevelCluster0.GetLoadAssignment().GetEndpoints()[0].Priority - -// assert.NotEmpty(t, resourceLevelClusterHost0, "API Level Cluster's assigned host should not be null") -// assert.Equal(t, "resourceLevelProdEndpoint", resourceLevelClusterHost0, "API Level Cluster's assigned host is incorrect.") -// assert.Equal(t, uint32(443), resourceLevelClusterPort0, "API Level Cluster's assigned host is incorrect.") -// assert.Equal(t, uint32(0), resourceLevelClusterPriority0, "API Level Cluster's assigned Priority is incorrect.") - -// assert.Equal(t, 2, len(routes), "Number of routes created is incorrect") -// } - func TestCreateRoutesWithClustersDifferentBackendRefs(t *testing.T) { apiState := synchronizer.APIState{} apiDefinition := v1alpha2.API{ diff --git a/adapter/internal/oasparser/model/adapter_internal_api.go b/adapter/internal/oasparser/model/adapter_internal_api.go index 906f909bf..882226d31 100644 --- a/adapter/internal/oasparser/model/adapter_internal_api.go +++ b/adapter/internal/oasparser/model/adapter_internal_api.go @@ -29,7 +29,6 @@ import ( "github.com/wso2/apk/adapter/config" "github.com/wso2/apk/adapter/internal/interceptor" "github.com/wso2/apk/adapter/internal/loggers" - logger "github.com/wso2/apk/adapter/internal/loggers" "github.com/wso2/apk/adapter/internal/oasparser/constants" "github.com/wso2/apk/adapter/internal/operator/utils" dpv1alpha1 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1" @@ -444,13 +443,13 @@ func (adapterInternalAPI *AdapterInternalAPI) GetEnvironment() string { func (adapterInternalAPI *AdapterInternalAPI) Validate() error { for _, res := range adapterInternalAPI.resources { if res.endpoints == nil || len(res.endpoints.Endpoints) == 0 { - logger.LoggerOasparser.Errorf("No Endpoints are provided for the resources in %s:%s, API_UUID: %v", + loggers.LoggerOasparser.Errorf("No Endpoints are provided for the resources in %s:%s, API_UUID: %v", adapterInternalAPI.title, adapterInternalAPI.version, adapterInternalAPI.UUID) return errors.New("no endpoints are provided for the API") } err := res.endpoints.validateEndpointCluster() if err != nil { - logger.LoggerOasparser.Errorf("Error while parsing the endpoints of the API %s:%s - %v, API_UUID: %v", + loggers.LoggerOasparser.Errorf("Error while parsing the endpoints of the API %s:%s - %v, API_UUID: %v", adapterInternalAPI.title, adapterInternalAPI.version, err, adapterInternalAPI.UUID) return err } @@ -932,7 +931,7 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoGQLRouteCR(gqlRoute *dpv1al resourcePath := *match.Path resource := &Resource{path: resourcePath, methods: []*Operation{{iD: uuid.New().String(), method: string(*match.Type), policies: policies, - auth: apiAuth, RateLimitPolicy: parseRateLimitPolicyToInternal(resourceRatelimitPolicy), scopes: scopes}}, + auth: apiAuth, rateLimitPolicy: parseRateLimitPolicyToInternal(resourceRatelimitPolicy), scopes: scopes}}, iD: uuid.New().String(), } resources = append(resources, resource) @@ -981,7 +980,7 @@ func (retryConfig *RetryConfig) validateRetryConfig() { var validStatusCodes []uint32 for _, statusCode := range retryConfig.StatusCodes { if statusCode > 598 || statusCode < 401 { - logger.LoggerOasparser.Errorf("Given status code for the API retry config is invalid." + + loggers.LoggerOasparser.Errorf("Given status code for the API retry config is invalid." + "Must be in the range 401 - 598. Dropping the status code.") } else { validStatusCodes = append(validStatusCodes, statusCode) @@ -999,7 +998,7 @@ func (endpointCluster *EndpointCluster) validateEndpointCluster() error { for _, endpoint := range endpointCluster.Endpoints { err = endpoint.validateEndpoint() if err != nil { - logger.LoggerOasparser.Errorf("Error while parsing the endpoint. %v", err) + loggers.LoggerOasparser.Errorf("Error while parsing the endpoint. %v", err) return err } } @@ -1075,17 +1074,17 @@ func (adapterInternalAPI *AdapterInternalAPI) GetInterceptor(vendorExtensions ma serviceURLV := v.(string) endpoint, err := getHTTPEndpoint(serviceURLV) if err != nil { - logger.LoggerOasparser.Error("Error reading interceptors service url value", err) + loggers.LoggerOasparser.Error("Error reading interceptors service url value", err) return InterceptEndpoint{} } if endpoint.Basepath != "" { - logger.LoggerOasparser.Warnf("Interceptor serviceURL basepath is given as %v but it will be ignored", + loggers.LoggerOasparser.Warnf("Interceptor serviceURL basepath is given as %v but it will be ignored", endpoint.Basepath) } endpointCluster.Endpoints = []Endpoint{*endpoint} } else { - logger.LoggerOasparser.Error("Error reading interceptors service url value") + loggers.LoggerOasparser.Error("Error reading interceptors service url value") return InterceptEndpoint{} } //clusterTimeout optional @@ -1094,7 +1093,7 @@ func (adapterInternalAPI *AdapterInternalAPI) GetInterceptor(vendorExtensions ma if err == nil { clusterTimeoutV = time.Duration(p) } else { - logger.LoggerOasparser.Errorf("Error reading interceptors %v value : %v", constants.ClusterTimeout, err.Error()) + loggers.LoggerOasparser.Errorf("Error reading interceptors %v value : %v", constants.ClusterTimeout, err.Error()) } } //requestTimeout optional @@ -1103,7 +1102,7 @@ func (adapterInternalAPI *AdapterInternalAPI) GetInterceptor(vendorExtensions ma if err == nil { requestTimeoutV = time.Duration(p) } else { - logger.LoggerOasparser.Errorf("Error reading interceptors %v value : %v", constants.RequestTimeout, err.Error()) + loggers.LoggerOasparser.Errorf("Error reading interceptors %v value : %v", constants.RequestTimeout, err.Error()) } } //includes optional @@ -1125,7 +1124,7 @@ func (adapterInternalAPI *AdapterInternalAPI) GetInterceptor(vendorExtensions ma Level: level, } } - logger.LoggerOasparser.Error("Error parsing response interceptors values to adapterInternalAPI") + loggers.LoggerOasparser.Error("Error parsing response interceptors values to adapterInternalAPI") } return InterceptEndpoint{} } diff --git a/adapter/internal/oasparser/model/api_operation.go b/adapter/internal/oasparser/model/api_operation.go index 0841b1df4..a3d228544 100644 --- a/adapter/internal/oasparser/model/api_operation.go +++ b/adapter/internal/oasparser/model/api_operation.go @@ -20,14 +20,8 @@ package model import ( - "encoding/json" - "errors" - "regexp" - "strconv" "strings" - "github.com/getkin/kin-openapi/openapi3" - "github.com/go-openapi/spec" "github.com/google/uuid" "github.com/wso2/apk/adapter/config" "github.com/wso2/apk/adapter/internal/interceptor" @@ -48,8 +42,7 @@ type Operation struct { vendorExtensions map[string]interface{} policies OperationPolicies mockedAPIConfig *api.MockedApiConfig - //todo(amali) refactor all vars to private/public vars - RateLimitPolicy *RateLimitPolicy + rateLimitPolicy *RateLimitPolicy } // Authentication holds authentication related configurations @@ -89,134 +82,6 @@ func (operation *Operation) GetAuthentication() *Authentication { return operation.auth } -// SetMockedAPIConfigOAS3 generate mock impl endpoint configurations -func (operation *Operation) SetMockedAPIConfigOAS3(openAPIOperation *openapi3.Operation) { - if len(openAPIOperation.Responses) > 0 { - mockedAPIConfig := &api.MockedApiConfig{ - Responses: make([]*api.MockedResponseConfig, 0), - } - for responseCode, responseRef := range openAPIOperation.Responses { - code := strings.ToLower(responseCode) - if matched, _ := regexp.MatchString("^[0-9x]*", code); (matched && len(code) == 3) || code == "default" { - mockedResponse := &api.MockedResponseConfig{ - Code: code, - Content: make([]*api.MockedContentConfig, 0), - } - if responseRef != nil && responseRef.Value != nil { - for mediaType, content := range responseRef.Value.Content { - example, err := convertToJSON(content.Example) - if err == nil { - mockedResponse.Content = append(mockedResponse.Content, &api.MockedContentConfig{ - ContentType: mediaType, - Examples: []*api.MockedContentExample{{Ref: "", Body: example}}, - }) - } else if len(content.Examples) > 0 { - mockedContentExamples := make([]*api.MockedContentExample, 0) - for ref, exampleVal := range content.Examples { - if exampleVal != nil && exampleVal.Value != nil { - example, err = convertToJSON(exampleVal.Value.Value) - if err == nil { - mockedContentExamples = append(mockedContentExamples, &api.MockedContentExample{ - Ref: ref, - Body: example, - }) - } - } - - } - mockedResponse.Content = append(mockedResponse.Content, - &api.MockedContentConfig{ - ContentType: mediaType, - Examples: mockedContentExamples, - }) - } - } - for headerName, headerValues := range responseRef.Value.Headers { - example, err := convertToJSON(headerValues.Value.Example) - if err == nil { - mockedResponse.Headers = append(mockedResponse.Headers, &api.MockedHeaderConfig{ - Name: headerName, - Value: example, - }) - } - } - } - if len(mockedResponse.Content) > 0 { - mockedAPIConfig.Responses = append(mockedAPIConfig.Responses, mockedResponse) - } - } - } - if len(mockedAPIConfig.Responses) > 0 { - operation.mockedAPIConfig = mockedAPIConfig - } - } -} - -// SetMockedAPIConfigOAS2 generate mock impl endpoint configurations -func (operation *Operation) SetMockedAPIConfigOAS2(openAPIOperation *spec.Operation) { - if openAPIOperation.Responses != nil && len(openAPIOperation.Responses.StatusCodeResponses) > 0 { - mockedAPIConfig := &api.MockedApiConfig{ - Responses: make([]*api.MockedResponseConfig, 0), - } - // get response codes - for responseCode, responseRef := range openAPIOperation.Responses.StatusCodeResponses { - mockedResponse := &api.MockedResponseConfig{ - Code: strconv.Itoa(responseCode), - Content: make([]*api.MockedContentConfig, 0), - } - for mediaType, content := range responseRef.ResponseProps.Examples { - //todo(amali) xml payload gen - example, err := convertToJSON(content) - if err == nil { - mockedResponse.Content = append(mockedResponse.Content, &api.MockedContentConfig{ - ContentType: mediaType, - Examples: []*api.MockedContentExample{{Ref: "", Body: example}}, - }) - } - } - // swagger does not support header example/examples - if len(mockedResponse.Content) > 0 { - mockedAPIConfig.Responses = append(mockedAPIConfig.Responses, mockedResponse) - } - } - // get default response examples - if openAPIOperation.Responses.Default != nil && len(openAPIOperation.Responses.Default.Examples) > 0 { - mockedResponse := &api.MockedResponseConfig{ - Code: "default", - Content: make([]*api.MockedContentConfig, 0), - } - for mediaType, content := range openAPIOperation.Responses.Default.Examples { - example, err := convertToJSON(content) - if err == nil { - mockedResponse.Content = append(mockedResponse.Content, &api.MockedContentConfig{ - ContentType: mediaType, - Examples: []*api.MockedContentExample{{Ref: "", Body: example}}, - }) - } - } - // swagger does not support header example/examples - if len(mockedResponse.Content) > 0 { - mockedAPIConfig.Responses = append(mockedAPIConfig.Responses, mockedResponse) - } - } - if len(mockedAPIConfig.Responses) > 0 { - operation.mockedAPIConfig = mockedAPIConfig - } - } -} - -// convertToJSON parse interface to JSON string. returns error if a null value has passed -func convertToJSON(data interface{}) (string, error) { - if data != nil { - b, err := json.Marshal(data) - if err != nil { - return "", err - } - return string(b), nil - } - return "", errors.New("null object passed") -} - // GetMethod returns the http method name of the give API operation func (operation *Operation) GetMethod() string { return operation.method @@ -227,16 +92,16 @@ func (operation *Operation) GetPolicies() *OperationPolicies { return &operation.policies } +// GetRateLimitPolicy returns the operation level throttling policy +func (operation *Operation) GetRateLimitPolicy() *RateLimitPolicy { + return operation.rateLimitPolicy +} + // GetScopes returns the security schemas defined for the http opeartion func (operation *Operation) GetScopes() []string { return operation.scopes } -// SetScopes sets the security schemas for the http opeartion -func (operation *Operation) SetScopes(scopes []string) { - operation.scopes = scopes -} - // GetTier returns the operation level throttling tier func (operation *Operation) GetTier() string { return operation.tier diff --git a/adapter/internal/oasparser/model/http_route.go b/adapter/internal/oasparser/model/http_route.go index c62ededd5..11fb078d7 100644 --- a/adapter/internal/oasparser/model/http_route.go +++ b/adapter/internal/oasparser/model/http_route.go @@ -274,22 +274,22 @@ func getAllowedOperations(httpMethod *gwapiv1b1.HTTPMethod, policies OperationPo ratelimitPolicy *RateLimitPolicy, scopes []string) []*Operation { if httpMethod != nil { return []*Operation{{iD: uuid.New().String(), method: string(*httpMethod), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}} + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}} } return []*Operation{{iD: uuid.New().String(), method: string(gwapiv1b1.HTTPMethodGet), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}, + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}, {iD: uuid.New().String(), method: string(gwapiv1b1.HTTPMethodPost), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}, + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}, {iD: uuid.New().String(), method: string(gwapiv1b1.HTTPMethodDelete), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}, + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}, {iD: uuid.New().String(), method: string(gwapiv1b1.HTTPMethodPatch), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}, + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}, {iD: uuid.New().String(), method: string(gwapiv1b1.HTTPMethodPut), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}, + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}, {iD: uuid.New().String(), method: string(gwapiv1b1.HTTPMethodHead), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}, + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}, {iD: uuid.New().String(), method: string(gwapiv1b1.HTTPMethodOptions), policies: policies, - auth: auth, RateLimitPolicy: ratelimitPolicy, scopes: scopes}} + auth: auth, rateLimitPolicy: ratelimitPolicy, scopes: scopes}} } // SetInfoAPICR populates ID, ApiType, Version and XWso2BasePath of adapterInternalAPI. diff --git a/adapter/internal/operator/controllers/dp/api_controller.go b/adapter/internal/operator/controllers/dp/api_controller.go index 9de15fcec..bc5f93a8c 100644 --- a/adapter/internal/operator/controllers/dp/api_controller.go +++ b/adapter/internal/operator/controllers/dp/api_controller.go @@ -91,7 +91,7 @@ var ( type APIReconciler struct { client k8client.Client ods *synchronizer.OperatorDataStore - ch *chan synchronizer.APIEvent + ch *chan *synchronizer.APIEvent successChannel *chan synchronizer.SuccessEvent statusUpdater *status.UpdateHandler mgr manager.Manager @@ -99,7 +99,7 @@ type APIReconciler struct { // NewAPIController creates a new API controller instance. API Controllers watches for dpv1alpha2.API and gwapiv1b1.HTTPRoute. func NewAPIController(mgr manager.Manager, operatorDataStore *synchronizer.OperatorDataStore, statusUpdater *status.UpdateHandler, - ch *chan synchronizer.APIEvent, successChannel *chan synchronizer.SuccessEvent) error { + ch *chan *synchronizer.APIEvent, successChannel *chan synchronizer.SuccessEvent) error { apiReconciler := &APIReconciler{ client: mgr.GetClient(), ods: operatorDataStore, @@ -245,7 +245,7 @@ func (apiReconciler *APIReconciler) Reconcile(ctx context.Context, req ctrl.Requ apiReconciler.ods.DeleteCachedAPI(req.NamespacedName) loggers.LoggerAPKOperator.Infof("Delete event received for API : %s with API UUID : %v, hence deleted from API cache", req.NamespacedName.String(), string(apiCR.ObjectMeta.UID)) - *apiReconciler.ch <- synchronizer.APIEvent{EventType: constants.Delete, Events: []synchronizer.APIState{apiState}} + *apiReconciler.ch <- &synchronizer.APIEvent{EventType: constants.Delete, Events: []synchronizer.APIState{apiState}} return ctrl.Result{}, nil } loggers.LoggerAPKOperator.Warnf("Api CR related to the reconcile request with key: %s returned error. Assuming API with API UUID : %v is already deleted, hence ignoring the error : %v", @@ -260,7 +260,7 @@ func (apiReconciler *APIReconciler) Reconcile(ctx context.Context, req ctrl.Requ } else if apiState != nil { loggers.LoggerAPKOperator.Infof("Ready to deploy CRs for API in namespace : %s with API UUID : %v, %v", req.NamespacedName.String(), string(apiCR.ObjectMeta.UID), err) - *apiReconciler.ch <- *apiState + *apiReconciler.ch <- apiState } return ctrl.Result{}, nil } @@ -287,7 +287,7 @@ func (apiReconciler *APIReconciler) applyStartupAPIs() { } // Send all the API events to the channel if len(combinedapiEvent.Events) > 0 { - *apiReconciler.ch <- *combinedapiEvent + *apiReconciler.ch <- combinedapiEvent loggers.LoggerAPKOperator.Info("Initial APIs were reconciled successfully") } else { loggers.LoggerAPKOperator.Warn("No startup APIs found") @@ -1544,7 +1544,6 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.API{}, configMapAPIDefinition, func(rawObj k8client.Object) []string { - loggers.LoggerAPI.Error("AMALIII configMapAPIDefinition: ", configMapAPIDefinition) api := rawObj.(*dpv1alpha2.API) var configMaps []string if api.Spec.DefinitionFileRef != "" { @@ -1554,7 +1553,6 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { Namespace: api.Namespace, }.String()) } - loggers.LoggerAPI.Error("AMALIII configMaps: ", configMaps) return configMaps }); err != nil { return err @@ -1991,23 +1989,25 @@ func (apiReconciler *APIReconciler) handleStatus() { timeNow := metav1.Now() event = fmt.Sprintf("[%s] %s", timeNow.String(), message) - apiReconciler.statusUpdater.Send(status.Update{ - NamespacedName: successEvent.APINamespacedName, - Resource: new(dpv1alpha2.API), - UpdateStatus: func(obj k8client.Object) k8client.Object { - h, ok := obj.(*dpv1alpha2.API) - if !ok { - loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2626, logging.BLOCKER, "Unsupported object type %T", obj)) - } - hCopy := h.DeepCopy() - hCopy.Status.DeploymentStatus.Status = successEvent.State - hCopy.Status.DeploymentStatus.Accepted = accept - hCopy.Status.DeploymentStatus.Message = message - hCopy.Status.DeploymentStatus.Events = append(hCopy.Status.DeploymentStatus.Events, event) - hCopy.Status.DeploymentStatus.TransitionTime = &timeNow - return hCopy - }, - }) + for _, apiName := range successEvent.APINamespacedName { // handle startup multiple apis + apiReconciler.statusUpdater.Send(status.Update{ + NamespacedName: apiName, + Resource: new(dpv1alpha2.API), + UpdateStatus: func(obj k8client.Object) k8client.Object { + h, ok := obj.(*dpv1alpha2.API) + if !ok { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2626, logging.BLOCKER, "Unsupported object type %T", obj)) + } + hCopy := h.DeepCopy() + hCopy.Status.DeploymentStatus.Status = successEvent.State + hCopy.Status.DeploymentStatus.Accepted = accept + hCopy.Status.DeploymentStatus.Message = message + hCopy.Status.DeploymentStatus.Events = append(hCopy.Status.DeploymentStatus.Events, event) + hCopy.Status.DeploymentStatus.TransitionTime = &timeNow + return hCopy + }, + }) + } } } diff --git a/adapter/internal/operator/operator.go b/adapter/internal/operator/operator.go index 4630190b4..c71286d07 100644 --- a/adapter/internal/operator/operator.go +++ b/adapter/internal/operator/operator.go @@ -110,7 +110,7 @@ func InitOperator() { } // TODO: Decide on a buffer size and add to config. - ch := make(chan synchronizer.APIEvent, 10) + ch := make(chan *synchronizer.APIEvent, 10) successChannel := make(chan synchronizer.SuccessEvent, 10) gatewaych := make(chan synchronizer.GatewayEvent, 10) diff --git a/adapter/internal/operator/synchronizer/synchronizer.go b/adapter/internal/operator/synchronizer/synchronizer.go index a97137065..3305399d5 100644 --- a/adapter/internal/operator/synchronizer/synchronizer.go +++ b/adapter/internal/operator/synchronizer/synchronizer.go @@ -32,6 +32,7 @@ import ( "github.com/wso2/apk/adapter/internal/loggers" "github.com/wso2/apk/adapter/internal/oasparser/model" "github.com/wso2/apk/adapter/internal/operator/constants" + "github.com/wso2/apk/adapter/internal/operator/utils" "github.com/wso2/apk/adapter/pkg/logging" "github.com/wso2/apk/adapter/pkg/utils/tlsutils" ) @@ -47,48 +48,60 @@ type APIEvent struct { // SuccessEvent holds the data structure used for aknowledgement of a successful API deployment type SuccessEvent struct { - APINamespacedName types.NamespacedName + // APINamespacedName updated api namespaced names + APINamespacedName []types.NamespacedName State string Events []string } +// PartitionEvent is the event sent to the partition server. +type PartitionEvent struct { + EventType string `json:"eventType"` + APIName string `json:"apiName"` + APIVersion string `json:"apiVersion"` + BasePath string `json:"basePath"` + Organization string `json:"organization"` + Partition string `json:"partition"` + APIUUID string `json:"apiId"` + Vhosts []string `json:"vhosts"` +} + var ( // TODO: Decide on a buffer size and add to config. - paritionCh chan APIEvent + paritionCh chan *APIEvent + // Runtime client connetion + partitionClient *http.Client ) func init() { if config.ReadConfigs().PartitionServer.Enabled { - paritionCh = make(chan APIEvent, 10) + paritionCh = make(chan *APIEvent, 10) } } // HandleAPILifeCycleEvents handles the API events generated from OperatorDataStore -func HandleAPILifeCycleEvents(ch *chan APIEvent, successChannel *chan SuccessEvent) { +func HandleAPILifeCycleEvents(ch *chan *APIEvent, successChannel *chan SuccessEvent) { loggers.LoggerAPKOperator.Info("Operator synchronizer listening for API lifecycle events...") for event := range *ch { var err error switch event.EventType { case constants.Delete: loggers.LoggerAPKOperator.Infof("Delete event received for %v", event.Events[0].APIDefinition.Name) - err = undeployAPIInGateway(event.Events[0]) + if err = undeployAPIInGateway(event); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2629, logging.CRITICAL, "API deployment failed for %s event : %v", event.EventType, err)) + } else { + if config.ReadConfigs().PartitionServer.Enabled { + paritionCh <- event + } + } case constants.Create: - deployMultipleAPIsInGateway(event.Events) + deployMultipleAPIsInGateway(event, successChannel) case constants.Update: - loggers.LoggerAPKOperator.Infof("Update event received for %v", event.Events[0].APIDefinition.Name) - err = deployAPIInGateway(event.Events[0]) + deployMultipleAPIsInGateway(event, successChannel) } if err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2629, logging.CRITICAL, "API deployment failed for %s event : %v", event.EventType, err)) } else if event.EventType != constants.Create { - // TODO(amali) commented out because there was no usage for this - // if event.EventType != constants.Delete && event.EventType != constants.Create { - // *successChannel <- SuccessEvent{ - // APINamespacedName: utils.NamespacedName(event.Events[0].APIDefinition), - // State: event.EventType, - // Events: event.UpdatedEvents, - // } - // } if config.ReadConfigs().PartitionServer.Enabled { paritionCh <- event } @@ -96,21 +109,30 @@ func HandleAPILifeCycleEvents(ch *chan APIEvent, successChannel *chan SuccessEve } } -func undeployAPIInGateway(apiState APIState) error { +func undeployAPIInGateway(apiEvent *APIEvent) error { + var err error + apiState := apiEvent.Events[0] if apiState.APIDefinition.Spec.APIType == "REST" { - return undeployRestAPIInGateway(apiState) + err = undeployRestAPIInGateway(apiState) } if apiState.APIDefinition.Spec.APIType == "GraphQL" { - return undeployGQLAPIInGateway(apiState) + err = undeployGQLAPIInGateway(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 } // deployMultipleAPIsInGateway deploys the related API in CREATE and UPDATE events. -func deployMultipleAPIsInGateway(apiStates []APIState) { +func deployMultipleAPIsInGateway(event *APIEvent, successChannel *chan SuccessEvent) { updatedLabelsMap := make(map[string]struct{}) - for _, apiState := range apiStates { - loggers.LoggerAPKOperator.Infof("Create event received for %v", apiState.APIDefinition.Name) + var updatedAPIs []types.NamespacedName + for i, apiState := range event.Events { + loggers.LoggerAPKOperator.Infof("%s event received for %s", event.EventType, apiState.APIDefinition.Name) if len(apiState.OldOrganizationID) != 0 { xds.RemoveAPIFromOrgAPIMap(string((*apiState.APIDefinition).ObjectMeta.UID), apiState.OldOrganizationID) } @@ -133,6 +155,8 @@ func deployMultipleAPIsInGateway(apiStates []APIState) { "Error deploying prod httpRoute of API : %v in Organization %v from environments %v. Error: %v", string(apiState.APIDefinition.Spec.APIName), apiState.APIDefinition.Spec.Organization, getLabelsForAPI(apiState.ProdHTTPRoute.HTTPRouteCombined), err)) + // removing failed updates from the events list because this will be sent to partition server + event.Events = append(event.Events[:i], event.Events[i+1:]...) continue } for label := range updatedLabels { @@ -147,6 +171,8 @@ func deployMultipleAPIsInGateway(apiStates []APIState) { "Error deploying sand httpRoute of API : %v in Organization %v from environments %v. Error: %v", string(apiState.APIDefinition.Spec.APIName), apiState.APIDefinition.Spec.Organization, getLabelsForAPI(apiState.ProdHTTPRoute.HTTPRouteCombined), err)) + // removing failed updates from the events list because this will be sent to partition server + event.Events = append(event.Events[:i], event.Events[i+1:]...) continue } for label := range updatedLabels { @@ -193,95 +219,25 @@ func deployMultipleAPIsInGateway(apiStates []APIState) { } } } - if config.ReadConfigs().PartitionServer.Enabled { - apiEvent := APIEvent{ - EventType: constants.Create, - Events: []APIState{apiState}, - UpdatedEvents: []string{}, - } - paritionCh <- apiEvent - } - } - //TODO(amali) only update status if this is successful - xds.UpdateXdsCacheOnAPIChange(updatedLabelsMap) -} - -// deployAPIInGateway deploys the related API in CREATE and UPDATE events. -func deployAPIInGateway(apiState APIState) error { - updatedLabelsMap := make(map[string]struct{}) - if len(apiState.OldOrganizationID) != 0 { - xds.RemoveAPIFromOrgAPIMap(string((*apiState.APIDefinition).ObjectMeta.UID), apiState.OldOrganizationID) + updatedAPIs = append(updatedAPIs, utils.NamespacedName(apiState.APIDefinition)) } - if apiState.APIDefinition.Spec.APIType == "REST" { - if apiState.ProdHTTPRoute == nil { - var adapterInternalAPI model.AdapterInternalAPI - adapterInternalAPI.SetInfoAPICR(*apiState.APIDefinition) - xds.RemoveAPICacheForEnv(adapterInternalAPI, constants.Production) - } - if apiState.SandHTTPRoute == nil { - var adapterInternalAPI model.AdapterInternalAPI - adapterInternalAPI.SetInfoAPICR(*apiState.APIDefinition) - xds.RemoveAPICacheForEnv(adapterInternalAPI, constants.Sandbox) - } - if apiState.ProdHTTPRoute != nil { - _, updatedLabels, err := GenerateAdapterInternalAPI(apiState, apiState.ProdHTTPRoute, constants.Production) - if err != nil { - return err - } - for label := range updatedLabels { - updatedLabelsMap[label] = struct{}{} - } - } - - if apiState.SandHTTPRoute != nil { - _, updatedLabels, err := GenerateAdapterInternalAPI(apiState, apiState.SandHTTPRoute, constants.Sandbox) - if err != nil { - return err - } - for label := range updatedLabels { - updatedLabelsMap[label] = struct{}{} - } - } - } - if apiState.APIDefinition.Spec.APIType == "GraphQL" { - if apiState.ProdGQLRoute == nil { - var adapterInternalAPI model.AdapterInternalAPI - adapterInternalAPI.SetInfoAPICR(*apiState.APIDefinition) - xds.RemoveAPICacheForEnv(adapterInternalAPI, constants.Production) - } - if apiState.SandGQLRoute == nil { - var adapterInternalAPI model.AdapterInternalAPI - adapterInternalAPI.SetInfoAPICR(*apiState.APIDefinition) - xds.RemoveAPICacheForEnv(adapterInternalAPI, constants.Sandbox) + updated := xds.UpdateXdsCacheOnAPIChange(updatedLabelsMap) + if updated { + loggers.LoggerAPKOperator.Info("XDS cache updated for apis: %+v", updatedAPIs) + *successChannel <- SuccessEvent{ + APINamespacedName: updatedAPIs, + State: event.EventType, + Events: event.UpdatedEvents, } - if apiState.ProdGQLRoute != nil { - _, updatedLabels, err := generateGQLAdapterInternalAPI(apiState, apiState.ProdGQLRoute, constants.Production) - if err != nil { - return err - } - for label := range updatedLabels { - updatedLabelsMap[label] = struct{}{} - } - } - if apiState.SandGQLRoute != nil { - _, updatedLabels, err := generateGQLAdapterInternalAPI(apiState, apiState.SandGQLRoute, constants.Sandbox) - if err != nil { - return err - } - for label := range updatedLabels { - updatedLabelsMap[label] = struct{}{} - } + if config.ReadConfigs().PartitionServer.Enabled { + paritionCh <- event } + } else { + loggers.LoggerAPKOperator.Info("XDS cache not updated for APIs : %+v", updatedAPIs) } - - xds.UpdateXdsCacheOnAPIChange(updatedLabelsMap) - return nil } -// Runtime client connetion -var partitionClient *http.Client - func init() { conf := config.ReadConfigs() @@ -349,15 +305,3 @@ func SendEventToPartitionServer() { } } - -// PartitionEvent is the event sent to the partition server. -type PartitionEvent struct { - EventType string `json:"eventType"` - APIName string `json:"apiName"` - APIVersion string `json:"apiVersion"` - BasePath string `json:"basePath"` - Organization string `json:"organization"` - Partition string `json:"partition"` - APIUUID string `json:"apiId"` - Vhosts []string `json:"vhosts"` -}