From 77bbae890a087990c4a737f83d54a5185504cc1f Mon Sep 17 00:00:00 2001 From: lakshmimsft Date: Thu, 28 Sep 2023 00:09:18 -0700 Subject: [PATCH] update dsrp --- cmd/applications-rp/main.go | 2 + cmd/ucpd/ucp-self-hosted-dev.yaml | 2 +- deploy/Chart/templates/ucp/configmaps.yaml | 2 +- .../configSettings.md | 2 +- pkg/datastoresrp/setup/operations.go | 172 ++++++++++++++++++ pkg/datastoresrp/setup/setup.go | 167 +++++++++++++++++ pkg/datastoresrp/setup/setup_test.go | 147 +++++++++++++++ .../frontend/handler/getoperations.go | 160 ---------------- .../frontend/handler/getoperations_test.go | 2 +- .../frontend/handler/routes_test.go | 12 +- 10 files changed, 494 insertions(+), 174 deletions(-) create mode 100644 pkg/datastoresrp/setup/operations.go create mode 100644 pkg/datastoresrp/setup/setup.go create mode 100644 pkg/datastoresrp/setup/setup_test.go diff --git a/cmd/applications-rp/main.go b/cmd/applications-rp/main.go index 57b93a00a0..ce78da1417 100644 --- a/cmd/applications-rp/main.go +++ b/cmd/applications-rp/main.go @@ -45,6 +45,7 @@ import ( "github.com/radius-project/radius/pkg/ucp/ucplog" corerp_setup "github.com/radius-project/radius/pkg/corerp/setup" + dsrp_setup "github.com/radius-project/radius/pkg/datastoresrp/setup" ) const serviceName = "radius" @@ -187,6 +188,7 @@ func builders(options hostoptions.HostOptions) ([]builder.Builder, error) { return []builder.Builder{ corerp_setup.SetupNamespace(config).GenerateBuilder(), + dsrp_setup.SetupNamespace(config).GenerateBuilder(), // Add resource provider builders... }, nil } diff --git a/cmd/ucpd/ucp-self-hosted-dev.yaml b/cmd/ucpd/ucp-self-hosted-dev.yaml index 8e73d30861..0d8ffb5b51 100644 --- a/cmd/ucpd/ucp-self-hosted-dev.yaml +++ b/cmd/ucpd/ucp-self-hosted-dev.yaml @@ -41,7 +41,7 @@ planes: Applications.Core: "http://localhost:8080" Applications.Messaging: "http://localhost:8081" Applications.Dapr: "http://localhost:8081" - Applications.Datastores: "http://localhost:8081" + Applications.Datastores: "http://localhost:8080" Microsoft.Resources: "http://localhost:5017" kind: "UCPNative" diff --git a/deploy/Chart/templates/ucp/configmaps.yaml b/deploy/Chart/templates/ucp/configmaps.yaml index 95b27be087..c2d5f665ee 100644 --- a/deploy/Chart/templates/ucp/configmaps.yaml +++ b/deploy/Chart/templates/ucp/configmaps.yaml @@ -36,7 +36,7 @@ data: resourceProviders: Applications.Core: "http://applications-rp.radius-system:5443" Applications.Dapr: "http://applications-rp.radius-system:5444" - Applications.Datastores: "http://applications-rp.radius-system:5444" + Applications.Datastores: "http://applications-rp.radius-system:5443" Applications.Messaging: "http://applications-rp.radius-system:5444" Microsoft.Resources: "http://bicep-de.radius-system:6443" kind: "UCPNative" diff --git a/docs/contributing/contributing-code/contributing-code-control-plane/configSettings.md b/docs/contributing/contributing-code/contributing-code-control-plane/configSettings.md index 2043051d22..9e3824fb2e 100644 --- a/docs/contributing/contributing-code/contributing-code-control-plane/configSettings.md +++ b/docs/contributing/contributing-code/contributing-code-control-plane/configSettings.md @@ -231,7 +231,7 @@ planes: resourceProviders: Applications.Core: "http://applications-rp.radius-system:5443" Applications.Dapr: "http://applications-rp.radius-system:5444" - Applications.Datastores: "http://applications-rp.radius-system:5444" + Applications.Datastores: "http://applications-rp.radius-system:5443" Applications.Messaging: "http://applications-rp.radius-system:5444" Microsoft.Resources: "http://bicep-de.radius-system:6443" kind: "UCPNative" diff --git a/pkg/datastoresrp/setup/operations.go b/pkg/datastoresrp/setup/operations.go new file mode 100644 index 0000000000..91e91b5d91 --- /dev/null +++ b/pkg/datastoresrp/setup/operations.go @@ -0,0 +1,172 @@ +/* +Copyright 2023 The Radius Authors. + +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 setup + +import v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" + +var operationList = []v1.Operation{ + { + Name: "Applications.Datastores/operations/read", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "operations", + Operation: "Get operations", + Description: "Get the list of operations", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/redisCaches/read", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "redisCaches", + Operation: "List redisCaches", + Description: "List Redis cache resource(s).", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/redisCaches/write", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "redisCaches", + Operation: "Create/Update redisCaches", + Description: "Create or update an Redis cache resource.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/redisCaches/delete", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "redisCaches", + Operation: "Delete redisCache", + Description: "Delete a Redis cache resource.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/redisCaches/getmetadata/action", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "redisCaches", + Operation: "Get recipe metadata", + Description: "Get recipe metadata.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/redisCaches/listsecrets/action", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "redisCaches", + Operation: "List secrets", + Description: "Lists Redis cache secrets.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/register/action", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "Applications.Datastores", + Operation: "Register Applications.Datastores", + Description: "Register the subscription for Applications.Datastores.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/unregister/action", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "Applications.Datastores", + Operation: "Unregister Applications.Datastores", + Description: "Unregister the subscription for Applications.Datastores.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/mongoDatabases/read", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "mongoDatabases", + Operation: "List mongoDatabases", + Description: "List Mongo database resource(s).", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/mongoDatabases/write", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "mongoDatabases", + Operation: "Create/Update mongoDatabases", + Description: "Create or update a Mongo database resource.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/mongoDatabases/delete", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "mongoDatabases", + Operation: "Delete mongoDatabases", + Description: "Delete a Mongo databases resource.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/mongoDatabases/listsecrets/action", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastore", + Resource: "mongoDatabases", + Operation: "List secrets", + Description: "List secret(s) of Mongo database resource.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/sqlDatabases/read", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "sqlDatabases", + Operation: "List sqlDatabases", + Description: "List SQL database resource(s).", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/sqlDatabases/write", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "sqlDatabases", + Operation: "Create/Update sqlDatabases", + Description: "Create or update a SQL database resource.", + }, + IsDataAction: false, + }, + { + Name: "Applications.Datastores/sqlDatabases/delete", + Display: &v1.OperationDisplayProperties{ + Provider: "Applications.Datastores", + Resource: "sqlDatabases", + Operation: "Delete sqlDatabases", + Description: "Delete a SQL database resource.", + }, + IsDataAction: false, + }, +} diff --git a/pkg/datastoresrp/setup/setup.go b/pkg/datastoresrp/setup/setup.go new file mode 100644 index 0000000000..bd869b371d --- /dev/null +++ b/pkg/datastoresrp/setup/setup.go @@ -0,0 +1,167 @@ +/* +Copyright 2023 The Radius Authors. + +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 setup + +import ( + "time" + + asyncctrl "github.com/radius-project/radius/pkg/armrpc/asyncoperation/controller" + "github.com/radius-project/radius/pkg/armrpc/builder" + apictrl "github.com/radius-project/radius/pkg/armrpc/frontend/controller" + "github.com/radius-project/radius/pkg/datastoresrp/datamodel" + "github.com/radius-project/radius/pkg/datastoresrp/datamodel/converter" + "github.com/radius-project/radius/pkg/recipes/controllerconfig" + + ds_ctrl "github.com/radius-project/radius/pkg/datastoresrp/frontend/controller" + mongo_ctrl "github.com/radius-project/radius/pkg/datastoresrp/frontend/controller/mongodatabases" + rds_ctrl "github.com/radius-project/radius/pkg/datastoresrp/frontend/controller/rediscaches" + sql_ctrl "github.com/radius-project/radius/pkg/datastoresrp/frontend/controller/sqldatabases" + mongo_proc "github.com/radius-project/radius/pkg/datastoresrp/processors/mongodatabases" + rds_proc "github.com/radius-project/radius/pkg/datastoresrp/processors/rediscaches" + sql_proc "github.com/radius-project/radius/pkg/datastoresrp/processors/sqldatabases" + pr_ctrl "github.com/radius-project/radius/pkg/portableresources/backend/controller" + rp_frontend "github.com/radius-project/radius/pkg/rp/frontend" +) + +const ( + // AsyncOperationRetryAfter is polling interval for async create/update or delete resource operations. + AsyncOperationRetryAfter = time.Duration(5) * time.Second +) + +// SetupNamespace builds the namespace for core resource provider. +func SetupNamespace(recipeControllerConfig *controllerconfig.RecipeControllerConfig) *builder.Namespace { + ns := builder.NewNamespace("Applications.Datastores") + + _ = ns.AddResource("redisCaches", &builder.ResourceOption[*datamodel.RedisCache, datamodel.RedisCache]{ + RequestConverter: converter.RedisCacheDataModelFromVersioned, + ResponseConverter: converter.RedisCacheDataModelToVersioned, + + Put: builder.Operation[datamodel.RedisCache]{ + UpdateFilters: []apictrl.UpdateFilter[datamodel.RedisCache]{ + rp_frontend.PrepareRadiusResource[*datamodel.RedisCache], + }, + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewCreateOrUpdateResource[*datamodel.RedisCache, datamodel.RedisCache](options, &rds_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateRedisCacheTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Patch: builder.Operation[datamodel.RedisCache]{ + UpdateFilters: []apictrl.UpdateFilter[datamodel.RedisCache]{ + rp_frontend.PrepareRadiusResource[*datamodel.RedisCache], + }, + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewCreateOrUpdateResource[*datamodel.RedisCache, datamodel.RedisCache](options, &rds_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateRedisCacheTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Delete: builder.Operation[datamodel.RedisCache]{ + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewDeleteResource[*datamodel.RedisCache, datamodel.RedisCache](options, &rds_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateRedisCacheTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Custom: map[string]builder.Operation[datamodel.RedisCache]{ + "listsecrets": { + APIController: rds_ctrl.NewListSecretsRedisCache, + }, + }, + }) + + _ = ns.AddResource("mongoDatabases", &builder.ResourceOption[*datamodel.MongoDatabase, datamodel.MongoDatabase]{ + RequestConverter: converter.MongoDatabaseDataModelFromVersioned, + ResponseConverter: converter.MongoDatabaseDataModelToVersioned, + + Put: builder.Operation[datamodel.MongoDatabase]{ + UpdateFilters: []apictrl.UpdateFilter[datamodel.MongoDatabase]{ + rp_frontend.PrepareRadiusResource[*datamodel.MongoDatabase], + }, + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewCreateOrUpdateResource[*datamodel.MongoDatabase, datamodel.MongoDatabase](options, &mongo_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateMongoDatabaseTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Patch: builder.Operation[datamodel.MongoDatabase]{ + UpdateFilters: []apictrl.UpdateFilter[datamodel.MongoDatabase]{ + rp_frontend.PrepareRadiusResource[*datamodel.MongoDatabase], + }, + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewCreateOrUpdateResource[*datamodel.MongoDatabase, datamodel.MongoDatabase](options, &mongo_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateMongoDatabaseTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Delete: builder.Operation[datamodel.MongoDatabase]{ + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewDeleteResource[*datamodel.MongoDatabase, datamodel.MongoDatabase](options, &mongo_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateRedisCacheTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Custom: map[string]builder.Operation[datamodel.MongoDatabase]{ + "listsecrets": { + APIController: mongo_ctrl.NewListSecretsMongoDatabase, + }, + }, + }) + + _ = ns.AddResource("sqldatabases", &builder.ResourceOption[*datamodel.SqlDatabase, datamodel.SqlDatabase]{ + RequestConverter: converter.SqlDatabaseDataModelFromVersioned, + ResponseConverter: converter.SqlDatabaseDataModelToVersioned, + + Put: builder.Operation[datamodel.SqlDatabase]{ + UpdateFilters: []apictrl.UpdateFilter[datamodel.SqlDatabase]{ + rp_frontend.PrepareRadiusResource[*datamodel.SqlDatabase], + }, + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewCreateOrUpdateResource[*datamodel.SqlDatabase, datamodel.SqlDatabase](options, &sql_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateMongoDatabaseTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Patch: builder.Operation[datamodel.SqlDatabase]{ + UpdateFilters: []apictrl.UpdateFilter[datamodel.SqlDatabase]{ + rp_frontend.PrepareRadiusResource[*datamodel.SqlDatabase], + }, + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewCreateOrUpdateResource[*datamodel.SqlDatabase, datamodel.SqlDatabase](options, &sql_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateMongoDatabaseTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Delete: builder.Operation[datamodel.SqlDatabase]{ + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewDeleteResource[*datamodel.SqlDatabase, datamodel.SqlDatabase](options, &sql_proc.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ds_ctrl.AsyncCreateOrUpdateRedisCacheTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Custom: map[string]builder.Operation[datamodel.SqlDatabase]{ + "listsecrets": { + APIController: sql_ctrl.NewListSecretsSqlDatabase, + }, + }, + }) + + // Optional + ns.SetAvailableOperations(operationList) + + return ns +} diff --git a/pkg/datastoresrp/setup/setup_test.go b/pkg/datastoresrp/setup/setup_test.go new file mode 100644 index 0000000000..ef58c9eb3c --- /dev/null +++ b/pkg/datastoresrp/setup/setup_test.go @@ -0,0 +1,147 @@ +/* +Copyright 2023 The Radius Authors. + +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 setup + +import ( + "context" + "net/http" + "testing" + + "github.com/go-chi/chi/v5" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" + "github.com/radius-project/radius/pkg/armrpc/builder" + apictrl "github.com/radius-project/radius/pkg/armrpc/frontend/controller" + "github.com/radius-project/radius/pkg/armrpc/rpctest" + ds_ctrl "github.com/radius-project/radius/pkg/datastoresrp/frontend/controller" + "github.com/radius-project/radius/pkg/portableresources" + "github.com/radius-project/radius/pkg/recipes/controllerconfig" + "github.com/radius-project/radius/pkg/ucp/dataprovider" + "github.com/radius-project/radius/pkg/ucp/store" +) + +var handlerTests = []rpctest.HandlerTestSpec{ + { + OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: v1.OperationPlaneScopeList}, + Path: "/providers/applications.datastores/mongodatabases", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: v1.OperationList}, + Path: "/resourcegroups/testrg/providers/applications.datastores/mongodatabases", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: v1.OperationGet}, + Path: "/resourcegroups/testrg/providers/applications.datastores/mongodatabases/mongo", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: v1.OperationPut}, + Path: "/resourcegroups/testrg/providers/applications.datastores/mongodatabases/mongo", + Method: http.MethodPut, + }, { + OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: v1.OperationPatch}, + Path: "/resourcegroups/testrg/providers/applications.datastores/mongodatabases/mongo", + Method: http.MethodPatch, + }, { + OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: v1.OperationDelete}, + Path: "/resourcegroups/testrg/providers/applications.datastores/mongodatabases/mongo", + Method: http.MethodDelete, + }, { + OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: ds_ctrl.OperationListSecret}, + Path: "/resourcegroups/testrg/providers/applications.datastores/mongodatabases/mongo/listsecrets", + Method: http.MethodPost, + }, { + OperationType: v1.OperationType{Type: portableresources.RedisCachesResourceType, Method: v1.OperationPlaneScopeList}, + Path: "/providers/applications.datastores/rediscaches", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.RedisCachesResourceType, Method: v1.OperationList}, + Path: "/resourcegroups/testrg/providers/applications.datastores/rediscaches", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.RedisCachesResourceType, Method: v1.OperationGet}, + Path: "/resourcegroups/testrg/providers/applications.datastores/rediscaches/redis", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.RedisCachesResourceType, Method: v1.OperationPut}, + Path: "/resourcegroups/testrg/providers/applications.datastores/rediscaches/redis", + Method: http.MethodPut, + }, { + OperationType: v1.OperationType{Type: portableresources.RedisCachesResourceType, Method: v1.OperationPatch}, + Path: "/resourcegroups/testrg/providers/applications.datastores/rediscaches/redis", + Method: http.MethodPatch, + }, { + OperationType: v1.OperationType{Type: portableresources.RedisCachesResourceType, Method: v1.OperationDelete}, + Path: "/resourcegroups/testrg/providers/applications.datastores/rediscaches/redis", + Method: http.MethodDelete, + }, { + OperationType: v1.OperationType{Type: portableresources.RedisCachesResourceType, Method: ds_ctrl.OperationListSecret}, + Path: "/resourcegroups/testrg/providers/applications.datastores/rediscaches/redis/listsecrets", + Method: http.MethodPost, + }, { + OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: v1.OperationPlaneScopeList}, + Path: "/providers/applications.datastores/sqldatabases", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: v1.OperationList}, + Path: "/resourcegroups/testrg/providers/applications.datastores/sqldatabases", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: v1.OperationGet}, + Path: "/resourcegroups/testrg/providers/applications.datastores/sqldatabases/sql", + Method: http.MethodGet, + }, { + OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: v1.OperationPut}, + Path: "/resourcegroups/testrg/providers/applications.datastores/sqldatabases/sql", + Method: http.MethodPut, + }, { + OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: v1.OperationPatch}, + Path: "/resourcegroups/testrg/providers/applications.datastores/sqldatabases/sql", + Method: http.MethodPatch, + }, { + OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: v1.OperationDelete}, + Path: "/resourcegroups/testrg/providers/applications.datastores/sqldatabases/sql", + Method: http.MethodDelete, + }, { + OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: ds_ctrl.OperationListSecret}, + Path: "/resourcegroups/testrg/providers/applications.datastores/sqldatabases/sql/listsecrets", + Method: http.MethodPost, + }, +} + +func TestRouter(t *testing.T) { + mctrl := gomock.NewController(t) + + mockSP := dataprovider.NewMockDataStorageProvider(mctrl) + mockSC := store.NewMockStorageClient(mctrl) + + mockSC.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).Return(&store.Object{}, nil).AnyTimes() + mockSC.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + mockSP.EXPECT().GetStorageClient(gomock.Any(), gomock.Any()).Return(store.StorageClient(mockSC), nil).AnyTimes() + + cfg := &controllerconfig.RecipeControllerConfig{} + ns := SetupNamespace(cfg) + nsBuilder := ns.GenerateBuilder() + + rpctest.AssertRouters(t, handlerTests, "/api.ucp.dev", "/planes/radius/local", func(ctx context.Context) (chi.Router, error) { + r := chi.NewRouter() + validator, err := builder.NewOpenAPIValidator(ctx, "/api.ucp.dev", "applications.datastores") + require.NoError(t, err) + return r, nsBuilder.ApplyAPIHandlers(ctx, r, apictrl.Options{PathBase: "/api.ucp.dev", DataProvider: mockSP}, validator) + }) +} diff --git a/pkg/portableresources/frontend/handler/getoperations.go b/pkg/portableresources/frontend/handler/getoperations.go index d3af86525c..8d731fca05 100644 --- a/pkg/portableresources/frontend/handler/getoperations.go +++ b/pkg/portableresources/frontend/handler/getoperations.go @@ -64,16 +64,6 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList { }, IsDataAction: false, }, - &v1.Operation{ - Name: "Applications.Datastores/operations/read", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "operations", - Operation: "Get operations", - Description: "Get the list of operations.", - }, - IsDataAction: false, - }, &v1.Operation{ Name: "Applications.Messaging/operations/read", Display: &v1.OperationDisplayProperties{ @@ -84,56 +74,6 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList { }, IsDataAction: false, }, - &v1.Operation{ - Name: "Applications.Datastores/mongoDatabases/read", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "mongoDatabases", - Operation: "Get/List mongoDatabases", - Description: "Gets/Lists mongoDatabase resource(s).", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/mongoDatabases/write", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "mongoDatabases", - Operation: "Create/Update mongoDatabases", - Description: "Creates or updates a mongo database resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/mongoDatabases/delete", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "mongoDatabases", - Operation: "Delete mongoDatabase", - Description: "Deletes a mongoDatabase resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/mongoDatabases/listsecrets/action", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "mongoDatabases", - Operation: "List secrets", - Description: "Lists mongoDatabase secrets.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/register/action", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: DatastoresProviderNamespace, - Operation: "Register Applications.Datastores resource provider", - Description: "Registers 'Applications.Datastores' resource provider with a subscription.", - }, - IsDataAction: false, - }, &v1.Operation{ Name: "Applications.Dapr/register/action", Display: &v1.OperationDisplayProperties{ @@ -154,106 +94,6 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList { }, IsDataAction: false, }, - &v1.Operation{ - Name: "Applications.Datastores/unregister/action", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "Applications.Datastores", - Operation: "Unregister 'Applications.Datastores' resource provider", - Description: "Unregisters 'Applications.Datastores' resource provider with a subscription.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Dapr/unregister/action", - Display: &v1.OperationDisplayProperties{ - Provider: DaprProviderNamespace, - Resource: "Applications.Datastores", - Operation: "Unregister 'Applications.Dapr' resource provider", - Description: "Unregisters 'Applications.Dapr' resource provider with a subscription.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Messaging/unregister/action", - Display: &v1.OperationDisplayProperties{ - Provider: MessagingProviderNamespace, - Resource: "Applications.Datastores", - Operation: "Unregister 'Applications.Messaging' resource provider", - Description: "Unregisters 'Applications.Messaging' resource provider with a subscription.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/sqlDatabases/read", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "sqlDatabases", - Operation: "Get/List sqlDatabases", - Description: "Gets/Lists sqlDatabase resource(s).", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/sqlDatabases/write", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "sqlDatabases", - Operation: "Create/Update sqlDatabases", - Description: "Creates or updates a sql database resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/sqlDatabases/delete", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "sqlDatabases", - Operation: "Delete sqlDatabase", - Description: "Deletes a sqlDatabase resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/redisCaches/read", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "redisCaches", - Operation: "Get/List redisCaches", - Description: "Gets/Lists redisCache resource(s).", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/redisCaches/write", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "redisCaches", - Operation: "Create/Update redisCaches", - Description: "Creates or updates a redisCache resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/redisCaches/delete", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "redisCaches", - Operation: "Delete redisCache", - Description: "Deletes a redisCache resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Datastores/redisCaches/listsecrets/action", - Display: &v1.OperationDisplayProperties{ - Provider: DatastoresProviderNamespace, - Resource: "redisCaches", - Operation: "List secrets", - Description: "Lists redisCache secrets.", - }, - IsDataAction: false, - }, &v1.Operation{ Name: "Applications.Messaging/rabbitMQQueues/read", Display: &v1.OperationDisplayProperties{ diff --git a/pkg/portableresources/frontend/handler/getoperations_test.go b/pkg/portableresources/frontend/handler/getoperations_test.go index 8d9781c0a5..e669ff2d2f 100644 --- a/pkg/portableresources/frontend/handler/getoperations_test.go +++ b/pkg/portableresources/frontend/handler/getoperations_test.go @@ -47,7 +47,7 @@ func TestRunWith20231001Preview(t *testing.T) { case *rest.OKResponse: pagination, ok := v.Body.(*v1.PaginatedList) require.True(t, ok) - require.Equal(t, 33, len(pagination.Value)) + require.Equal(t, 17, len(pagination.Value)) default: require.Truef(t, false, "should not return error") } diff --git a/pkg/portableresources/frontend/handler/routes_test.go b/pkg/portableresources/frontend/handler/routes_test.go index ccc8f96a65..400f786c3f 100644 --- a/pkg/portableresources/frontend/handler/routes_test.go +++ b/pkg/portableresources/frontend/handler/routes_test.go @@ -26,7 +26,6 @@ import ( v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" ctrl "github.com/radius-project/radius/pkg/armrpc/frontend/controller" "github.com/radius-project/radius/pkg/armrpc/rpctest" - ds_ctrl "github.com/radius-project/radius/pkg/datastoresrp/frontend/controller" rabbitmq_ctrl "github.com/radius-project/radius/pkg/messagingrp/frontend/controller/rabbitmqqueues" "github.com/radius-project/radius/pkg/portableresources" "github.com/radius-project/radius/pkg/ucp/dataprovider" @@ -134,7 +133,7 @@ var handlerTests = []rpctest.HandlerTestSpec{ OperationType: v1.OperationType{Type: portableresources.DaprStateStoresResourceType, Method: v1.OperationDelete}, Path: "/resourcegroups/testrg/providers/applications.dapr/statestores/daprstatestore", Method: http.MethodDelete, - }, { + }, /*{ OperationType: v1.OperationType{Type: portableresources.MongoDatabasesResourceType, Method: v1.OperationList}, Path: "/providers/applications.datastores/mongodatabases", Method: http.MethodGet, @@ -218,7 +217,7 @@ var handlerTests = []rpctest.HandlerTestSpec{ OperationType: v1.OperationType{Type: portableresources.SqlDatabasesResourceType, Method: ds_ctrl.OperationListSecret}, Path: "/resourcegroups/testrg/providers/applications.datastores/sqldatabases/sql/listsecrets", Method: http.MethodPost, - }, { + },*/{ OperationType: v1.OperationType{Type: "Applications.Messaging/operationStatuses", Method: v1.OperationGet}, Path: "/providers/applications.messaging/locations/global/operationstatuses/00000000-0000-0000-0000-000000000000", Method: http.MethodGet, @@ -274,13 +273,6 @@ func TestHandlers(t *testing.T) { WithoutRootScope: true, SkipOperationTypeValidation: true, }, - { - OperationType: v1.OperationType{Type: "Applications.Datastores/providers", Method: v1.OperationGet}, - Path: "/providers/applications.datastores/operations", - Method: http.MethodGet, - WithoutRootScope: true, - SkipOperationTypeValidation: true, - }, }...) // Test handlers for Azure resources