From 31c016b27811cc14a96499ca87297af8774541a3 Mon Sep 17 00:00:00 2001 From: lakshmimsft Date: Wed, 18 Dec 2024 01:41:04 -0800 Subject: [PATCH] upd per discussion Signed-off-by: lakshmimsft --- cmd/ucpd/ucp-dev.yaml | 2 +- deploy/Chart/templates/ucp/configmaps.yaml | 2 +- deploy/manifest/built-in-providers/test1.yaml | 12 - deploy/manifest/built-in-providers/test2.yaml | 12 - pkg/cli/cmd/resourceprovider/create/create.go | 59 ++-- .../resourceprovider/create/create_test.go | 144 ++++------ .../resourceprovider-valid1.yaml} | 0 .../resourceprovider-valid2.yaml} | 0 pkg/cli/manifest/registermanifest.go | 158 ++++++++++- pkg/cli/manifest/registermanifest_test.go | 249 +++------------- pkg/ucp/hostoptions/providerconfig.go | 8 +- .../service.go | 32 ++- pkg/ucp/server/server.go | 4 +- .../locations_fake_test_notneeded.go | 149 ---------- pkg/ucp/ucpclient/registermanifests.go | 151 ---------- pkg/ucp/ucpclient/registermanifests_test.go | 266 ------------------ .../resourceproviders_fakes_test_notneeded.go | 159 ----------- .../resourcetypes_fake_test_notneeded.go | 148 ---------- pkg/ucp/ucpclient/testdata/test1.yaml | 12 - pkg/ucp/ucpclient/testdata/test2.yaml | 12 - pkg/ucp/ucpclient/ucpclient.go | 120 -------- pkg/ucp/ucpclient/ucpclient_test.go | 56 ---- 22 files changed, 319 insertions(+), 1436 deletions(-) delete mode 100644 deploy/manifest/built-in-providers/test1.yaml delete mode 100644 deploy/manifest/built-in-providers/test2.yaml rename pkg/cli/manifest/{testdata2/test1.yaml => registerdirectory_testdata/resourceprovider-valid1.yaml} (100%) rename pkg/cli/manifest/{testdata2/test2.yaml => registerdirectory_testdata/resourceprovider-valid2.yaml} (100%) rename pkg/ucp/{manifestservice => initializer}/service.go (78%) delete mode 100644 pkg/ucp/ucpclient/locations_fake_test_notneeded.go delete mode 100644 pkg/ucp/ucpclient/registermanifests.go delete mode 100644 pkg/ucp/ucpclient/registermanifests_test.go delete mode 100644 pkg/ucp/ucpclient/resourceproviders_fakes_test_notneeded.go delete mode 100644 pkg/ucp/ucpclient/resourcetypes_fake_test_notneeded.go delete mode 100644 pkg/ucp/ucpclient/testdata/test1.yaml delete mode 100644 pkg/ucp/ucpclient/testdata/test2.yaml delete mode 100644 pkg/ucp/ucpclient/ucpclient.go delete mode 100644 pkg/ucp/ucpclient/ucpclient_test.go diff --git a/cmd/ucpd/ucp-dev.yaml b/cmd/ucpd/ucp-dev.yaml index 35ddcd84c3..659a5c7a16 100644 --- a/cmd/ucpd/ucp-dev.yaml +++ b/cmd/ucpd/ucp-dev.yaml @@ -58,7 +58,7 @@ routing: # This is the default downstream (dynamic-rp) for UDT implementations. defaultDownstreamEndpoint: "http://localhost:8082" -manifests: +initialization: # This is the directory location which contains manifests to be registered. manifestDirectory: "deploy/manifest/built-in-providers" diff --git a/deploy/Chart/templates/ucp/configmaps.yaml b/deploy/Chart/templates/ucp/configmaps.yaml index 1f9f0bfd0c..3814ae64ad 100644 --- a/deploy/Chart/templates/ucp/configmaps.yaml +++ b/deploy/Chart/templates/ucp/configmaps.yaml @@ -54,7 +54,7 @@ data: routing: defaultDownstreamEndpoint: "http://dynamic-rp.radius-sytem:8082" - manifests: + initialization: manifestDirectory: "deploy/manifest/built-in-providers" metricsProvider: diff --git a/deploy/manifest/built-in-providers/test1.yaml b/deploy/manifest/built-in-providers/test1.yaml deleted file mode 100644 index 16740fb5d3..0000000000 --- a/deploy/manifest/built-in-providers/test1.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: Applications.Core -types: - containers: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: [] - applications: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: [] diff --git a/deploy/manifest/built-in-providers/test2.yaml b/deploy/manifest/built-in-providers/test2.yaml deleted file mode 100644 index 8fe9cf02de..0000000000 --- a/deploy/manifest/built-in-providers/test2.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: Applications.Dapr -types: - configurationStores: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: ["Recipes"] - pubSubBrokers: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: ["Recipes"] diff --git a/pkg/cli/cmd/resourceprovider/create/create.go b/pkg/cli/cmd/resourceprovider/create/create.go index 771a409af3..a8025abc4b 100644 --- a/pkg/cli/cmd/resourceprovider/create/create.go +++ b/pkg/cli/cmd/resourceprovider/create/create.go @@ -19,16 +19,17 @@ package create import ( "context" + aztoken "github.com/radius-project/radius/pkg/azure/tokencredentials" "github.com/radius-project/radius/pkg/cli" "github.com/radius-project/radius/pkg/cli/cmd" "github.com/radius-project/radius/pkg/cli/cmd/commonflags" "github.com/radius-project/radius/pkg/cli/cmd/resourceprovider/common" - "github.com/radius-project/radius/pkg/cli/connections" "github.com/radius-project/radius/pkg/cli/framework" "github.com/radius-project/radius/pkg/cli/manifest" "github.com/radius-project/radius/pkg/cli/output" "github.com/radius-project/radius/pkg/cli/workspaces" - "github.com/radius-project/radius/pkg/ucp/ucpclient" + "github.com/radius-project/radius/pkg/sdk" + "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" "github.com/spf13/cobra" ) @@ -69,22 +70,26 @@ rad resource-provider create --from-file /path/to/input.json // Runner is the Runner implementation for the `rad resource-provider create` command. type Runner struct { - ConnectionFactory connections.Factory - ConfigHolder *framework.ConfigHolder - Output output.Interface - Format string - Workspace *workspaces.Workspace + UCPClientFactory *v20231001preview.ClientFactory + ConfigHolder *framework.ConfigHolder + Output output.Interface + Format string + Workspace *workspaces.Workspace ResourceProviderManifestFilePath string ResourceProvider *manifest.ResourceProvider + Logger func(format string, args ...any) } // NewRunner creates an instance of the runner for the `rad resource-provider create` command. func NewRunner(factory framework.Factory) *Runner { + output := factory.GetOutput() return &Runner{ - ConnectionFactory: factory.GetConnectionFactory(), - ConfigHolder: factory.GetConfigHolder(), - Output: factory.GetOutput(), + ConfigHolder: factory.GetConfigHolder(), + Output: output, + Logger: func(format string, args ...any) { + output.LogInfo(format, args...) + }, } } @@ -97,6 +102,13 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { } r.Workspace = workspace + if r.UCPClientFactory == nil { + err = r.setClientFactory(cmd.Context(), workspace) + if err != nil { + return err + } + } + format, err := cli.RequireOutput(cmd) if err != nil { return err @@ -114,33 +126,40 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { // Run runs the `rad resource-provider create` command. func (r *Runner) Run(ctx context.Context) error { - connection, err := cmd.GetConnection(ctx, r.Workspace) - if err != nil { + // Proceed with registering manifests + if err := manifest.RegisterFile(ctx, r.UCPClientFactory, "local", r.ResourceProviderManifestFilePath, r.Logger); err != nil { return err } - ucpclient, err := ucpclient.NewUCPClient(connection) + response, err := r.UCPClientFactory.NewResourceProvidersClient().Get(ctx, "local", r.ResourceProvider.Name, nil) if err != nil { return err } - // Proceed with registering manifests - if err := ucpclient.RegisterManifests(ctx, r.ResourceProviderManifestFilePath); err != nil { - return nil + // Add a blank line before printing the result. + r.Output.LogInfo("") + + err = r.Output.WriteFormatted(r.Format, response, common.GetResourceProviderTableFormat()) + if err != nil { + return err } - response, err := ucpclient.GetResourceProvider(ctx, "local", r.ResourceProvider.Name) + return nil +} + +func (r *Runner) setClientFactory(ctx context.Context, workspace *workspaces.Workspace) error { + connection, err := cmd.GetConnection(ctx, workspace) if err != nil { return err } - // Add a blank line before printing the result. - r.Output.LogInfo("") + clientOptions := sdk.NewClientOptions(connection) - err = r.Output.WriteFormatted(r.Format, response, common.GetResourceProviderTableFormat()) + clientFactory, err := v20231001preview.NewClientFactory(&aztoken.AnonymousCredential{}, clientOptions) if err != nil { return err } + r.UCPClientFactory = clientFactory return nil } diff --git a/pkg/cli/cmd/resourceprovider/create/create_test.go b/pkg/cli/cmd/resourceprovider/create/create_test.go index 83f7f317db..4e394c1db9 100644 --- a/pkg/cli/cmd/resourceprovider/create/create_test.go +++ b/pkg/cli/cmd/resourceprovider/create/create_test.go @@ -17,22 +17,20 @@ limitations under the License. package create import ( + "bytes" "context" + "fmt" "testing" - v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" - "github.com/radius-project/radius/pkg/cli/clients" - "github.com/radius-project/radius/pkg/cli/cmd/resourceprovider/common" - "github.com/radius-project/radius/pkg/cli/connections" + "github.com/radius-project/radius/pkg/cli/cmd/commonflags" "github.com/radius-project/radius/pkg/cli/framework" + frmwk "github.com/radius-project/radius/pkg/cli/framework" "github.com/radius-project/radius/pkg/cli/manifest" "github.com/radius-project/radius/pkg/cli/output" "github.com/radius-project/radius/pkg/cli/workspaces" - "github.com/radius-project/radius/pkg/to" - "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" "github.com/radius-project/radius/test/radcli" + "github.com/spf13/cobra" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" ) func Test_CommandValidation(t *testing.T) { @@ -47,122 +45,86 @@ func Test_Validate(t *testing.T) { Name: "Valid", Input: []string{"--from-file", "testdata/valid.yaml"}, ExpectedValid: true, - ConfigHolder: framework.ConfigHolder{Config: config}, + ConfigHolder: frmwk.ConfigHolder{Config: config}, }, { Name: "Invalid: Error in manifest", Input: []string{"--from-file", "testdata/missing-required-field.yaml"}, ExpectedValid: false, - ConfigHolder: framework.ConfigHolder{Config: config}, + ConfigHolder: frmwk.ConfigHolder{Config: config}, }, { Name: "Invalid: missing arguments", Input: []string{}, ExpectedValid: false, - ConfigHolder: framework.ConfigHolder{Config: config}, + ConfigHolder: frmwk.ConfigHolder{Config: config}, }, { Name: "Invalid: too many arguments", Input: []string{"abcd", "--from-file", "testdata/valid.yaml"}, ExpectedValid: false, - ConfigHolder: framework.ConfigHolder{Config: config}, + ConfigHolder: frmwk.ConfigHolder{Config: config}, }, } - radcli.SharedValidateValidation(t, NewCommand, testcases) + + radcli.SharedValidateValidation(t, func(framework frmwk.Factory) (*cobra.Command, framework.Runner) { + runner := NewRunner(framework) + clientFactory, err := manifest.NewTestClientFactory() + require.NoError(t, err) + + runner.UCPClientFactory = clientFactory + runner.Output = &output.MockOutput{} + runner.ResourceProviderManifestFilePath = "testdata/valid.yaml" + + cmd := &cobra.Command{ + Use: "test", + Short: "Test command", + Args: cobra.ExactArgs(0), + RunE: frmwk.RunCommand(runner), + } + commonflags.AddOutputFlag(cmd) + commonflags.AddWorkspaceFlag(cmd) + commonflags.AddFromFileFlagVar(cmd, &runner.ResourceProviderManifestFilePath) + _ = cmd.MarkFlagRequired("from-file") + _ = cmd.MarkFlagFilename("from-file", "yaml", "json") + return cmd, runner + }, testcases) + } func Test_Run(t *testing.T) { t.Run("Success: resource provider created", func(t *testing.T) { - ctrl := gomock.NewController(t) resourceProviderData, err := manifest.ReadFile("testdata/valid.yaml") require.NoError(t, err) - expectedResourceProvider := v20231001preview.ResourceProviderResource{ - Location: to.Ptr(v1.LocationGlobal), - Properties: &v20231001preview.ResourceProviderProperties{}, - } - expectedResourceType := v20231001preview.ResourceTypeResource{ - Properties: &v20231001preview.ResourceTypeProperties{}, - } - expectedAPIVersion := v20231001preview.APIVersionResource{ - Properties: &v20231001preview.APIVersionProperties{}, - } - expectedLocation := v20231001preview.LocationResource{ - Properties: &v20231001preview.LocationProperties{ - ResourceTypes: map[string]*v20231001preview.LocationResourceType{ - "testResources": { - APIVersions: map[string]map[string]any{ - "2025-01-01-preview": {}, - }, - }, - }, - }, - } + expectedResourceType := "testResources" + expectedAPIVersion := "2025-01-01-preview" - appManagementClient := clients.NewMockApplicationsManagementClient(ctrl) - appManagementClient.EXPECT(). - CreateOrUpdateResourceProvider(gomock.Any(), "local", "MyCompany.Resources", &expectedResourceProvider). - Return(expectedResourceProvider, nil). - Times(1) - appManagementClient.EXPECT(). - CreateOrUpdateResourceType(gomock.Any(), "local", "MyCompany.Resources", "testResources", &expectedResourceType). - Return(expectedResourceType, nil). - Times(1) - appManagementClient.EXPECT(). - CreateOrUpdateAPIVersion(gomock.Any(), "local", "MyCompany.Resources", "testResources", "2025-01-01-preview", &expectedAPIVersion). - Return(expectedAPIVersion, nil). - Times(1) - appManagementClient.EXPECT(). - CreateOrUpdateLocation(gomock.Any(), "local", "MyCompany.Resources", v1.LocationGlobal, &expectedLocation). - Return(expectedLocation, nil). - Times(1) - appManagementClient.EXPECT(). - GetResourceProvider(gomock.Any(), "local", "MyCompany.Resources"). - Return(expectedResourceProvider, nil). - Times(1) - - outputSink := &output.MockOutput{} + clientFactory, err := manifest.NewTestClientFactory() + require.NoError(t, err) + + var logBuffer bytes.Buffer + logger := func(format string, args ...any) { + fmt.Fprintf(&logBuffer, format+"\n", args...) + } runner := &Runner{ - ConnectionFactory: &connections.MockFactory{ApplicationsManagementClient: appManagementClient}, - Output: outputSink, - Workspace: &workspaces.Workspace{}, - ResourceProvider: resourceProviderData, - Format: "table", + UCPClientFactory: clientFactory, + Output: &output.MockOutput{}, + Workspace: &workspaces.Workspace{}, + ResourceProvider: resourceProviderData, + Format: "table", + Logger: logger, + ResourceProviderManifestFilePath: "testdata/valid.yaml", } err = runner.Run(context.Background()) require.NoError(t, err) - expectedOutput := []any{ - output.LogOutput{ - Format: "Creating resource provider %s", - Params: []any{"MyCompany.Resources"}, - }, - output.LogOutput{ - Format: "Creating resource type %s/%s", - Params: []any{"MyCompany.Resources", "testResources"}, - }, - output.LogOutput{ - Format: "Creating API Version %s/%s@%s", - Params: []any{"MyCompany.Resources", "testResources", "2025-01-01-preview"}, - }, - output.LogOutput{ - Format: "Creating location %s/%s", - Params: []any{"MyCompany.Resources", "global"}, - }, - output.LogOutput{ - Format: "", - Params: nil, - }, - output.FormattedOutput{ - Format: "table", - Obj: expectedResourceProvider, - Options: common.GetResourceProviderTableFormat(), - }, - } - require.Equal(t, expectedOutput, outputSink.Writes) + logOutput := logBuffer.String() + require.Contains(t, logOutput, fmt.Sprintf("Creating resource provider %s", resourceProviderData.Name)) + require.Contains(t, logOutput, fmt.Sprintf("Creating resource type %s/%s", resourceProviderData.Name, expectedResourceType)) + require.Contains(t, logOutput, fmt.Sprintf("Creating API Version %s/%s@%s", resourceProviderData.Name, expectedResourceType, expectedAPIVersion)) }) - } diff --git a/pkg/cli/manifest/testdata2/test1.yaml b/pkg/cli/manifest/registerdirectory_testdata/resourceprovider-valid1.yaml similarity index 100% rename from pkg/cli/manifest/testdata2/test1.yaml rename to pkg/cli/manifest/registerdirectory_testdata/resourceprovider-valid1.yaml diff --git a/pkg/cli/manifest/testdata2/test2.yaml b/pkg/cli/manifest/registerdirectory_testdata/resourceprovider-valid2.yaml similarity index 100% rename from pkg/cli/manifest/testdata2/test2.yaml rename to pkg/cli/manifest/registerdirectory_testdata/resourceprovider-valid2.yaml diff --git a/pkg/cli/manifest/registermanifest.go b/pkg/cli/manifest/registermanifest.go index 8fff48924d..0e97ee5290 100644 --- a/pkg/cli/manifest/registermanifest.go +++ b/pkg/cli/manifest/registermanifest.go @@ -14,16 +14,22 @@ package manifest import ( "context" "fmt" + "net/http" "os" "path/filepath" + armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" + azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" "github.com/radius-project/radius/pkg/to" "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" + ucpfake "github.com/radius-project/radius/pkg/ucp/api/v20231001preview/fake" ) // RegisterFile registers a manifest file -func RegisterFile(ctx context.Context, clientFactory v20231001preview.ClientFactory, planeName string, filePath string, logger func(string)) error { +func RegisterFile(ctx context.Context, clientFactory *v20231001preview.ClientFactory, planeName string, filePath string, logger func(format string, args ...any)) error { // Check for valid file path if filePath == "" { return fmt.Errorf("invalid manifest file path") @@ -35,6 +41,7 @@ func RegisterFile(ctx context.Context, clientFactory v20231001preview.ClientFact return err } + logIfEnabled(logger, "Creating resource provider %s", resourceProvider.Name) resourceProviderPoller, err := clientFactory.NewResourceProvidersClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, v20231001preview.ResourceProviderResource{ Location: to.Ptr(v1.LocationGlobal), Properties: &v20231001preview.ResourceProviderProperties{}, @@ -57,6 +64,7 @@ func RegisterFile(ctx context.Context, clientFactory v20231001preview.ClientFact } for resourceTypeName, resourceType := range resourceProvider.Types { + logIfEnabled(logger, "Creating resource type %s/%s", resourceProvider.Name, resourceTypeName) resourceTypePoller, err := clientFactory.NewResourceTypesClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, resourceTypeName, v20231001preview.ResourceTypeResource{ Properties: &v20231001preview.ResourceTypeProperties{ DefaultAPIVersion: resourceType.DefaultAPIVersion, @@ -76,6 +84,7 @@ func RegisterFile(ctx context.Context, clientFactory v20231001preview.ClientFact } for apiVersionName := range resourceType.APIVersions { + logIfEnabled(logger, "Creating API Version %s/%s@%s", resourceProvider.Name, resourceTypeName, apiVersionName) apiVersionsPoller, err := clientFactory.NewAPIVersionsClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, resourceTypeName, apiVersionName, v20231001preview.APIVersionResource{ Properties: &v20231001preview.APIVersionProperties{}, }, nil) @@ -94,6 +103,7 @@ func RegisterFile(ctx context.Context, clientFactory v20231001preview.ClientFact locationResource.Properties.ResourceTypes[resourceTypeName] = locationResourceType } + logIfEnabled(logger, "Creating location %s/%s", resourceProvider.Name, v1.LocationGlobal) locationPoller, err := clientFactory.NewLocationsClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, v1.LocationGlobal, locationResource, nil) if err != nil { return err @@ -113,7 +123,7 @@ func RegisterFile(ctx context.Context, clientFactory v20231001preview.ClientFact } // RegisterDirectory registers all manifest files in a directory -func RegisterDirectory(ctx context.Context, clientFactory v20231001preview.ClientFactory, planeName string, directoryPath string, logger func(string)) error { +func RegisterDirectory(ctx context.Context, clientFactory *v20231001preview.ClientFactory, planeName string, directoryPath string, logger func(format string, args ...any)) error { // Check for valid directory path if directoryPath == "" { return fmt.Errorf("invalid manifest directory") @@ -137,10 +147,11 @@ func RegisterDirectory(ctx context.Context, clientFactory v20231001preview.Clien // Iterate over each file in the directory for _, fileInfo := range files { if fileInfo.IsDir() { - continue // Skip directories - TBD: check if want to include subdirectories + continue // Skip directories } filePath := filepath.Join(directoryPath, fileInfo.Name()) + logIfEnabled(logger, "Registering manifest %s", filePath) err = RegisterFile(ctx, clientFactory, planeName, filePath, logger) if err != nil { return fmt.Errorf("failed to register manifest file %s: %w", filePath, err) @@ -149,3 +160,144 @@ func RegisterDirectory(ctx context.Context, clientFactory v20231001preview.Clien return nil } + +// Define an optional logger to prevent nil pointer dereference +func logIfEnabled(logger func(format string, args ...any), format string, args ...any) { + if logger != nil { + logger(format, args...) + } +} + +func NewTestClientFactory() (*v20231001preview.ClientFactory, error) { + // Create fake servers for each client + resourceProvidersServer := ucpfake.ResourceProvidersServer{ + BeginCreateOrUpdate: func( + ctx context.Context, + planeName string, + resourceProviderName string, + resource v20231001preview.ResourceProviderResource, + options *v20231001preview.ResourceProvidersClientBeginCreateOrUpdateOptions, + ) (resp azfake.PollerResponder[v20231001preview.ResourceProvidersClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { + // Simulate successful creation + result := v20231001preview.ResourceProvidersClientCreateOrUpdateResponse{ + ResourceProviderResource: resource, + } + resp.AddNonTerminalResponse(http.StatusCreated, nil) + resp.SetTerminalResponse(http.StatusOK, result, nil) + + return + }, + Get: func( + ctx context.Context, + planeName string, + resourceProviderName string, + options *v20231001preview.ResourceProvidersClientGetOptions, // Add this parameter + ) (resp azfake.Responder[v20231001preview.ResourceProvidersClientGetResponse], errResp azfake.ErrorResponder) { + response := v20231001preview.ResourceProvidersClientGetResponse{ + ResourceProviderResource: v20231001preview.ResourceProviderResource{ + Name: to.Ptr(resourceProviderName), + }, + } + resp.SetResponse(http.StatusOK, response, nil) + return + }, + } + + // Create other fake servers similarly + resourceTypesServer := ucpfake.ResourceTypesServer{ + BeginCreateOrUpdate: func( + ctx context.Context, + planeName string, + resourceProviderName string, + resourceTypeName string, + resource v20231001preview.ResourceTypeResource, + options *v20231001preview.ResourceTypesClientBeginCreateOrUpdateOptions, + ) (resp azfake.PollerResponder[v20231001preview.ResourceTypesClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { + result := v20231001preview.ResourceTypesClientCreateOrUpdateResponse{ + ResourceTypeResource: resource, + } + + resp.AddNonTerminalResponse(http.StatusCreated, nil) + resp.SetTerminalResponse(http.StatusOK, result, nil) + + return + }, + Get: func( + ctx context.Context, + planeName string, + resourceProviderName string, + resourceTypeName string, + options *v20231001preview.ResourceTypesClientGetOptions, + ) (resp azfake.Responder[v20231001preview.ResourceTypesClientGetResponse], errResp azfake.ErrorResponder) { + response := v20231001preview.ResourceTypesClientGetResponse{ + ResourceTypeResource: v20231001preview.ResourceTypeResource{ + Name: to.Ptr(resourceTypeName), + }, + } + resp.SetResponse(http.StatusOK, response, nil) + return + }, + } + + apiVersionsServer := ucpfake.APIVersionsServer{ + BeginCreateOrUpdate: func( + ctx context.Context, + planeName string, + resourceProviderName string, + resourceTypeName string, + apiVersionName string, // Added missing parameter + resource v20231001preview.APIVersionResource, + options *v20231001preview.APIVersionsClientBeginCreateOrUpdateOptions, + ) (resp azfake.PollerResponder[v20231001preview.APIVersionsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { + // Simulate successful creation + result := v20231001preview.APIVersionsClientCreateOrUpdateResponse{ + APIVersionResource: resource, + } + resp.AddNonTerminalResponse(http.StatusCreated, nil) + resp.SetTerminalResponse(http.StatusOK, result, nil) + return + }, + } + + locationsServer := ucpfake.LocationsServer{ + BeginCreateOrUpdate: func( + ctx context.Context, + planeName string, + resourceProviderName string, + locationName string, + resource v20231001preview.LocationResource, + options *v20231001preview.LocationsClientBeginCreateOrUpdateOptions, + ) (resp azfake.PollerResponder[v20231001preview.LocationsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { + // Simulate successful creation + result := v20231001preview.LocationsClientCreateOrUpdateResponse{ + LocationResource: resource, + } + resp.AddNonTerminalResponse(http.StatusCreated, nil) + resp.SetTerminalResponse(http.StatusOK, result, nil) + + return + }, + } + + serverFactory := ucpfake.ServerFactory{ + ResourceProvidersServer: resourceProvidersServer, + ResourceTypesServer: resourceTypesServer, + APIVersionsServer: apiVersionsServer, + LocationsServer: locationsServer, + } + + serverFactoryTransport := ucpfake.NewServerFactoryTransport(&serverFactory) + + clientOptions := &armpolicy.ClientOptions{ + ClientOptions: policy.ClientOptions{ + Transport: serverFactoryTransport, + }, + } + + clientFactory, err := v20231001preview.NewClientFactory(&azfake.TokenCredential{}, clientOptions) + if err != nil { + return nil, err + } + + return clientFactory, err +} diff --git a/pkg/cli/manifest/registermanifest_test.go b/pkg/cli/manifest/registermanifest_test.go index 334398e152..8657f546c8 100644 --- a/pkg/cli/manifest/registermanifest_test.go +++ b/pkg/cli/manifest/registermanifest_test.go @@ -13,159 +13,20 @@ limitations under the License. package manifest import ( + "bytes" "context" - "net/http" + "fmt" "testing" // armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/radius-project/radius/pkg/to" - "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" - ucpfake "github.com/radius-project/radius/pkg/ucp/api/v20231001preview/fake" "github.com/stretchr/testify/require" ) -func NewTestClientFactory() (*v20231001preview.ClientFactory, error) { - - // Create fake servers for each client - resourceProvidersServer := ucpfake.ResourceProvidersServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resource v20231001preview.ResourceProviderResource, - options *v20231001preview.ResourceProvidersClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceProvidersClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - // Simulate successful creation - result := v20231001preview.ResourceProvidersClientCreateOrUpdateResponse{ - ResourceProviderResource: resource, - } - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - Get: func( - ctx context.Context, - planeName string, - resourceProviderName string, - options *v20231001preview.ResourceProvidersClientGetOptions, - ) (resp azfake.Responder[v20231001preview.ResourceProvidersClientGetResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.ResourceProvidersClientGetResponse{ - ResourceProviderResource: v20231001preview.ResourceProviderResource{ - Name: to.Ptr(resourceProviderName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - } - - // Create other fake servers similarly - resourceTypesServer := ucpfake.ResourceTypesServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - resource v20231001preview.ResourceTypeResource, - options *v20231001preview.ResourceTypesClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceTypesClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - result := v20231001preview.ResourceTypesClientCreateOrUpdateResponse{ - ResourceTypeResource: resource, - } - - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - Get: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - options *v20231001preview.ResourceTypesClientGetOptions, - ) (resp azfake.Responder[v20231001preview.ResourceTypesClientGetResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.ResourceTypesClientGetResponse{ - ResourceTypeResource: v20231001preview.ResourceTypeResource{ - Name: to.Ptr(resourceTypeName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - } - - apiVersionsServer := ucpfake.APIVersionsServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - apiVersionName string, // Added missing parameter - resource v20231001preview.APIVersionResource, - options *v20231001preview.APIVersionsClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.APIVersionsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - // Simulate successful creation - result := v20231001preview.APIVersionsClientCreateOrUpdateResponse{ - APIVersionResource: resource, - } - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - return - }, - } - - locationsServer := ucpfake.LocationsServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - locationName string, - resource v20231001preview.LocationResource, - options *v20231001preview.LocationsClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.LocationsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - // Simulate successful creation - result := v20231001preview.LocationsClientCreateOrUpdateResponse{ - LocationResource: resource, - } - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - } - - serverFactory := ucpfake.ServerFactory{ - ResourceProvidersServer: resourceProvidersServer, - ResourceTypesServer: resourceTypesServer, - APIVersionsServer: apiVersionsServer, - LocationsServer: locationsServer, - } - - serverFactoryTransport := ucpfake.NewServerFactoryTransport(&serverFactory) - - clientOptions := &armpolicy.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Transport: serverFactoryTransport, - }, - } - - clientFactory, err := v20231001preview.NewClientFactory(&azfake.TokenCredential{}, clientOptions) - if err != nil { - return nil, err - } - - return clientFactory, err -} - func TestRegisterDirectory(t *testing.T) { tests := []struct { name string - clientFactory func() (*v20231001preview.ClientFactory, error) planeName string directoryPath string expectError bool @@ -173,21 +34,15 @@ func TestRegisterDirectory(t *testing.T) { expectedResourceProvider string }{ { - name: "Success", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, + name: "Success", planeName: "local", - directoryPath: "testdata2", + directoryPath: "registerdirectory_testdata", expectError: false, expectedErrorMessage: "", expectedResourceProvider: "MyCompany2.CompanyName2", }, { - name: "EmptyDirectoryPath", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, + name: "EmptyDirectoryPath", planeName: "local", directoryPath: "", expectError: true, @@ -195,10 +50,7 @@ func TestRegisterDirectory(t *testing.T) { expectedResourceProvider: "", }, { - name: "InvalidDirectoryPath", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, + name: "InvalidDirectoryPath", planeName: "local", directoryPath: "#^$/invalid", expectError: true, @@ -206,36 +58,32 @@ func TestRegisterDirectory(t *testing.T) { expectedResourceProvider: "", }, { - name: "FilePathInsteadOfDirectory", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, + name: "FilePathInsteadOfDirectory", planeName: "local", directoryPath: "testdata/valid.yaml", expectError: true, - expectedErrorMessage: "manifest path testdata/valid.yaml is not a directory path", + expectedErrorMessage: "manifest path testdata/valid.yaml is not a directory", expectedResourceProvider: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - clientFactory, err := tt.clientFactory() - require.NoError(t, err, "Failed to create client factory") - logger := func(message string) {} + clientFactory, err := NewTestClientFactory() + require.NoError(t, err) - err = RegisterDirectory(context.Background(), *clientFactory, tt.planeName, tt.directoryPath, logger) + err = RegisterDirectory(context.Background(), clientFactory, tt.planeName, tt.directoryPath, nil) if tt.expectError { - require.Error(t, err, "Expected an error but got none") - require.Contains(t, err.Error(), tt.expectedErrorMessage, "Error message does not match") + require.Error(t, err) + require.Contains(t, err.Error(), tt.expectedErrorMessage) } else { - require.NoError(t, err, "Did not expect an error but got one") + require.NoError(t, err) // Verify the expected resource provider exists if tt.expectedResourceProvider != "" { rp, err := clientFactory.NewResourceProvidersClient().Get(context.Background(), tt.planeName, tt.expectedResourceProvider, nil) require.NoError(t, err, "Failed to retrieve the expected resource provider") - require.Equal(t, to.Ptr(tt.expectedResourceProvider), rp.Name, "Resource provider name does not match") + require.Equal(t, to.Ptr(tt.expectedResourceProvider), rp.Name) } } }) @@ -245,77 +93,62 @@ func TestRegisterDirectory(t *testing.T) { func TestRegisterFile(t *testing.T) { tests := []struct { name string - clientFactory func() (*v20231001preview.ClientFactory, error) planeName string filePath string expectError bool expectedErrorMessage string expectedResourceProvider string + expectedResourceTypeName string + expectedAPIVersion string }{ { - name: "Success", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, + name: "Success", planeName: "local", - filePath: "testdata2", + filePath: "registerdirectory_testdata/resourceprovider-valid2.yaml", expectError: false, expectedErrorMessage: "", expectedResourceProvider: "MyCompany2.CompanyName2", + expectedResourceTypeName: "testResource3", + expectedAPIVersion: "2025-01-01-preview", }, { - name: "EmptyDirectoryPath", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, + name: "EmptyDirectoryPath", planeName: "local", filePath: "", expectError: true, - expectedErrorMessage: "invalid manifest directory", - expectedResourceProvider: "", - }, - { - name: "InvalidDirectoryPath", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, - planeName: "local", - filePath: "#^$/invalid", - expectError: true, - expectedErrorMessage: "failed to access manifest path #^$/invalid: stat #^$/invalid: no such file or directory", - expectedResourceProvider: "", - }, - { - name: "FilePathInsteadOfDirectory", - clientFactory: func() (*v20231001preview.ClientFactory, error) { - return NewTestClientFactory() - }, - planeName: "local", - filePath: "testdata/valid.yaml", - expectError: true, - expectedErrorMessage: "manifest path testdata/valid.yaml is not a directory path", + expectedErrorMessage: "invalid manifest file path", expectedResourceProvider: "", + expectedResourceTypeName: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - clientFactory, err := tt.clientFactory() + + clientFactory, err := NewTestClientFactory() require.NoError(t, err, "Failed to create client factory") - logger := func(message string) {} - err = RegisterDirectory(context.Background(), *clientFactory, tt.planeName, tt.filePath, logger) + var logBuffer bytes.Buffer + logger := func(format string, args ...interface{}) { + fmt.Fprintf(&logBuffer, format+"\n", args...) + } + + err = RegisterFile(context.Background(), clientFactory, tt.planeName, tt.filePath, logger) if tt.expectError { - require.Error(t, err, "Expected an error but got none") - require.Contains(t, err.Error(), tt.expectedErrorMessage, "Error message does not match") + require.Error(t, err) + require.Contains(t, err.Error(), tt.expectedErrorMessage) } else { - require.NoError(t, err, "Did not expect an error but got one") + require.NoError(t, err) // Verify the expected resource provider exists if tt.expectedResourceProvider != "" { rp, err := clientFactory.NewResourceProvidersClient().Get(context.Background(), tt.planeName, tt.expectedResourceProvider, nil) require.NoError(t, err, "Failed to retrieve the expected resource provider") - require.Equal(t, to.Ptr(tt.expectedResourceProvider), rp.Name, "Resource provider name does not match") + require.Equal(t, to.Ptr(tt.expectedResourceProvider), rp.Name) + + logOutput := logBuffer.String() + require.Contains(t, logOutput, fmt.Sprintf("Creating resource type %s/%s", tt.expectedResourceProvider, tt.expectedResourceTypeName)) + require.Contains(t, logOutput, fmt.Sprintf("Creating API Version %s/%s@%s", tt.expectedResourceProvider, tt.expectedResourceTypeName, tt.expectedAPIVersion)) } } }) diff --git a/pkg/ucp/hostoptions/providerconfig.go b/pkg/ucp/hostoptions/providerconfig.go index 3145486877..09d68b52a6 100644 --- a/pkg/ucp/hostoptions/providerconfig.go +++ b/pkg/ucp/hostoptions/providerconfig.go @@ -42,7 +42,7 @@ type UCPConfig struct { UCP config.UCPOptions `yaml:"ucp"` Location string `yaml:"location"` Routing RoutingConfig `yaml:"routing"` - Manifests ManifestConfig `yaml:"manifests"` + Initialization InitializationConfig `yaml:"initialization"` } const ( @@ -65,8 +65,10 @@ type RoutingConfig struct { DefaultDownstreamEndpoint string `yaml:"defaultDownstreamEndpoint"` } -// ManifestConfig provides configuration for UCP manifests. -type ManifestConfig struct { +// InitializeConfig defines the configuration for initializing the UCP server. +// +// This includes resources that are added to UCP's data on startup. +type InitializationConfig struct { // ManifestDirectory is the directory where UCP manifests are stored. ManifestDirectory string `yaml:"manifestDirectory"` } diff --git a/pkg/ucp/manifestservice/service.go b/pkg/ucp/initializer/service.go similarity index 78% rename from pkg/ucp/manifestservice/service.go rename to pkg/ucp/initializer/service.go index da34017ce9..9da4e33d47 100644 --- a/pkg/ucp/manifestservice/service.go +++ b/pkg/ucp/initializer/service.go @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package manifestservice +package initializer import ( "context" "fmt" "net" + "net/url" "os" "time" @@ -50,7 +51,7 @@ func NewService(connection sdk.Connection, options ucpoptions.UCPConfig) *Servic // Name gets this service name. func (s *Service) Name() string { - return "manifestservice" + return "initializer" } func waitForServer(ctx context.Context, host, port string, retryInterval time.Duration, timeout time.Duration) error { @@ -80,19 +81,31 @@ func waitForServer(ctx context.Context, host, port string, retryInterval time.Du func (w *Service) Run(ctx context.Context) error { logger := ucplog.FromContextOrDiscard(ctx) - // Define connection parameters - hostName := "localhost" //w.ucpConnection.Endpoint()/split to get host? // Replace with actual method - port := "9000" // extract from endpoint Replace with actual method + if w.ucpConnection == nil || w.ucpConnection.Endpoint() == "" { + return fmt.Errorf("connection to UCP is not set") + } + + // Parse the endpoint URL and extract host and port + parsedURL, err := url.Parse(w.ucpConnection.Endpoint()) + if err != nil { + return fmt.Errorf("failed to parse endpoint URL: %w", err) + } + + hostName, port, err := net.SplitHostPort(parsedURL.Host) + if err != nil { + return fmt.Errorf("failed to split host and port: %w", err) + } + logger.Info("Parsed Host and Port", "host", hostName, "port", port) // Attempt to connect to the server - err := waitForServer(ctx, hostName, port, 500*time.Millisecond, 5*time.Second) + err = waitForServer(ctx, hostName, port, 500*time.Millisecond, 5*time.Second) if err != nil { logger.Error(err, "Server is not available for manifest registration") return nil } // Server is up, proceed to register manifests - manifestDir := w.options.Manifests.ManifestDirectory + manifestDir := w.options.Initialization.ManifestDirectory if manifestDir == "" { logger.Info("No manifest directory specified") return nil @@ -113,9 +126,8 @@ func (w *Service) Run(ctx context.Context) error { } // Proceed with registering manifests - if err := manifest.RegisterDirectory(ctx, *clientFactory, "local", manifestDir, nil); err != nil { - logger.Error(err, "Failed to register manifests") - return nil + if err := manifest.RegisterDirectory(ctx, clientFactory, "local", manifestDir, nil); err != nil { + return fmt.Errorf("error registering manifests : %w", err) } logger.Info("Successfully registered manifests", "directory", manifestDir) diff --git a/pkg/ucp/server/server.go b/pkg/ucp/server/server.go index 5d414e0357..6e9b521d33 100644 --- a/pkg/ucp/server/server.go +++ b/pkg/ucp/server/server.go @@ -38,8 +38,8 @@ import ( "github.com/radius-project/radius/pkg/ucp/frontend/api" "github.com/radius-project/radius/pkg/ucp/hosting" "github.com/radius-project/radius/pkg/ucp/hostoptions" + "github.com/radius-project/radius/pkg/ucp/initializer" - "github.com/radius-project/radius/pkg/ucp/manifestservice" qprovider "github.com/radius-project/radius/pkg/ucp/queue/provider" "github.com/radius-project/radius/pkg/ucp/rest" "github.com/radius-project/radius/pkg/ucp/secret/provider" @@ -206,7 +206,7 @@ func NewServer(options *Options) (*hosting.Host, error) { options.TracerProviderOptions.ServiceName = "ucp" hostingServices = append(hostingServices, &trace.Service{Options: options.TracerProviderOptions}) - hostingServices = append(hostingServices, manifestservice.NewService(options.UCPConnection, *options.Config)) + hostingServices = append(hostingServices, initializer.NewService(options.UCPConnection, *options.Config)) return &hosting.Host{ Services: hostingServices, diff --git a/pkg/ucp/ucpclient/locations_fake_test_notneeded.go b/pkg/ucp/ucpclient/locations_fake_test_notneeded.go deleted file mode 100644 index 25068129e3..0000000000 --- a/pkg/ucp/ucpclient/locations_fake_test_notneeded.go +++ /dev/null @@ -1,149 +0,0 @@ -package ucpclient - -import ( - "context" - "net/http" - "testing" - - armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" - "github.com/stretchr/testify/require" - - v20231001preview "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" - "github.com/radius-project/radius/pkg/ucp/api/v20231001preview/fake" -) - -func TestLocationsServer(t *testing.T) { - // Initialize the fake LocationsServer with method implementations. - srv := &fake.LocationsServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - locationName string, - resource v20231001preview.LocationResource, - options *v20231001preview.LocationsClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.LocationsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - // Create the response object. - result := v20231001preview.LocationsClientCreateOrUpdateResponse{ - LocationResource: resource, - } - - // Create a PollerResponder to simulate a long-running operation (LRO). - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - Get: func( - ctx context.Context, - planeName string, - resourceProviderName string, - locationName string, - options *v20231001preview.LocationsClientGetOptions, - ) (resp azfake.Responder[v20231001preview.LocationsClientGetResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.LocationsClientGetResponse{ - LocationResource: v20231001preview.LocationResource{ - Name: to.Ptr(locationName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - BeginDelete: func( - ctx context.Context, - planeName string, - resourceProviderName string, - locationName string, - options *v20231001preview.LocationsClientBeginDeleteOptions, - ) (resp azfake.PollerResponder[v20231001preview.LocationsClientDeleteResponse], errResp azfake.ErrorResponder) { - // Create the response object. - result := v20231001preview.LocationsClientDeleteResponse{} - - resp.AddNonTerminalResponse(http.StatusNoContent, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - return - }, - NewListPager: func( - planeName string, - resourceProviderName string, - options *v20231001preview.LocationsClientListOptions, - ) (resp azfake.PagerResponder[v20231001preview.LocationsClientListResponse]) { - // Simulate paging with two pages of results. - page1 := v20231001preview.LocationsClientListResponse{ - LocationResourceListResult: v20231001preview.LocationResourceListResult{ - Value: []*v20231001preview.LocationResource{ - {Name: to.Ptr("location1")}, - {Name: to.Ptr("location2")}, - }, - NextLink: to.Ptr("nextPageLink"), - }, - } - page2 := v20231001preview.LocationsClientListResponse{ - LocationResourceListResult: v20231001preview.LocationResourceListResult{ - Value: []*v20231001preview.LocationResource{ - {Name: to.Ptr("location3")}, - }, - }, - } - resp.AddPage(http.StatusOK, page1, nil) - resp.AddPage(http.StatusOK, page2, nil) - return - }, - } - - // Create a fake transport using the LocationsServer. - transport := fake.NewLocationsServerTransport(srv) - - // Set up client options with the fake transport. - clientOptions := &armpolicy.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Transport: transport, - }, - } - - // Create the LocationsClient with the fake transport and mock credential. - client, err := v20231001preview.NewLocationsClient(&azfake.TokenCredential{}, clientOptions) - require.NoError(t, err) - - ctx := context.Background() - planeName := "testPlane" - resourceProviderName := "testResourceProvider" - locationName := "testLocation" - resource := v20231001preview.LocationResource{ - Name: to.Ptr(locationName), - } - - // Call BeginCreateOrUpdate and poll until completion. - pollerResp, err := client.BeginCreateOrUpdate(ctx, planeName, resourceProviderName, locationName, resource, nil) - require.NoError(t, err) - finalResp, err := pollerResp.PollUntilDone(ctx, nil) - require.NoError(t, err) - require.Equal(t, locationName, *finalResp.Name) - - // Call Get. - getResp, err := client.Get(ctx, planeName, resourceProviderName, locationName, nil) - require.NoError(t, err) - require.Equal(t, locationName, *getResp.Name) - - // Call BeginDelete and poll until completion. - deletePollerResp, err := client.BeginDelete(ctx, planeName, resourceProviderName, locationName, nil) - require.NoError(t, err) - _, err = deletePollerResp.PollUntilDone(ctx, nil) - require.NoError(t, err) - - // Call NewListPager. - pager := client.NewListPager(planeName, resourceProviderName, nil) - var locations []*v20231001preview.LocationResource - for pager.More() { - page, err := pager.NextPage(ctx) - require.NoError(t, err) - locations = append(locations, page.Value...) - } - require.Len(t, locations, 3) - require.Equal(t, "location1", *locations[0].Name) - require.Equal(t, "location2", *locations[1].Name) - require.Equal(t, "location3", *locations[2].Name) -} diff --git a/pkg/ucp/ucpclient/registermanifests.go b/pkg/ucp/ucpclient/registermanifests.go deleted file mode 100644 index cc0b447fe5..0000000000 --- a/pkg/ucp/ucpclient/registermanifests.go +++ /dev/null @@ -1,151 +0,0 @@ -/* -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 ucpclient - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - - "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" - aztoken "github.com/radius-project/radius/pkg/azure/tokencredentials" - "github.com/radius-project/radius/pkg/cli/manifest" - "github.com/radius-project/radius/pkg/sdk" - "github.com/radius-project/radius/pkg/to" - "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" -) - -type UCPClientImpl struct { - Options *policy.ClientOptions -} - -func NewUCPClient(UCPConnection sdk.Connection) (*UCPClient, error) { - if UCPConnection == nil { - return nil, errors.New("UCP connection is nil") - } - - clientOptions := sdk.NewClientOptions(UCPConnection) - - resourceProvidersClient, err := v20231001preview.NewResourceProvidersClient(&aztoken.AnonymousCredential{}, clientOptions) - if err != nil { - return nil, fmt.Errorf("failed to create ResourceProvidersClient: %w", err) - } - - resourceTypesClient, err := v20231001preview.NewResourceTypesClient(&aztoken.AnonymousCredential{}, clientOptions) - if err != nil { - return nil, fmt.Errorf("failed to create ResourceTypeResource: %w", err) - } - - apiVersionsClient, err := v20231001preview.NewAPIVersionsClient(&aztoken.AnonymousCredential{}, clientOptions) - if err != nil { - return nil, fmt.Errorf("failed to create APIVersionResource: %w", err) - } - - locationsClient, err := v20231001preview.NewLocationsClient(&aztoken.AnonymousCredential{}, clientOptions) - if err != nil { - return nil, fmt.Errorf("failed to create LocationResource: %w", err) - } - - return &UCPClient{ - ResourceProvidersClient: resourceProvidersClient, - ResourceTypesClient: resourceTypesClient, - APIVersionsClient: apiVersionsClient, - LocationsClient: locationsClient, - }, nil -} - -func (u *UCPClient) RegisterManifests(ctx context.Context, manifestDirectory string) error { - - // loop thru files in the directory - //manifestDirectory := u.Options.Config.Manifests.ManifestDirectory - if manifestDirectory == "" { - return fmt.Errorf("invalid manifest directory") - } - - // List all files in the manifestDirectory - files, err := os.ReadDir(manifestDirectory) - if err != nil { - return err - } - - // Iterate over each file in the directory - for _, fileInfo := range files { - if fileInfo.IsDir() { - continue // Skip directories - TBD: check if want to include subdirectories - } - filePath := filepath.Join(manifestDirectory, fileInfo.Name()) - - // Read the manifest file - resourceProvider, err := manifest.ReadFile(filePath) - if err != nil { - return err - } - - _, err = u.CreateOrUpdateResourceProvider(ctx, planeName, resourceProvider.Name, &v20231001preview.ResourceProviderResource{ - Location: to.Ptr(v1.LocationGlobal), - Properties: &v20231001preview.ResourceProviderProperties{}, - }) - if err != nil { - return err - } - - // The location resource contains references to all of the resource types and API versions that the resource provider supports. - // We're instantiating the struct here so we can update it as we loop. - locationResource := v20231001preview.LocationResource{ - Properties: &v20231001preview.LocationProperties{ - ResourceTypes: map[string]*v20231001preview.LocationResourceType{}, - }, - } - - for resourceTypeName, resourceType := range resourceProvider.Types { - _, err := u.CreateOrUpdateResourceType(ctx, planeName, resourceProvider.Name, resourceTypeName, &v20231001preview.ResourceTypeResource{ - Properties: &v20231001preview.ResourceTypeProperties{ - DefaultAPIVersion: resourceType.DefaultAPIVersion, - }, - }) - if err != nil { - return err - } - - locationResourceType := &v20231001preview.LocationResourceType{ - APIVersions: map[string]map[string]any{}, - } - - for apiVersionName := range resourceType.APIVersions { - _, err := u.CreateOrUpdateAPIVersion(ctx, planeName, resourceProvider.Name, resourceTypeName, apiVersionName, &v20231001preview.APIVersionResource{ - Properties: &v20231001preview.APIVersionProperties{}, - }) - if err != nil { - return err - } - - locationResourceType.APIVersions[apiVersionName] = map[string]any{} - } - - locationResource.Properties.ResourceTypes[resourceTypeName] = locationResourceType - } - - _, err = u.CreateOrUpdateLocation(ctx, planeName, resourceProvider.Name, v1.LocationGlobal, &locationResource) - if err != nil { - return err - } - - _, err = u.GetResourceProvider(ctx, planeName, resourceProvider.Name) - if err != nil { - return err - } - } - return nil -} diff --git a/pkg/ucp/ucpclient/registermanifests_test.go b/pkg/ucp/ucpclient/registermanifests_test.go deleted file mode 100644 index ab4beb540a..0000000000 --- a/pkg/ucp/ucpclient/registermanifests_test.go +++ /dev/null @@ -1,266 +0,0 @@ -/* -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 ucpclient - -import ( - "context" - "fmt" - "net/http" - "testing" - - // armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/radius-project/radius/pkg/to" - "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" - ucpfake "github.com/radius-project/radius/pkg/ucp/api/v20231001preview/fake" - "github.com/stretchr/testify/require" -) - -type FakeUCPServer struct { - ResourceProvidersServer *ucpfake.ResourceProvidersServer - ResourceTypesServer *ucpfake.ResourceTypesServer - APIVersionsServer *ucpfake.APIVersionsServer - LocationsServer *ucpfake.LocationsServer -} - -func NewFakeUCPServer() (*FakeUCPServer, error) { - - // Create fake servers for each client - resourceProvidersServer := &ucpfake.ResourceProvidersServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resource v20231001preview.ResourceProviderResource, - options *v20231001preview.ResourceProvidersClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceProvidersClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - // Simulate successful creation - result := v20231001preview.ResourceProvidersClientCreateOrUpdateResponse{ - ResourceProviderResource: resource, - } - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - Get: func( - ctx context.Context, - planeName string, - resourceProviderName string, - options *v20231001preview.ResourceProvidersClientGetOptions, - ) (resp azfake.Responder[v20231001preview.ResourceProvidersClientGetResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.ResourceProvidersClientGetResponse{ - ResourceProviderResource: v20231001preview.ResourceProviderResource{ - Name: to.Ptr(resourceProviderName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - } - - // Create other fake servers similarly - resourceTypesServer := &ucpfake.ResourceTypesServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - resource v20231001preview.ResourceTypeResource, - options *v20231001preview.ResourceTypesClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceTypesClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - result := v20231001preview.ResourceTypesClientCreateOrUpdateResponse{ - ResourceTypeResource: resource, - } - - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - Get: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - options *v20231001preview.ResourceTypesClientGetOptions, - ) (resp azfake.Responder[v20231001preview.ResourceTypesClientGetResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.ResourceTypesClientGetResponse{ - ResourceTypeResource: v20231001preview.ResourceTypeResource{ - Name: to.Ptr(resourceTypeName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - } - - apiVersionsServer := &ucpfake.APIVersionsServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - apiVersionName string, // Added missing parameter - resource v20231001preview.APIVersionResource, - options *v20231001preview.APIVersionsClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.APIVersionsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - // Simulate successful creation - result := v20231001preview.APIVersionsClientCreateOrUpdateResponse{ - APIVersionResource: resource, - } - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - return - }, - } - - locationsServer := &ucpfake.LocationsServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - locationName string, - resource v20231001preview.LocationResource, - options *v20231001preview.LocationsClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.LocationsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - // Simulate successful creation - result := v20231001preview.LocationsClientCreateOrUpdateResponse{ - LocationResource: resource, - } - resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - } - - // Return the FakeUCPClient instance - return &FakeUCPServer{ - ResourceProvidersServer: resourceProvidersServer, - ResourceTypesServer: resourceTypesServer, - APIVersionsServer: apiVersionsServer, - LocationsServer: locationsServer, - /*UCPClient: ucpClient, - - ResourceProvidersClient: *resourceProvidersClient, - ResourceTypesClient: *resourceTypesClient, - APIVersionsClient: *apiVersionsClient, - LocationsClient: *locationsClient, - */ - }, nil -} - -func NewTestUCPClient(server *FakeUCPServer) (*UCPClient, error) { - - // Create individual transports for each fake server - resourceProvidersTransport := ucpfake.NewResourceProvidersServerTransport(server.ResourceProvidersServer) - resourceTypesTransport := ucpfake.NewResourceTypesServerTransport(server.ResourceTypesServer) - apiVersionsTransport := ucpfake.NewAPIVersionsServerTransport(server.APIVersionsServer) - locationsTransport := ucpfake.NewLocationsServerTransport(server.LocationsServer) - - // Configure client options with respective transports - resourceProvidersOptions := &armpolicy.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Transport: resourceProvidersTransport, - }, - } - - resourceTypesOptions := &armpolicy.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Transport: resourceTypesTransport, - }, - } - - apiVersionsOptions := &armpolicy.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Transport: apiVersionsTransport, - }, - } - - locationsOptions := &armpolicy.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Transport: locationsTransport, - }, - } - - credential := &azfake.TokenCredential{} - - resourceProvidersClient, err := v20231001preview.NewResourceProvidersClient(credential, resourceProvidersOptions) - if err != nil { - return nil, fmt.Errorf("failed to create fake ResourceProvidersClient: %w", err) - } - - resourceTypesClient, err := v20231001preview.NewResourceTypesClient(credential, resourceTypesOptions) - if err != nil { - return nil, fmt.Errorf("failed to create fake ResourceTypesClient: %w", err) - } - - apiVersionsClient, err := v20231001preview.NewAPIVersionsClient(credential, apiVersionsOptions) - if err != nil { - return nil, fmt.Errorf("failed to create fake APIVersionsClient: %w", err) - } - - locationsClient, err := v20231001preview.NewLocationsClient(credential, locationsOptions) - if err != nil { - return nil, fmt.Errorf("failed to create fake LocationsClient: %w", err) - } - - return &UCPClient{ - ResourceProvidersClient: resourceProvidersClient, - ResourceTypesClient: resourceTypesClient, - APIVersionsClient: apiVersionsClient, - LocationsClient: locationsClient, - }, nil -} - -func TestRegisterManifests_Success(t *testing.T) { - ctx := context.Background() - expectedResourceProvider := "MyCompany2.CompanyName2" - - // Setup fake UCP server - server, err := NewFakeUCPServer() - require.NoError(t, err) - - // Setup UCP client with fake servers - client, err := NewTestUCPClient(server) - require.NoError(t, err) - - err = client.RegisterManifests(ctx, "testdata") - require.NoError(t, err) - - // Verify resource provider was created - rp, err := client.GetResourceProvider(ctx, planeName, expectedResourceProvider) - require.NoError(t, err) - require.Equal(t, to.Ptr(expectedResourceProvider), rp.Name) - -} - -func TestRegisterManifests_InvalidParameters(t *testing.T) { - ctx := context.Background() - - // Setup fake UCP server - server, err := NewFakeUCPServer() - require.NoError(t, err) - - // Setup UCP client with fake servers - client, err := NewTestUCPClient(server) - require.NoError(t, err) - - // Pass invalid manifest directory - err = client.RegisterManifests(ctx, "") - require.Error(t, err) - require.Contains(t, err.Error(), "invalid manifest directory") -} diff --git a/pkg/ucp/ucpclient/resourceproviders_fakes_test_notneeded.go b/pkg/ucp/ucpclient/resourceproviders_fakes_test_notneeded.go deleted file mode 100644 index 0e08277d44..0000000000 --- a/pkg/ucp/ucpclient/resourceproviders_fakes_test_notneeded.go +++ /dev/null @@ -1,159 +0,0 @@ -package ucpclient - -import ( - "context" - "net/http" - "testing" - - armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" - "github.com/stretchr/testify/require" - - v20231001preview "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" - "github.com/radius-project/radius/pkg/ucp/api/v20231001preview/fake" -) - -func TestResourceProvidersServer(t *testing.T) { - // Initialize the fake ResourceProvidersServer with method implementations. - srv := &fake.ResourceProvidersServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resource v20231001preview.ResourceProviderResource, - options *v20231001preview.ResourceProvidersClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceProvidersClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - result := v20231001preview.ResourceProvidersClientCreateOrUpdateResponse{ - ResourceProviderResource: resource, - } - - // resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - Get: func( - ctx context.Context, - planeName string, - resourceProviderName string, - options *v20231001preview.ResourceProvidersClientGetOptions, - ) (resp azfake.Responder[v20231001preview.ResourceProvidersClientGetResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.ResourceProvidersClientGetResponse{ - ResourceProviderResource: v20231001preview.ResourceProviderResource{ - Name: to.Ptr(resourceProviderName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - BeginDelete: func( - ctx context.Context, - planeName string, - resourceProviderName string, - options *v20231001preview.ResourceProvidersClientBeginDeleteOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceProvidersClientDeleteResponse], errResp azfake.ErrorResponder) { - // Simulate a delete operation with a final response. - result := v20231001preview.ResourceProvidersClientDeleteResponse{} - - // resp.AddNonTerminalResponse(http.StatusCreated, nil) - resp.SetTerminalResponse(http.StatusOK, result, nil) - return - }, - // Updated NewListPager method - NewListPager: func( - planeName string, - options *v20231001preview.ResourceProvidersClientListOptions, - ) (resp azfake.PagerResponder[v20231001preview.ResourceProvidersClientListResponse]) { - // Simulate paging with two pages of results. - page1 := v20231001preview.ResourceProvidersClientListResponse{ - ResourceProviderResourceListResult: v20231001preview.ResourceProviderResourceListResult{ - Value: []*v20231001preview.ResourceProviderResource{ - {Name: to.Ptr("resourceProvider1")}, - {Name: to.Ptr("resourceProvider2")}, - }, - NextLink: to.Ptr("nextPageLink"), - }, - } - page2 := v20231001preview.ResourceProvidersClientListResponse{ - ResourceProviderResourceListResult: v20231001preview.ResourceProviderResourceListResult{ - Value: []*v20231001preview.ResourceProviderResource{ - {Name: to.Ptr("resourceProvider3")}, - }, - }, - } - resp.AddPage(http.StatusOK, page1, nil) - resp.AddPage(http.StatusOK, page2, nil) - return - }, - GetProviderSummary: func( - ctx context.Context, - planeName string, - resourceProviderName string, - options *v20231001preview.ResourceProvidersClientGetProviderSummaryOptions, - ) (resp azfake.Responder[v20231001preview.ResourceProvidersClientGetProviderSummaryResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.ResourceProvidersClientGetProviderSummaryResponse{ - ResourceProviderSummary: v20231001preview.ResourceProviderSummary{ - Name: to.Ptr(resourceProviderName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - } - - // Create a fake transport using the ResourceProvidersServer. - transport := fake.NewResourceProvidersServerTransport(srv) - clientOptions := &armpolicy.ClientOptions{ClientOptions: policy.ClientOptions{ - Transport: transport, - }} - - // Create the ResourceProvidersClient with the fake transport. - client, err := v20231001preview.NewResourceProvidersClient(&azfake.TokenCredential{}, clientOptions) - require.NoError(t, err) - - ctx := context.Background() - planeName := planeName - resourceProviderName := "testResourceProvider" - resource := v20231001preview.ResourceProviderResource{ - Name: to.Ptr(resourceProviderName), - } - - // Call BeginCreateOrUpdate and poll until completion. - pollerResp, err := client.BeginCreateOrUpdate(ctx, planeName, resourceProviderName, resource, nil) - require.NoError(t, err) - _, err = pollerResp.PollUntilDone(ctx, nil) - require.NoError(t, err) - - // Call Get. - getResp, err := client.Get(ctx, planeName, resourceProviderName, nil) - require.NoError(t, err) - require.Equal(t, resourceProviderName, *getResp.Name) - - // Call BeginDelete and poll until completion. - deletePollerResp, err := client.BeginDelete(ctx, planeName, resourceProviderName, nil) - require.NoError(t, err) - _, err = deletePollerResp.PollUntilDone(ctx, nil) - require.NoError(t, err) - - // Call NewListPager. - pager := client.NewListPager(planeName, nil) - var resources []*v20231001preview.ResourceProviderResource - - for pager.More() { - page, err := pager.NextPage(ctx) - require.NoError(t, err) - resources = append(resources, page.Value...) - } - - require.Len(t, resources, 3) - require.Equal(t, "resourceProvider1", *resources[0].Name) - require.Equal(t, "resourceProvider2", *resources[1].Name) - require.Equal(t, "resourceProvider3", *resources[2].Name) - - // Call GetProviderSummary. - summaryResp, err := client.GetProviderSummary(ctx, planeName, resourceProviderName, nil) - require.NoError(t, err) - require.Equal(t, resourceProviderName, *summaryResp.Name) -} diff --git a/pkg/ucp/ucpclient/resourcetypes_fake_test_notneeded.go b/pkg/ucp/ucpclient/resourcetypes_fake_test_notneeded.go deleted file mode 100644 index cb06d7eaf2..0000000000 --- a/pkg/ucp/ucpclient/resourcetypes_fake_test_notneeded.go +++ /dev/null @@ -1,148 +0,0 @@ -package ucpclient - -import ( - "context" - "net/http" - "testing" - - armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" - azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" - "github.com/stretchr/testify/require" - - v20231001preview "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" - "github.com/radius-project/radius/pkg/ucp/api/v20231001preview/fake" -) - -func TestResourceTypesServer(t *testing.T) { - // Initialize the fake ResourceTypesServer with method implementations. - srv := &fake.ResourceTypesServer{ - BeginCreateOrUpdate: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - resource v20231001preview.ResourceTypeResource, - options *v20231001preview.ResourceTypesClientBeginCreateOrUpdateOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceTypesClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) { - result := v20231001preview.ResourceTypesClientCreateOrUpdateResponse{ - ResourceTypeResource: resource, - } - - // Create a PollerResponder to simulate a long-running operation (LRO) - resp.SetTerminalResponse(http.StatusOK, result, nil) - - return - }, - Get: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - options *v20231001preview.ResourceTypesClientGetOptions, - ) (resp azfake.Responder[v20231001preview.ResourceTypesClientGetResponse], errResp azfake.ErrorResponder) { - response := v20231001preview.ResourceTypesClientGetResponse{ - ResourceTypeResource: v20231001preview.ResourceTypeResource{ - Name: to.Ptr(resourceTypeName), - }, - } - resp.SetResponse(http.StatusOK, response, nil) - return - }, - BeginDelete: func( - ctx context.Context, - planeName string, - resourceProviderName string, - resourceTypeName string, - options *v20231001preview.ResourceTypesClientBeginDeleteOptions, - ) (resp azfake.PollerResponder[v20231001preview.ResourceTypesClientDeleteResponse], errResp azfake.ErrorResponder) { - // Create the response object - result := v20231001preview.ResourceTypesClientDeleteResponse{} - // Create a PollerResponder to simulate a long-running operation (LRO) - resp.AddNonTerminalResponse(http.StatusAccepted, nil) - resp.SetTerminalResponse(http.StatusNoContent, result, nil) - - return - }, - NewListPager: func( - planeName string, - resourceProviderName string, - options *v20231001preview.ResourceTypesClientListOptions, - ) (resp azfake.PagerResponder[v20231001preview.ResourceTypesClientListResponse]) { - // Simulate paging with two pages of results. - page1 := v20231001preview.ResourceTypesClientListResponse{ - ResourceTypeResourceListResult: v20231001preview.ResourceTypeResourceListResult{ - Value: []*v20231001preview.ResourceTypeResource{ - {Name: to.Ptr("resourceType1")}, - {Name: to.Ptr("resourceType2")}, - }, - NextLink: to.Ptr("nextPageLink"), - }, - } - page2 := v20231001preview.ResourceTypesClientListResponse{ - ResourceTypeResourceListResult: v20231001preview.ResourceTypeResourceListResult{ - Value: []*v20231001preview.ResourceTypeResource{ - {Name: to.Ptr("resourceType3")}, - }, - }, - } - resp.AddPage(http.StatusOK, page1, nil) - resp.AddPage(http.StatusOK, page2, nil) - return - }, - } - - // Create a fake transport using the ResourceTypesServer. - transport := fake.NewResourceTypesServerTransport(srv) - - // Set up client options with the fake transport. - clientOptions := &armpolicy.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Transport: transport, - }, - } - - // Create the ResourceTypesClient with the fake transport and mock credential. - client, err := v20231001preview.NewResourceTypesClient(&azfake.TokenCredential{}, clientOptions) - require.NoError(t, err) - - ctx := context.Background() - planeName := planeName - resourceProviderName := "testResourceProvider" - resourceTypeName := "testResourceType" - resource := v20231001preview.ResourceTypeResource{ - Name: to.Ptr(resourceTypeName), - } - - // Call BeginCreateOrUpdate and poll until completion. - pollerResp, err := client.BeginCreateOrUpdate(ctx, planeName, resourceProviderName, resourceTypeName, resource, nil) - require.NoError(t, err) - finalResp, err := pollerResp.PollUntilDone(ctx, nil) - require.NoError(t, err) - require.Equal(t, resourceTypeName, *finalResp.Name) - - // Call Get. - getResp, err := client.Get(ctx, planeName, resourceProviderName, resourceTypeName, nil) - require.NoError(t, err) - require.Equal(t, resourceTypeName, *getResp.Name) - - // Call BeginDelete and poll until completion. - deletePollerResp, err := client.BeginDelete(ctx, planeName, resourceProviderName, resourceTypeName, nil) - require.NoError(t, err) - _, err = deletePollerResp.PollUntilDone(ctx, nil) - require.NoError(t, err) - - // Call NewListPager. - pager := client.NewListPager(planeName, resourceProviderName, nil) - var resources []*v20231001preview.ResourceTypeResource - for pager.More() { - page, err := pager.NextPage(ctx) - require.NoError(t, err) - resources = append(resources, page.Value...) - } - require.Len(t, resources, 3) - require.Equal(t, "resourceType1", *resources[0].Name) - require.Equal(t, "resourceType2", *resources[1].Name) - require.Equal(t, "resourceType3", *resources[2].Name) -} diff --git a/pkg/ucp/ucpclient/testdata/test1.yaml b/pkg/ucp/ucpclient/testdata/test1.yaml deleted file mode 100644 index b76f369047..0000000000 --- a/pkg/ucp/ucpclient/testdata/test1.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: MyCompany.CompanyName -types: - testResource1: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: [] - testResource2: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: [] diff --git a/pkg/ucp/ucpclient/testdata/test2.yaml b/pkg/ucp/ucpclient/testdata/test2.yaml deleted file mode 100644 index 3ef2b3ffcc..0000000000 --- a/pkg/ucp/ucpclient/testdata/test2.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: MyCompany2.CompanyName2 -types: - testResource3: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: ["Recipes"] - testResource4: - apiVersions: - "2025-01-01-preview": - schema: {} - capabilities: ["Recipes"] diff --git a/pkg/ucp/ucpclient/ucpclient.go b/pkg/ucp/ucpclient/ucpclient.go deleted file mode 100644 index 0e1efa2e8d..0000000000 --- a/pkg/ucp/ucpclient/ucpclient.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -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 ucpclient - -import ( - "context" - "fmt" - - ucpv20231001 "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" -) - -const planeName = "local" - -// UCPClient holds instances of each specific client. -type UCPClient struct { - ResourceProvidersClient *ucpv20231001.ResourceProvidersClient - ResourceTypesClient *ucpv20231001.ResourceTypesClient - APIVersionsClient *ucpv20231001.APIVersionsClient - LocationsClient *ucpv20231001.LocationsClient - // Add other clients as needed -} - -// CreateOrUpdateResourceProvider creates or updates a resource provider in the configured scope. -func (u *UCPClient) CreateOrUpdateResourceProvider(ctx context.Context, planeName string, resourceProviderName string, resource *ucpv20231001.ResourceProviderResource) (ucpv20231001.ResourceProviderResource, error) { - if u.ResourceProvidersClient == nil { - return ucpv20231001.ResourceProviderResource{}, fmt.Errorf("ResourceProvidersClient is nil") - } - - poller, err := u.ResourceProvidersClient.BeginCreateOrUpdate(ctx, planeName, resourceProviderName, *resource, &ucpv20231001.ResourceProvidersClientBeginCreateOrUpdateOptions{}) - if err != nil { - return ucpv20231001.ResourceProviderResource{}, fmt.Errorf("begin create or update failed: %w", err) - } - - response, err := poller.PollUntilDone(ctx, nil) - if err != nil { - return ucpv20231001.ResourceProviderResource{}, fmt.Errorf("poll until done failed: %w", err) - } - - return response.ResourceProviderResource, nil -} - -// CreateOrUpdateResourceType creates or updates a resource type in the configured scope. -func (u *UCPClient) CreateOrUpdateResourceType(ctx context.Context, planeName string, resourceProviderName string, resourceTypeName string, resource *ucpv20231001.ResourceTypeResource) (ucpv20231001.ResourceTypeResource, error) { - if u.ResourceTypesClient == nil { - return ucpv20231001.ResourceTypeResource{}, fmt.Errorf("ResourceTypeResource is nil") - } - - poller, err := u.ResourceTypesClient.BeginCreateOrUpdate(ctx, planeName, resourceProviderName, resourceTypeName, *resource, &ucpv20231001.ResourceTypesClientBeginCreateOrUpdateOptions{}) - if err != nil { - return ucpv20231001.ResourceTypeResource{}, err - } - - response, err := poller.PollUntilDone(ctx, nil) - if err != nil { - return ucpv20231001.ResourceTypeResource{}, err - } - - return response.ResourceTypeResource, nil -} - -// CreateOrUpdateAPIVersion creates or updates an API version in the configured scope. -func (u *UCPClient) CreateOrUpdateAPIVersion(ctx context.Context, planeName string, resourceProviderName string, resourceTypeName string, apiVersionName string, resource *ucpv20231001.APIVersionResource) (ucpv20231001.APIVersionResource, error) { - if u.APIVersionsClient == nil { - return ucpv20231001.APIVersionResource{}, fmt.Errorf("APIVersionResource is nil") - } - - poller, err := u.APIVersionsClient.BeginCreateOrUpdate(ctx, planeName, resourceProviderName, resourceTypeName, apiVersionName, *resource, &ucpv20231001.APIVersionsClientBeginCreateOrUpdateOptions{}) - if err != nil { - return ucpv20231001.APIVersionResource{}, err - } - - response, err := poller.PollUntilDone(ctx, nil) - if err != nil { - return ucpv20231001.APIVersionResource{}, err - } - - return response.APIVersionResource, nil -} - -// CreateOrUpdateLocation creates or updates a resource provider location in the configured scope. -func (u *UCPClient) CreateOrUpdateLocation(ctx context.Context, planeName string, resourceProviderName string, locationName string, resource *ucpv20231001.LocationResource) (ucpv20231001.LocationResource, error) { - if u.LocationsClient == nil { - return ucpv20231001.LocationResource{}, fmt.Errorf("LocationResource is nil") - } - - poller, err := u.LocationsClient.BeginCreateOrUpdate(ctx, planeName, resourceProviderName, locationName, *resource, &ucpv20231001.LocationsClientBeginCreateOrUpdateOptions{}) - if err != nil { - return ucpv20231001.LocationResource{}, err - } - - response, err := poller.PollUntilDone(ctx, nil) - if err != nil { - return ucpv20231001.LocationResource{}, err - } - - return response.LocationResource, nil -} - -// GetResourceProvider gets the resource provider with the specified name in the configured scope. -func (u *UCPClient) GetResourceProvider(ctx context.Context, planeName string, resourceProviderName string) (ucpv20231001.ResourceProviderResource, error) { - if u.ResourceProvidersClient == nil { - return ucpv20231001.ResourceProviderResource{}, fmt.Errorf("ResourceProvidersClient is nil") - } - - response, err := u.ResourceProvidersClient.Get(ctx, planeName, resourceProviderName, &ucpv20231001.ResourceProvidersClientGetOptions{}) - if err != nil { - return ucpv20231001.ResourceProviderResource{}, err - } - - return response.ResourceProviderResource, nil -} diff --git a/pkg/ucp/ucpclient/ucpclient_test.go b/pkg/ucp/ucpclient/ucpclient_test.go deleted file mode 100644 index 43a100cf1a..0000000000 --- a/pkg/ucp/ucpclient/ucpclient_test.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -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 ucpclient - -import ( - "context" - "testing" - - "github.com/radius-project/radius/pkg/to" - ucpv20231001 "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" - "github.com/stretchr/testify/require" -) - -func TestCreateOrUpdateResourceProvider_Success(t *testing.T) { - ctx := context.Background() - resourceProviderName := "MyCompany2.CompanyName2" - resource := &ucpv20231001.ResourceProviderResource{ - Name: to.Ptr(resourceProviderName), - } - - // Setup fake UCP server - server, err := NewFakeUCPServer() - require.NoError(t, err) - - // Setup UCP client with fake servers - client, err := NewTestUCPClient(server) - require.NoError(t, err) - - updatedResource, err := client.CreateOrUpdateResourceProvider(ctx, planeName, resourceProviderName, resource) - require.NoError(t, err) - require.Equal(t, resourceProviderName, *updatedResource.Name) -} - -func TestCreateOrUpdateResourceProvider_Failure(t *testing.T) { - ctx := context.Background() - resourceProviderName := "MyCompany2.CompanyName2" - resource := &ucpv20231001.ResourceProviderResource{ - Name: to.Ptr(resourceProviderName), - } - - // Setup UCP client with fake servers - client := UCPClient{} - - _, err := client.CreateOrUpdateResourceProvider(ctx, planeName, resourceProviderName, resource) - require.Error(t, err) - require.ErrorContains(t, err, "ResourceProvidersClient is nil") -}