From eaee2607b983ede453e80fbeacabb0b25ce10273 Mon Sep 17 00:00:00 2001 From: Young Bu Park Date: Sun, 10 Sep 2023 20:59:20 -0700 Subject: [PATCH] Add missing async job controller for corerp and delete dead code. (#6243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description * Add deployment processor for corerp resource deletion * Delete dead code in corerp ## Type of change - This pull request is a minor refactor, code cleanup, test improvement, or other maintenance task and doesn't change the functionality of Radius (issue link optional). ## Auto-generated summary ### 🤖 Generated by Copilot at 0c13b30 ### Summary 🗑️🛣️📦 This pull request implements delete functionality for custom resources in the Radius core package. It also removes two unused files from the `pkg/corerp/backend` directory. > _Oh, we're the crew of the Radius ship, and we sail the code sea_ > _We create and update our resources, but sometimes we must delete_ > _So we pull on the rope and we sing this song, as we heave on the count of three_ > _`HTTPRoute`, `ContainerResource`, `Gateway`, and `VolumeResource`, goodbye to ye_ ### Walkthrough * Add delete operations for custom resources ([link](https://github.com/radius-project/radius/pull/6243/files?diff=unified&w=0#diff-1dfecb9519c9002f569daea7fb61bbb0b1f22e34d49ac2d03eeb3bc64e858c8fR92-R94), [link](https://github.com/radius-project/radius/pull/6243/files?diff=unified&w=0#diff-1dfecb9519c9002f569daea7fb61bbb0b1f22e34d49ac2d03eeb3bc64e858c8fR115-R117), [link](https://github.com/radius-project/radius/pull/6243/files?diff=unified&w=0#diff-1dfecb9519c9002f569daea7fb61bbb0b1f22e34d49ac2d03eeb3bc64e858c8fR138-R140), [link](https://github.com/radius-project/radius/pull/6243/files?diff=unified&w=0#diff-1dfecb9519c9002f569daea7fb61bbb0b1f22e34d49ac2d03eeb3bc64e858c8fR161-R163)) * Remove unused files ([link](https://github.com/radius-project/radius/pull/6243/files?diff=unified&w=0#diff-5d6b976ca1401aa4b4ea6fdaf8142700ada0d6ddd9690bb7eed8797f91d33466), [link](https://github.com/radius-project/radius/pull/6243/files?diff=unified&w=0#diff-0fb3b9f2c9139180171c66e076eacdb9f6ea1b44e8a3356a8dbc688436614535)) --- pkg/corerp/backend/service.go | 183 ---- pkg/corerp/backend/systemservice.go | 86 -- pkg/corerp/frontend/handler/getoperations.go | 299 ------- pkg/corerp/frontend/handler/routes.go | 855 ------------------- pkg/corerp/frontend/handler/routes_test.go | 265 ------ pkg/corerp/setup/setup.go | 56 +- 6 files changed, 48 insertions(+), 1696 deletions(-) delete mode 100644 pkg/corerp/backend/service.go delete mode 100644 pkg/corerp/backend/systemservice.go delete mode 100644 pkg/corerp/frontend/handler/getoperations.go delete mode 100644 pkg/corerp/frontend/handler/routes.go delete mode 100644 pkg/corerp/frontend/handler/routes_test.go diff --git a/pkg/corerp/backend/service.go b/pkg/corerp/backend/service.go deleted file mode 100644 index 6b5dbc5986..0000000000 --- a/pkg/corerp/backend/service.go +++ /dev/null @@ -1,183 +0,0 @@ -/* -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 backend - -import ( - "context" - "fmt" - - v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" - ctrl "github.com/radius-project/radius/pkg/armrpc/asyncoperation/controller" - "github.com/radius-project/radius/pkg/armrpc/asyncoperation/worker" - "github.com/radius-project/radius/pkg/armrpc/hostoptions" - aztoken "github.com/radius-project/radius/pkg/azure/tokencredentials" - backend_ctrl "github.com/radius-project/radius/pkg/corerp/backend/controller" - "github.com/radius-project/radius/pkg/corerp/backend/deployment" - "github.com/radius-project/radius/pkg/corerp/datamodel" - "github.com/radius-project/radius/pkg/corerp/model" - "github.com/radius-project/radius/pkg/corerp/processors/extenders" - "github.com/radius-project/radius/pkg/kubeutil" - "github.com/radius-project/radius/pkg/portableresources" - pr_backend_ctrl "github.com/radius-project/radius/pkg/portableresources/backend/controller" - "github.com/radius-project/radius/pkg/portableresources/processors" - "github.com/radius-project/radius/pkg/recipes" - "github.com/radius-project/radius/pkg/recipes/configloader" - "github.com/radius-project/radius/pkg/recipes/driver" - "github.com/radius-project/radius/pkg/recipes/engine" - "github.com/radius-project/radius/pkg/sdk" - "github.com/radius-project/radius/pkg/sdk/clients" - "github.com/radius-project/radius/pkg/ucp/secret/provider" -) - -const ( - providerName = "Applications.Core" -) - -var ( - // ResourceTypeNames is the array that holds resource types that needs async processing. - // We use this array to generate generic backend controller for each resource. - ResourceTypeNames = []string{ - "Applications.Core/containers", - "Applications.Core/gateways", - "Applications.Core/httpRoutes", - "Applications.Core/volumes", - } -) - -// Service is a service to run AsyncReqeustProcessWorker. -type Service struct { - worker.Service -} - -// NewService creates a new Service instance to run AsyncReqeustProcessWorker. -func NewService(options hostoptions.HostOptions) *Service { - return &Service{ - worker.Service{ - ProviderName: providerName, - Options: options, - }, - } -} - -// Name returns a string containing the service name. -func (w *Service) Name() string { - return fmt.Sprintf("%s async worker", providerName) -} - -// Run initializes the application model, registers controllers for different resource types, and starts the worker with -// the given options. -func (w *Service) Run(ctx context.Context) error { - if err := w.Init(ctx); err != nil { - return err - } - - k8s, err := kubeutil.NewClients(w.Options.K8sConfig) - if err != nil { - return fmt.Errorf("failed to initialize kubernetes clients: %w", err) - } - - coreAppModel, err := model.NewApplicationModel(w.Options.Arm, k8s.RuntimeClient, k8s.ClientSet, k8s.DiscoveryClient, k8s.DynamicClient) - if err != nil { - return fmt.Errorf("failed to initialize application model: %w", err) - } - - opts := ctrl.Options{ - DataProvider: w.StorageProvider, - KubeClient: k8s.RuntimeClient, - GetDeploymentProcessor: func() deployment.DeploymentProcessor { - return deployment.NewDeploymentProcessor(coreAppModel, w.StorageProvider, k8s.RuntimeClient, k8s.ClientSet) - }, - } - - for _, rt := range ResourceTypeNames { - // Register controllers - err = w.Controllers.Register(ctx, rt, v1.OperationPut, backend_ctrl.NewCreateOrUpdateResource, opts) - if err != nil { - panic(err) - } - err = w.Controllers.Register(ctx, rt, v1.OperationPatch, backend_ctrl.NewCreateOrUpdateResource, opts) - if err != nil { - panic(err) - } - err = w.Controllers.Register(ctx, rt, v1.OperationDelete, backend_ctrl.NewDeleteResource, opts) - if err != nil { - panic(err) - } - } - - client := processors.NewResourceClient(w.Options.Arm, w.Options.UCPConnection, k8s.RuntimeClient, k8s.DiscoveryClient) - clientOptions := sdk.NewClientOptions(w.Options.UCPConnection) - - deploymentEngineClient, err := clients.NewResourceDeploymentsClient(&clients.Options{ - Cred: &aztoken.AnonymousCredential{}, - BaseURI: w.Options.UCPConnection.Endpoint(), - ARMClientOptions: sdk.NewClientOptions(w.Options.UCPConnection), - }) - if err != nil { - return err - } - - configLoader := configloader.NewEnvironmentLoader(clientOptions) - engine := engine.NewEngine(engine.Options{ - ConfigurationLoader: configLoader, - Drivers: map[string]driver.Driver{ - recipes.TemplateKindBicep: driver.NewBicepDriver(clientOptions, deploymentEngineClient, client), - recipes.TemplateKindTerraform: driver.NewTerraformDriver(w.Options.UCPConnection, provider.NewSecretProvider(w.Options.Config.SecretProvider), - driver.TerraformOptions{ - Path: w.Options.Config.Terraform.Path, - }, k8s.ClientSet), - }, - }) - - opts.GetDeploymentProcessor = nil - extenderCreateOrUpdateController := func(options ctrl.Options) (ctrl.Controller, error) { - processor := &extenders.Processor{} - return pr_backend_ctrl.NewCreateOrUpdateResource[*datamodel.Extender, datamodel.Extender](options, processor, engine, client, configLoader) - } - extenderDeleteController := func(options ctrl.Options) (ctrl.Controller, error) { - processor := &extenders.Processor{} - return pr_backend_ctrl.NewDeleteResource[*datamodel.Extender, datamodel.Extender](options, processor, engine, configLoader) - } - - // Register controllers to run backend processing for extenders. - err = w.Controllers.Register(ctx, portableresources.ExtendersResourceType, v1.OperationPut, extenderCreateOrUpdateController, opts) - if err != nil { - return err - } - - err = w.Controllers.Register( - ctx, - portableresources.ExtendersResourceType, - v1.OperationDelete, - extenderDeleteController, - opts) - if err != nil { - return err - } - - workerOpts := worker.Options{} - if w.Options.Config.WorkerServer != nil { - if w.Options.Config.WorkerServer.MaxOperationConcurrency != nil { - workerOpts.MaxOperationConcurrency = *w.Options.Config.WorkerServer.MaxOperationConcurrency - } - if w.Options.Config.WorkerServer.MaxOperationRetryCount != nil { - workerOpts.MaxOperationRetryCount = *w.Options.Config.WorkerServer.MaxOperationRetryCount - } - } - - return w.Start(ctx, workerOpts) -} diff --git a/pkg/corerp/backend/systemservice.go b/pkg/corerp/backend/systemservice.go deleted file mode 100644 index d2fec5e57f..0000000000 --- a/pkg/corerp/backend/systemservice.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -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 backend - -import ( - "context" - "fmt" - "net" - "net/http" - - "github.com/radius-project/radius/pkg/armrpc/hostoptions" - "github.com/radius-project/radius/pkg/ucp/ucplog" - "github.com/radius-project/radius/pkg/version" -) - -// SystemService represents the service which provides the basic health status and metric server. -type SystemService struct { - options hostoptions.HostOptions -} - -// NewSystemService creates a new SystemService instance with the given options. -func NewSystemService(options hostoptions.HostOptions) *SystemService { - return &SystemService{ - options: options, - } -} - -// Name returns the name of the system service. -func (s *SystemService) Name() string { - return "system service" -} - -// Run sets up an HTTP server to handle requests on the given port and handles shutdown based on the -// context. It returns an error if the server fails to start. -func (s *SystemService) Run(ctx context.Context) error { - logger := ucplog.FromContextOrDiscard(ctx) - - mux := http.NewServeMux() - mux.HandleFunc("/version", version.ReportVersionHandler) - mux.HandleFunc("/healthz", version.ReportVersionHandler) - - // TODO: Add prometheus metric later. - - address := fmt.Sprintf(":%d", *s.options.Config.WorkerServer.Port) - - server := &http.Server{ - Addr: address, - Handler: mux, - BaseContext: func(ln net.Listener) context.Context { - return ctx - }, - } - - // Handle shutdown based on the context - go func() { - <-ctx.Done() - // We don't care about shutdown errors - _ = server.Shutdown(ctx) - }() - - logger.Info(fmt.Sprintf("System service endpoint on: '%s'...", address)) - if err := server.ListenAndServe(); err == http.ErrServerClosed { - // We expect this, safe to ignore. - logger.Info("Server stopped...") - return nil - } else if err != nil { - return err - } - - logger.Info("Server stopped...") - return nil -} diff --git a/pkg/corerp/frontend/handler/getoperations.go b/pkg/corerp/frontend/handler/getoperations.go deleted file mode 100644 index 18bc4dc937..0000000000 --- a/pkg/corerp/frontend/handler/getoperations.go +++ /dev/null @@ -1,299 +0,0 @@ -/* -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 handler - -import ( - "context" - "net/http" - - 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/rest" - v20220315privatepreview "github.com/radius-project/radius/pkg/corerp/api/v20220315privatepreview" -) - -var _ ctrl.Controller = (*GetOperations)(nil) - -// GetOperations is the controller implementation to get arm rpc available operations. -type GetOperations struct { - ctrl.BaseController -} - -// NewGetOperations creates a new GetOperations controller with the given options. -func NewGetOperations(opts ctrl.Options) (ctrl.Controller, error) { - return &GetOperations{ctrl.NewBaseController(opts)}, nil -} - -// Run checks the API version of the request and returns the available operations for the resource provider at tenant level. -// Spec: https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/proxy-api-reference.md#exposing-available-operations -func (opctrl *GetOperations) Run(ctx context.Context, w http.ResponseWriter, req *http.Request) (rest.Response, error) { - sCtx := v1.ARMRequestContextFromContext(ctx) - - switch sCtx.APIVersion { - case v20220315privatepreview.Version: - return rest.NewOKResponse(opctrl.availableOperationsV1()), nil - } - - return rest.NewNotFoundAPIVersionResponse("operations", ProviderNamespaceName, sCtx.APIVersion), nil -} - -func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList { - return &v1.PaginatedList{ - Value: []any{ - &v1.Operation{ - Name: "Applications.Core/operations/read", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "operations", - Operation: "Get operations", - Description: "Get the list of operations", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/environments/read", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "environments", - Operation: "List environments", - Description: "Get the list of environments.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/environments/write", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "environments", - Operation: "Create/Update environment", - Description: "Create or update an environment.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/environments/delete", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "environments", - Operation: "Delete environment", - Description: "Delete an environment.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/environments/getmetadata/action", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "environments", - Operation: "Get recipe metadata", - Description: "Get recipe metadata.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/environments/join/action", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "environments", - Operation: "Join environment", - Description: "Join to application environment.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/register/action", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: ProviderNamespaceName, - Operation: "Register Applications.Core", - Description: "Register the subscription for Applications.Core.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/unregister/action", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: ProviderNamespaceName, - Operation: "Unregister Applications.Core", - Description: "Unregister the subscription for Applications.Core.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/httproutes/read", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "httproutes", - Operation: "List httproutes", - Description: "Get the list of httproutes.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/httproutes/write", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "httproutes", - Operation: "Create/Update httproute", - Description: "Create or update an httproute.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/httproutes/delete", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "httproutes", - Operation: "Delete httproute", - Description: "Delete an httproute.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/applications/read", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "applications", - Operation: "List applications", - Description: "Get the list of applications.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/applications/write", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "applications", - Operation: "Create/Update application", - Description: "Create or update an application.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/applications/delete", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "applications", - Operation: "Delete application", - Description: "Delete an application.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/gateways/read", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "gateways", - Operation: "List gateways", - Description: "Get the list of gateways.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/gateways/write", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "gateways", - Operation: "Create/Update gateway", - Description: "Create or Updateg a gateway.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/gateways/delete", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "gateways", - Operation: "delete gateway", - Description: "Delete a gateway.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/containers/read", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "containers", - Operation: "List containers", - Description: "Get the list of containers.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/containers/write", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "containers", - Operation: "Create/Update container", - Description: "Create or update a container.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/containers/delete", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "containers", - Operation: "Delete container", - Description: "Delete a container.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/extenders/read", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "extenders", - Operation: "Get/List extenders", - Description: "Gets/Lists extender link(s).", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/extenders/write", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "extenders", - Operation: "Create/Update extenders", - Description: "Creates or updates a extender resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/extenders/delete", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "extenders", - Operation: "Delete extender", - Description: "Deletes a extender resource.", - }, - IsDataAction: false, - }, - &v1.Operation{ - Name: "Applications.Core/extenders/listsecrets/action", - Display: &v1.OperationDisplayProperties{ - Provider: ProviderNamespaceName, - Resource: "extenders", - Operation: "List secrets", - Description: "Lists extender secrets.", - }, - IsDataAction: false, - }, - }, - } -} diff --git a/pkg/corerp/frontend/handler/routes.go b/pkg/corerp/frontend/handler/routes.go deleted file mode 100644 index 8c7051b80f..0000000000 --- a/pkg/corerp/frontend/handler/routes.go +++ /dev/null @@ -1,855 +0,0 @@ -/* -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 handler - -import ( - "context" - "time" - - "github.com/go-chi/chi/v5" - - v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" - frontend_ctrl "github.com/radius-project/radius/pkg/armrpc/frontend/controller" - "github.com/radius-project/radius/pkg/armrpc/frontend/defaultoperation" - "github.com/radius-project/radius/pkg/armrpc/frontend/server" - "github.com/radius-project/radius/pkg/recipes/engine" - rp_frontend "github.com/radius-project/radius/pkg/rp/frontend" - "github.com/radius-project/radius/pkg/validator" - "github.com/radius-project/radius/swagger" - - "github.com/radius-project/radius/pkg/corerp/datamodel" - converter "github.com/radius-project/radius/pkg/corerp/datamodel/converter" - - app_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/applications" - ctr_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/containers" - env_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/environments" - ext_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/extenders" - gtwy_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/gateways" - hrt_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/httproutes" - secret_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/secretstores" - vol_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/volumes" -) - -const ( - ProviderNamespaceName = "Applications.Core" - - // AsyncOperationRetryAfter is polling interval for async create/update or delete resource operations. - AsyncOperationRetryAfter = time.Duration(5) * time.Second -) - -// AddRoutes registers handlers for Container, Application, Gateway, Volume and Secret Store resources, allowing for -// operations such as List, Get, Put, Patch and Delete. -func AddRoutes(ctx context.Context, r chi.Router, isARM bool, ctrlOpts frontend_ctrl.Options, engine engine.Engine) error { - rootScopePath := ctrlOpts.PathBase - if isARM { - rootScopePath += "/subscriptions/{subscriptionID}" - } else { - rootScopePath += "/planes/radius/{planeName}" - } - - resourceGroupPath := "/resourcegroups/{resourceGroupName}" - - // Configure the default ARM handlers. - err := server.ConfigureDefaultHandlers(ctx, r, rootScopePath, isARM, ProviderNamespaceName, NewGetOperations, ctrlOpts) - if err != nil { - return err - } - - // URLs may use either the subscription/plane scope or resource group scope. - // - // These paths are order sensitive and the longer path MUST be registered first. - prefixes := []string{ - rootScopePath + resourceGroupPath, - rootScopePath, - } - - specLoader, err := validator.LoadSpec(ctx, ProviderNamespaceName, swagger.SpecFiles, prefixes, "rootScope") - if err != nil { - return err - } - - validator := validator.APIValidator(validator.Options{ - SpecLoader: specLoader, - ResourceTypeGetter: validator.RadiusResourceTypeGetter, - }) - - // Register resource routers. - // - // Note: We have to follow the below rules to enable API validators: - // 1. For collection scope routers (xxxPlaneRouter and xxxResourceGroupRouter), register validator at HandlerOptions.Middlewares. - // 2. For resource scopes (xxxResourceRouter), register validator at Subrouter. - - // Environments resource routers. - envPlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/environments", validator) - envResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/environments", validator) - envResourceRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/environments/{environmentName}", validator) - - handlerOptions := []server.HandlerOptions{ - // Environments resource handler registration. - { - ParentRouter: envPlaneRouter, - ResourceType: env_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources( - opt, - frontend_ctrl.ResourceOptions[datamodel.Environment]{ - ResponseConverter: converter.EnvironmentDataModelToVersioned, - ListRecursiveQuery: true, - }) - }, - }, - { - ParentRouter: envResourceGroupRouter, - ResourceType: env_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.Environment]{ - ResponseConverter: converter.EnvironmentDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: envResourceRouter, - ResourceType: env_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.Environment]{ - ResponseConverter: converter.EnvironmentDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: envResourceRouter, - ResourceType: env_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: env_ctrl.NewCreateOrUpdateEnvironment, - }, - { - ParentRouter: envResourceRouter, - ResourceType: env_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: env_ctrl.NewCreateOrUpdateEnvironment, - }, - { - ParentRouter: envResourceRouter, - ResourceType: env_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultSyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.Environment]{ - RequestConverter: converter.EnvironmentDataModelFromVersioned, - ResponseConverter: converter.EnvironmentDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: envResourceRouter, - Path: "/getmetadata", - ResourceType: env_ctrl.ResourceTypeName, - Method: env_ctrl.OperationGetRecipeMetadata, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return env_ctrl.NewGetRecipeMetadata(opt, engine) - }, - }, - } - - // httpRoute resource handler registration. - httpRoutePlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/httproutes", validator) - httpRouteResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/httproutes", validator) - httpRouteResourceRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/httproutes/{httpRouteName}", validator) - - handlerOptions = append(handlerOptions, []server.HandlerOptions{ - { - ParentRouter: httpRoutePlaneRouter, - ResourceType: hrt_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.HTTPRoute]{ - ResponseConverter: converter.HTTPRouteDataModelToVersioned, - ListRecursiveQuery: true, - }, - ) - }, - }, - { - ParentRouter: httpRouteResourceGroupRouter, - ResourceType: hrt_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.HTTPRoute]{ - ResponseConverter: converter.HTTPRouteDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: httpRouteResourceRouter, - ResourceType: hrt_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.HTTPRoute]{ - ResponseConverter: converter.HTTPRouteDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: httpRouteResourceRouter, - ResourceType: hrt_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.HTTPRoute]{ - RequestConverter: converter.HTTPRouteDataModelFromVersioned, - ResponseConverter: converter.HTTPRouteDataModelToVersioned, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: httpRouteResourceRouter, - ResourceType: hrt_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.HTTPRoute]{ - RequestConverter: converter.HTTPRouteDataModelFromVersioned, - ResponseConverter: converter.HTTPRouteDataModelToVersioned, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: httpRouteResourceRouter, - ResourceType: hrt_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.HTTPRoute]{ - RequestConverter: converter.HTTPRouteDataModelFromVersioned, - ResponseConverter: converter.HTTPRouteDataModelToVersioned, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - }...) - - // Container resource handlers. - containerPlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/containers", validator) - containerResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/containers", validator) - containerResourceRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/containers/{containerName}", validator) - - handlerOptions = append(handlerOptions, []server.HandlerOptions{ - { - ParentRouter: containerPlaneRouter, - ResourceType: ctr_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.ContainerResource]{ - ResponseConverter: converter.ContainerDataModelToVersioned, - ListRecursiveQuery: true, - }, - ) - }, - }, - { - ParentRouter: containerResourceGroupRouter, - ResourceType: ctr_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.ContainerResource]{ - ResponseConverter: converter.ContainerDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: containerResourceRouter, - ResourceType: ctr_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.ContainerResource]{ - ResponseConverter: converter.ContainerDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: containerResourceRouter, - ResourceType: ctr_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.ContainerResource]{ - RequestConverter: converter.ContainerDataModelFromVersioned, - ResponseConverter: converter.ContainerDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.ContainerResource]{ - rp_frontend.PrepareRadiusResource[*datamodel.ContainerResource], - ctr_ctrl.ValidateAndMutateRequest, - }, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: containerResourceRouter, - ResourceType: ctr_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.ContainerResource]{ - RequestConverter: converter.ContainerDataModelFromVersioned, - ResponseConverter: converter.ContainerDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.ContainerResource]{ - rp_frontend.PrepareRadiusResource[*datamodel.ContainerResource], - ctr_ctrl.ValidateAndMutateRequest, - }, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: containerResourceRouter, - ResourceType: ctr_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.ContainerResource]{ - RequestConverter: converter.ContainerDataModelFromVersioned, - ResponseConverter: converter.ContainerDataModelToVersioned, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - }...) - - // Container resource handlers. - appPlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/applications", validator) - appResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/applications", validator) - appResourceRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/applications/{applicationName}", validator) - - handlerOptions = append(handlerOptions, []server.HandlerOptions{ - // Applications resource handler registration. - { - ParentRouter: appPlaneRouter, - ResourceType: app_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.Application]{ - ResponseConverter: converter.ApplicationDataModelToVersioned, - ListRecursiveQuery: true, - }, - ) - }, - }, - { - ParentRouter: appResourceGroupRouter, - ResourceType: app_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.Application]{ - ResponseConverter: converter.ApplicationDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: appResourceRouter, - ResourceType: app_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.Application]{ - ResponseConverter: converter.ApplicationDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: appResourceRouter, - ResourceType: app_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultSyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.Application]{ - RequestConverter: converter.ApplicationDataModelFromVersioned, - ResponseConverter: converter.ApplicationDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.Application]{ - rp_frontend.PrepareRadiusResource[*datamodel.Application], - app_ctrl.CreateAppScopedNamespace, - }, - }, - ) - }, - }, - { - ParentRouter: appResourceRouter, - ResourceType: app_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultSyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.Application]{ - RequestConverter: converter.ApplicationDataModelFromVersioned, - ResponseConverter: converter.ApplicationDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.Application]{ - rp_frontend.PrepareRadiusResource[*datamodel.Application], - app_ctrl.CreateAppScopedNamespace, - }, - }, - ) - }, - }, - { - ParentRouter: appResourceRouter, - ResourceType: app_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultSyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.Application]{ - RequestConverter: converter.ApplicationDataModelFromVersioned, - ResponseConverter: converter.ApplicationDataModelToVersioned, - }, - ) - }, - }, - }...) - - // Gateway resource handler registration. - gwPlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/gateways", validator) - gwResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/gateways", validator) - gwResourceRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/gateways/{gatewayName}", validator) - - handlerOptions = append(handlerOptions, []server.HandlerOptions{ - { - ParentRouter: gwPlaneRouter, - ResourceType: gtwy_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.Gateway]{ - ResponseConverter: converter.GatewayDataModelToVersioned, - ListRecursiveQuery: true, - }, - ) - }, - }, - { - ParentRouter: gwResourceGroupRouter, - ResourceType: gtwy_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.Gateway]{ - ResponseConverter: converter.GatewayDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: gwResourceRouter, - ResourceType: gtwy_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.Gateway]{ - ResponseConverter: converter.GatewayDataModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: gwResourceRouter, - ResourceType: gtwy_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.Gateway]{ - RequestConverter: converter.GatewayDataModelFromVersioned, - ResponseConverter: converter.GatewayDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.Gateway]{ - rp_frontend.PrepareRadiusResource[*datamodel.Gateway], - gtwy_ctrl.ValidateAndMutateRequest, - }, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: gwResourceRouter, - ResourceType: gtwy_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.Gateway]{ - RequestConverter: converter.GatewayDataModelFromVersioned, - ResponseConverter: converter.GatewayDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.Gateway]{ - rp_frontend.PrepareRadiusResource[*datamodel.Gateway], - gtwy_ctrl.ValidateAndMutateRequest, - }, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: gwResourceRouter, - ResourceType: gtwy_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.Gateway]{ - RequestConverter: converter.GatewayDataModelFromVersioned, - ResponseConverter: converter.GatewayDataModelToVersioned, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - }...) - - // Volumes resource handler registration. - volPlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/volumes", validator) - volResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/volumes", validator) - volRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/volumes/{volumeName}", validator) - handlerOptions = append(handlerOptions, []server.HandlerOptions{ - { - ParentRouter: volPlaneRouter, - ResourceType: vol_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.VolumeResource]{ - RequestConverter: converter.VolumeResourceModelFromVersioned, - ResponseConverter: converter.VolumeResourceModelToVersioned, - ListRecursiveQuery: true, - }, - ) - }, - }, - { - ParentRouter: volResourceGroupRouter, - ResourceType: vol_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.VolumeResource]{ - RequestConverter: converter.VolumeResourceModelFromVersioned, - ResponseConverter: converter.VolumeResourceModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: volRouter, - ResourceType: vol_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.VolumeResource]{ - RequestConverter: converter.VolumeResourceModelFromVersioned, - ResponseConverter: converter.VolumeResourceModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: volRouter, - ResourceType: vol_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.VolumeResource]{ - RequestConverter: converter.VolumeResourceModelFromVersioned, - ResponseConverter: converter.VolumeResourceModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.VolumeResource]{ - rp_frontend.PrepareRadiusResource[*datamodel.VolumeResource], - vol_ctrl.ValidateRequest, - }, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: volRouter, - ResourceType: vol_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.VolumeResource]{ - RequestConverter: converter.VolumeResourceModelFromVersioned, - ResponseConverter: converter.VolumeResourceModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.VolumeResource]{ - rp_frontend.PrepareRadiusResource[*datamodel.VolumeResource], - vol_ctrl.ValidateRequest, - }, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: volRouter, - ResourceType: vol_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.VolumeResource]{ - RequestConverter: converter.VolumeResourceModelFromVersioned, - ResponseConverter: converter.VolumeResourceModelToVersioned, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - }...) - - // Secret Store resource handler. - secretStorePlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/secretstores", validator) - secretStoreResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/secretstores", validator) - secretStoreResourceRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/secretstores/{secretStoreName}", validator) - - handlerOptions = append(handlerOptions, []server.HandlerOptions{ - { - ParentRouter: secretStorePlaneRouter, - ResourceType: secret_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.SecretStore]{ - ResponseConverter: converter.SecretStoreModelToVersioned, - ListRecursiveQuery: true, - }, - ) - }, - }, - { - ParentRouter: secretStoreResourceGroupRouter, - ResourceType: secret_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.SecretStore]{ - ResponseConverter: converter.SecretStoreModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: secretStoreResourceRouter, - ResourceType: secret_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.SecretStore]{ - ResponseConverter: converter.SecretStoreModelToVersioned, - }, - ) - }, - }, - { - ParentRouter: secretStoreResourceRouter, - ResourceType: secret_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultSyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.SecretStore]{ - RequestConverter: converter.SecretStoreModelFromVersioned, - ResponseConverter: converter.SecretStoreModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.SecretStore]{ - rp_frontend.PrepareRadiusResource[*datamodel.SecretStore], - secret_ctrl.ValidateAndMutateRequest, - secret_ctrl.UpsertSecret, - }, - }, - ) - }, - }, - { - ParentRouter: secretStoreResourceRouter, - ResourceType: secret_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultSyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.SecretStore]{ - RequestConverter: converter.SecretStoreModelFromVersioned, - ResponseConverter: converter.SecretStoreModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.SecretStore]{ - rp_frontend.PrepareRadiusResource[*datamodel.SecretStore], - secret_ctrl.ValidateAndMutateRequest, - secret_ctrl.UpsertSecret, - }, - }, - ) - }, - }, - { - ParentRouter: secretStoreResourceRouter, - ResourceType: secret_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultSyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.SecretStore]{ - ResponseConverter: converter.SecretStoreModelToVersioned, - DeleteFilters: []frontend_ctrl.DeleteFilter[datamodel.SecretStore]{ - secret_ctrl.DeleteRadiusSecret, - }, - }, - ) - }, - }, - { - ParentRouter: secretStoreResourceRouter, - Path: "/listsecrets", - ResourceType: secret_ctrl.ResourceTypeName, - Method: secret_ctrl.OperationListSecrets, - ControllerFactory: secret_ctrl.NewListSecrets, - }, - }...) - - extPlaneRouter := server.NewSubrouter(r, rootScopePath+"/providers/applications.core/extenders", validator) - extResourceGroupRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/extenders", validator) - extResourceRouter := server.NewSubrouter(r, rootScopePath+resourceGroupPath+"/providers/applications.core/extenders/{extenderName}", validator) - - handlerOptions = append(handlerOptions, []server.HandlerOptions{ - { - ParentRouter: extPlaneRouter, - ResourceType: ext_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.Extender]{ - RequestConverter: converter.ExtenderDataModelFromVersioned, - ResponseConverter: converter.ExtenderDataModelToVersioned, - ListRecursiveQuery: true, - }) - }, - }, - { - ParentRouter: extResourceGroupRouter, - ResourceType: ext_ctrl.ResourceTypeName, - Method: v1.OperationList, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewListResources(opt, - frontend_ctrl.ResourceOptions[datamodel.Extender]{ - RequestConverter: converter.ExtenderDataModelFromVersioned, - ResponseConverter: converter.ExtenderDataModelToVersioned, - }) - }, - }, - { - ParentRouter: extResourceRouter, - ResourceType: ext_ctrl.ResourceTypeName, - Method: v1.OperationGet, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewGetResource(opt, - frontend_ctrl.ResourceOptions[datamodel.Extender]{ - RequestConverter: converter.ExtenderDataModelFromVersioned, - ResponseConverter: converter.ExtenderDataModelToVersioned, - }) - }, - }, - { - ParentRouter: extResourceRouter, - ResourceType: ext_ctrl.ResourceTypeName, - Method: v1.OperationPut, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.Extender]{ - RequestConverter: converter.ExtenderDataModelFromVersioned, - ResponseConverter: converter.ExtenderDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.Extender]{ - rp_frontend.PrepareRadiusResource[*datamodel.Extender], - }, - AsyncOperationTimeout: ext_ctrl.AsyncCreateOrUpdateExtenderTimeout, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: extResourceRouter, - ResourceType: ext_ctrl.ResourceTypeName, - Method: v1.OperationPatch, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncPut(opt, - frontend_ctrl.ResourceOptions[datamodel.Extender]{ - RequestConverter: converter.ExtenderDataModelFromVersioned, - ResponseConverter: converter.ExtenderDataModelToVersioned, - UpdateFilters: []frontend_ctrl.UpdateFilter[datamodel.Extender]{ - rp_frontend.PrepareRadiusResource[*datamodel.Extender], - }, - AsyncOperationTimeout: ext_ctrl.AsyncCreateOrUpdateExtenderTimeout, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: extResourceRouter, - ResourceType: ext_ctrl.ResourceTypeName, - Method: v1.OperationDelete, - ControllerFactory: func(opt frontend_ctrl.Options) (frontend_ctrl.Controller, error) { - return defaultoperation.NewDefaultAsyncDelete(opt, - frontend_ctrl.ResourceOptions[datamodel.Extender]{ - RequestConverter: converter.ExtenderDataModelFromVersioned, - ResponseConverter: converter.ExtenderDataModelToVersioned, - AsyncOperationTimeout: ext_ctrl.AsyncDeleteExtenderTimeout, - AsyncOperationRetryAfter: AsyncOperationRetryAfter, - }, - ) - }, - }, - { - ParentRouter: extResourceRouter, - Path: "/listsecrets", - ResourceType: ext_ctrl.ResourceTypeName, - Method: ext_ctrl.OperationListSecrets, - ControllerFactory: ext_ctrl.NewListSecretsExtender, - }, - }...) - - for _, h := range handlerOptions { - if err := server.RegisterHandler(ctx, h, ctrlOpts); err != nil { - return err - } - } - - return nil -} diff --git a/pkg/corerp/frontend/handler/routes_test.go b/pkg/corerp/frontend/handler/routes_test.go deleted file mode 100644 index 735b57091d..0000000000 --- a/pkg/corerp/frontend/handler/routes_test.go +++ /dev/null @@ -1,265 +0,0 @@ -/* -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 handler - -import ( - "context" - "net/http" - "testing" - - "github.com/go-chi/chi/v5" - "github.com/golang/mock/gomock" - 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" - "github.com/radius-project/radius/pkg/recipes/engine" - "github.com/radius-project/radius/pkg/ucp/dataprovider" - "github.com/radius-project/radius/pkg/ucp/store" - - app_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/applications" - ctr_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/containers" - env_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/environments" - gtwy_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/gateways" - hrt_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/httproutes" - secret_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/secretstores" - vol_ctrl "github.com/radius-project/radius/pkg/corerp/frontend/controller/volumes" -) - -var handlerTests = []rpctest.HandlerTestSpec{ - { - OperationType: v1.OperationType{Type: app_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/providers/applications.core/applications", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: app_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/resourcegroups/testrg/providers/applications.core/applications", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: app_ctrl.ResourceTypeName, Method: v1.OperationGet}, - Path: "/resourcegroups/testrg/providers/applications.core/applications/app0", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: app_ctrl.ResourceTypeName, Method: v1.OperationPut}, - Path: "/resourcegroups/testrg/providers/applications.core/applications/app0", - Method: http.MethodPut, - }, { - OperationType: v1.OperationType{Type: app_ctrl.ResourceTypeName, Method: v1.OperationPatch}, - Path: "/resourcegroups/testrg/providers/applications.core/applications/app0", - Method: http.MethodPatch, - }, { - OperationType: v1.OperationType{Type: app_ctrl.ResourceTypeName, Method: v1.OperationDelete}, - Path: "/resourcegroups/testrg/providers/applications.core/applications/app0", - Method: http.MethodDelete, - }, { - OperationType: v1.OperationType{Type: ctr_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/providers/applications.core/containers", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: ctr_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/resourcegroups/testrg/providers/applications.core/containers", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: ctr_ctrl.ResourceTypeName, Method: v1.OperationGet}, - Path: "/resourcegroups/testrg/providers/applications.core/containers/ctr0", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: ctr_ctrl.ResourceTypeName, Method: v1.OperationPut}, - Path: "/resourcegroups/testrg/providers/applications.core/containers/ctr0", - Method: http.MethodPut, - }, { - OperationType: v1.OperationType{Type: ctr_ctrl.ResourceTypeName, Method: v1.OperationPatch}, - Path: "/resourcegroups/testrg/providers/applications.core/containers/ctr0", - Method: http.MethodPatch, - }, { - OperationType: v1.OperationType{Type: ctr_ctrl.ResourceTypeName, Method: v1.OperationDelete}, - Path: "/resourcegroups/testrg/providers/applications.core/containers/ctr0", - Method: http.MethodDelete, - }, { - OperationType: v1.OperationType{Type: env_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/providers/applications.core/environments", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: env_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/resourcegroups/testrg/providers/applications.core/environments", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: env_ctrl.ResourceTypeName, Method: v1.OperationGet}, - Path: "/resourcegroups/testrg/providers/applications.core/environments/env0", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: env_ctrl.ResourceTypeName, Method: v1.OperationPut}, - Path: "/resourcegroups/testrg/providers/applications.core/environments/env0", - Method: http.MethodPut, - }, { - OperationType: v1.OperationType{Type: env_ctrl.ResourceTypeName, Method: v1.OperationPatch}, - Path: "/resourcegroups/testrg/providers/applications.core/environments/env0", - Method: http.MethodPatch, - }, { - OperationType: v1.OperationType{Type: env_ctrl.ResourceTypeName, Method: v1.OperationDelete}, - Path: "/resourcegroups/testrg/providers/applications.core/environments/env0", - Method: http.MethodDelete, - }, { - OperationType: v1.OperationType{Type: env_ctrl.ResourceTypeName, Method: env_ctrl.OperationGetRecipeMetadata}, - Path: "/resourcegroups/testrg/providers/applications.core/environments/env0/getmetadata", - Method: http.MethodPost, - }, { - OperationType: v1.OperationType{Type: gtwy_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/providers/applications.core/gateways", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: gtwy_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/resourcegroups/testrg/providers/applications.core/gateways", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: gtwy_ctrl.ResourceTypeName, Method: v1.OperationGet}, - Path: "/resourcegroups/testrg/providers/applications.core/gateways/gateway0", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: gtwy_ctrl.ResourceTypeName, Method: v1.OperationPut}, - Path: "/resourcegroups/testrg/providers/applications.core/gateways/gateway0", - Method: http.MethodPut, - }, { - OperationType: v1.OperationType{Type: gtwy_ctrl.ResourceTypeName, Method: v1.OperationPatch}, - Path: "/resourcegroups/testrg/providers/applications.core/gateways/gateway0", - Method: http.MethodPatch, - }, { - OperationType: v1.OperationType{Type: gtwy_ctrl.ResourceTypeName, Method: v1.OperationDelete}, - Path: "/resourcegroups/testrg/providers/applications.core/gateways/gateway0", - Method: http.MethodDelete, - }, { - OperationType: v1.OperationType{Type: hrt_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/providers/applications.core/httproutes", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: hrt_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/resourcegroups/testrg/providers/applications.core/httproutes", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: hrt_ctrl.ResourceTypeName, Method: v1.OperationGet}, - Path: "/resourcegroups/testrg/providers/applications.core/httproutes/hrt0", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: hrt_ctrl.ResourceTypeName, Method: v1.OperationPut}, - Path: "/resourcegroups/testrg/providers/applications.core/httproutes/hrt0", - Method: http.MethodPut, - }, { - OperationType: v1.OperationType{Type: hrt_ctrl.ResourceTypeName, Method: v1.OperationPatch}, - Path: "/resourcegroups/testrg/providers/applications.core/httproutes/hrt0", - Method: http.MethodPatch, - }, { - OperationType: v1.OperationType{Type: hrt_ctrl.ResourceTypeName, Method: v1.OperationDelete}, - Path: "/resourcegroups/testrg/providers/applications.core/httproutes/hrt0", - Method: http.MethodDelete, - }, { - OperationType: v1.OperationType{Type: secret_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/providers/applications.core/secretstores", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: secret_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/resourcegroups/testrg/providers/applications.core/secretstores", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: secret_ctrl.ResourceTypeName, Method: v1.OperationGet}, - Path: "/resourcegroups/testrg/providers/applications.core/secretstores/secret0", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: secret_ctrl.ResourceTypeName, Method: v1.OperationPut}, - Path: "/resourcegroups/testrg/providers/applications.core/secretstores/secret0", - Method: http.MethodPut, - }, { - OperationType: v1.OperationType{Type: secret_ctrl.ResourceTypeName, Method: v1.OperationPatch}, - Path: "/resourcegroups/testrg/providers/applications.core/secretstores/secret0", - Method: http.MethodPatch, - }, { - OperationType: v1.OperationType{Type: secret_ctrl.ResourceTypeName, Method: v1.OperationDelete}, - Path: "/resourcegroups/testrg/providers/applications.core/secretstores/secret0", - Method: http.MethodDelete, - }, { - OperationType: v1.OperationType{Type: secret_ctrl.ResourceTypeName, Method: secret_ctrl.OperationListSecrets}, - Path: "/resourcegroups/testrg/providers/applications.core/secretstores/secret0/listsecrets", - Method: http.MethodPost, - }, { - OperationType: v1.OperationType{Type: vol_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/providers/applications.core/volumes", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: vol_ctrl.ResourceTypeName, Method: v1.OperationList}, - Path: "/resourcegroups/testrg/providers/applications.core/volumes", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: vol_ctrl.ResourceTypeName, Method: v1.OperationGet}, - Path: "/resourcegroups/testrg/providers/applications.core/volumes/volume0", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: vol_ctrl.ResourceTypeName, Method: v1.OperationPut}, - Path: "/resourcegroups/testrg/providers/applications.core/volumes/volume0", - Method: http.MethodPut, - }, { - OperationType: v1.OperationType{Type: vol_ctrl.ResourceTypeName, Method: v1.OperationPatch}, - Path: "/resourcegroups/testrg/providers/applications.core/volumes/volume0", - Method: http.MethodPatch, - }, { - OperationType: v1.OperationType{Type: vol_ctrl.ResourceTypeName, Method: v1.OperationDelete}, - Path: "/resourcegroups/testrg/providers/applications.core/volumes/volume0", - Method: http.MethodDelete, - }, { - OperationType: v1.OperationType{Type: "Applications.Core/operationStatuses", Method: v1.OperationGet}, - Path: "/providers/applications.core/locations/global/operationstatuses/00000000-0000-0000-0000-000000000000", - Method: http.MethodGet, - }, { - OperationType: v1.OperationType{Type: "Applications.Core/operationResults", Method: v1.OperationGet}, - Path: "/providers/applications.core/locations/global/operationresults/00000000-0000-0000-0000-000000000000", - Method: http.MethodGet, - }, -} - -func TestHandlers(t *testing.T) { - mctrl := gomock.NewController(t) - - mockSP := dataprovider.NewMockDataStorageProvider(mctrl) - mockSC := store.NewMockStorageClient(mctrl) - mockEngine := engine.NewMockEngine(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() - - t.Run("UCP", func(t *testing.T) { - // Test handlers for UCP resources. - rpctest.AssertRouters(t, handlerTests, "/api.ucp.dev", "/planes/radius/local", func(ctx context.Context) (chi.Router, error) { - r := chi.NewRouter() - return r, AddRoutes(ctx, r, false, ctrl.Options{PathBase: "/api.ucp.dev", DataProvider: mockSP}, mockEngine) - }) - }) - - t.Run("Azure", func(t *testing.T) { - // Add azure specific handlers. - azureHandlerTests := append(handlerTests, - rpctest.HandlerTestSpec{ - OperationType: v1.OperationType{Type: "Applications.Core/providers", Method: v1.OperationGet}, - Path: "/providers/applications.core/operations", - Method: http.MethodGet, - WithoutRootScope: true, - SkipOperationTypeValidation: true, - }) - // Test handlers for Azure resources - rpctest.AssertRouters(t, azureHandlerTests, "", "/subscriptions/00000000-0000-0000-0000-000000000000", func(ctx context.Context) (chi.Router, error) { - r := chi.NewRouter() - return r, AddRoutes(ctx, r, true, ctrl.Options{PathBase: "", DataProvider: mockSP}, mockEngine) - }) - }) -} diff --git a/pkg/corerp/setup/setup.go b/pkg/corerp/setup/setup.go index b4884fa5ad..83549c668e 100644 --- a/pkg/corerp/setup/setup.go +++ b/pkg/corerp/setup/setup.go @@ -17,6 +17,8 @@ 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" @@ -38,6 +40,11 @@ import ( pr_ctrl "github.com/radius-project/radius/pkg/portableresources/backend/controller" ) +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.Core") @@ -84,10 +91,16 @@ func SetupNamespace(recipeControllerConfig *controllerconfig.RecipeControllerCon ResponseConverter: converter.HTTPRouteDataModelToVersioned, Put: builder.Operation[datamodel.HTTPRoute]{ - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, Patch: builder.Operation[datamodel.HTTPRoute]{ - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Delete: builder.Operation[datamodel.HTTPRoute]{ + AsyncJobController: backend_ctrl.NewDeleteResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, }) @@ -100,14 +113,20 @@ func SetupNamespace(recipeControllerConfig *controllerconfig.RecipeControllerCon rp_frontend.PrepareRadiusResource[*datamodel.ContainerResource], ctr_ctrl.ValidateAndMutateRequest, }, - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, Patch: builder.Operation[datamodel.ContainerResource]{ UpdateFilters: []apictrl.UpdateFilter[datamodel.ContainerResource]{ rp_frontend.PrepareRadiusResource[*datamodel.ContainerResource], ctr_ctrl.ValidateAndMutateRequest, }, - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Delete: builder.Operation[datamodel.ContainerResource]{ + AsyncJobController: backend_ctrl.NewDeleteResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, }) @@ -120,14 +139,20 @@ func SetupNamespace(recipeControllerConfig *controllerconfig.RecipeControllerCon rp_frontend.PrepareRadiusResource[*datamodel.Gateway], gw_ctrl.ValidateAndMutateRequest, }, - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, Patch: builder.Operation[datamodel.Gateway]{ UpdateFilters: []apictrl.UpdateFilter[datamodel.Gateway]{ rp_frontend.PrepareRadiusResource[*datamodel.Gateway], gw_ctrl.ValidateAndMutateRequest, }, - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Delete: builder.Operation[datamodel.Gateway]{ + AsyncJobController: backend_ctrl.NewDeleteResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, }) @@ -140,14 +165,20 @@ func SetupNamespace(recipeControllerConfig *controllerconfig.RecipeControllerCon rp_frontend.PrepareRadiusResource[*datamodel.VolumeResource], vol_ctrl.ValidateRequest, }, - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, Patch: builder.Operation[datamodel.VolumeResource]{ UpdateFilters: []apictrl.UpdateFilter[datamodel.VolumeResource]{ rp_frontend.PrepareRadiusResource[*datamodel.VolumeResource], vol_ctrl.ValidateRequest, }, - AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncJobController: backend_ctrl.NewCreateOrUpdateResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, + }, + Delete: builder.Operation[datamodel.VolumeResource]{ + AsyncJobController: backend_ctrl.NewDeleteResource, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, }) @@ -192,16 +223,25 @@ func SetupNamespace(recipeControllerConfig *controllerconfig.RecipeControllerCon AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { return pr_ctrl.NewCreateOrUpdateResource(options, &ext_processor.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) }, + AsyncOperationTimeout: ext_ctrl.AsyncCreateOrUpdateExtenderTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, Patch: builder.Operation[datamodel.Extender]{ UpdateFilters: []apictrl.UpdateFilter[datamodel.Extender]{ rp_frontend.PrepareRadiusResource[*datamodel.Extender], }, + AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { + return pr_ctrl.NewCreateOrUpdateResource(options, &ext_processor.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ResourceClient, recipeControllerConfig.ConfigLoader) + }, + AsyncOperationTimeout: ext_ctrl.AsyncCreateOrUpdateExtenderTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, Delete: builder.Operation[datamodel.Extender]{ AsyncJobController: func(options asyncctrl.Options) (asyncctrl.Controller, error) { return pr_ctrl.NewDeleteResource(options, &ext_processor.Processor{}, recipeControllerConfig.Engine, recipeControllerConfig.ConfigLoader) }, + AsyncOperationTimeout: ext_ctrl.AsyncDeleteExtenderTimeout, + AsyncOperationRetryAfter: AsyncOperationRetryAfter, }, Custom: map[string]builder.Operation[datamodel.Extender]{ "listsecrets": {