From 2977c218391337d8aeb06a7ec6bfcc74ea4006cb Mon Sep 17 00:00:00 2001 From: lakshmimsft Date: Wed, 8 Jan 2025 00:49:46 -0800 Subject: [PATCH 1/3] remove legacy routing Signed-off-by: lakshmimsft --- .../{ => dev}/applications_core.yaml | 17 +- .../{ => dev}/applications_dapr.yaml | 11 +- .../{ => dev}/applications_datastores.yaml | 9 +- .../{ => dev}/applications_messaging.yaml | 5 +- .../{ => dev}/microsoft_resources.yaml | 6 +- .../self-hosted/applications_core.yaml | 40 ++++ .../self-hosted/applications_dapr.yaml | 25 +++ .../self-hosted/applications_datastores.yaml | 20 ++ .../self-hosted/applications_messaging.yaml | 10 + .../self-hosted/microsoft_resources.yaml | 10 + .../trackedresourceprocess_test.go | 61 ++++- pkg/ucp/datamodel/radiusplane.go | 14 -- .../frontend/controller/radius/proxy_test.go | 92 ++++++-- .../controller/resourcegroups/util.go | 38 +--- .../controller/resourcegroups/util_test.go | 208 ------------------ pkg/ucp/integrationtests/radius/proxy_test.go | 74 ++++++- .../noncloud/testdata/resourceprovider.yaml | 2 +- 17 files changed, 336 insertions(+), 306 deletions(-) rename deploy/manifest/built-in-providers/{ => dev}/applications_core.yaml (68%) rename deploy/manifest/built-in-providers/{ => dev}/applications_dapr.yaml (70%) rename deploy/manifest/built-in-providers/{ => dev}/applications_datastores.yaml (68%) rename deploy/manifest/built-in-providers/{ => dev}/applications_messaging.yaml (59%) rename deploy/manifest/built-in-providers/{ => dev}/microsoft_resources.yaml (54%) create mode 100644 deploy/manifest/built-in-providers/self-hosted/applications_core.yaml create mode 100644 deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml create mode 100644 deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml create mode 100644 deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml create mode 100644 deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml diff --git a/deploy/manifest/built-in-providers/applications_core.yaml b/deploy/manifest/built-in-providers/dev/applications_core.yaml similarity index 68% rename from deploy/manifest/built-in-providers/applications_core.yaml rename to deploy/manifest/built-in-providers/dev/applications_core.yaml index d105acaf01..6e8d34f65e 100644 --- a/deploy/manifest/built-in-providers/applications_core.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_core.yaml @@ -1,37 +1,40 @@ name: Applications.Core +locations: + global: + address: "http://localhost:8080" types: containers: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: [] applications: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: [] environments: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: [] gateways: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: [] secretStores: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: [] extenders: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] volumes: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: [] diff --git a/deploy/manifest/built-in-providers/applications_dapr.yaml b/deploy/manifest/built-in-providers/dev/applications_dapr.yaml similarity index 70% rename from deploy/manifest/built-in-providers/applications_dapr.yaml rename to deploy/manifest/built-in-providers/dev/applications_dapr.yaml index 3738e87643..11cd13567e 100644 --- a/deploy/manifest/built-in-providers/applications_dapr.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_dapr.yaml @@ -1,22 +1,25 @@ name: Applications.Dapr +locations: + global: + address: "http://localhost:8080" types: configurationStores: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] pubSubBrokers: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] secretStores: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] stateStores: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] diff --git a/deploy/manifest/built-in-providers/applications_datastores.yaml b/deploy/manifest/built-in-providers/dev/applications_datastores.yaml similarity index 68% rename from deploy/manifest/built-in-providers/applications_datastores.yaml rename to deploy/manifest/built-in-providers/dev/applications_datastores.yaml index b8eb7d65b7..767ed81ca1 100644 --- a/deploy/manifest/built-in-providers/applications_datastores.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_datastores.yaml @@ -1,17 +1,20 @@ name: Applications.Datastores +locations: + global: + address: "http://localhost:8080" types: mongoDatabases: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] sqlDatabases: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] redisCaches: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] diff --git a/deploy/manifest/built-in-providers/applications_messaging.yaml b/deploy/manifest/built-in-providers/dev/applications_messaging.yaml similarity index 59% rename from deploy/manifest/built-in-providers/applications_messaging.yaml rename to deploy/manifest/built-in-providers/dev/applications_messaging.yaml index cac03e8aa4..10db9242da 100644 --- a/deploy/manifest/built-in-providers/applications_messaging.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_messaging.yaml @@ -1,7 +1,10 @@ name: Applications.Messaging +locations: + global: + address: "http://localhost:8080" types: rabbitMQQueues: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] diff --git a/deploy/manifest/built-in-providers/microsoft_resources.yaml b/deploy/manifest/built-in-providers/dev/microsoft_resources.yaml similarity index 54% rename from deploy/manifest/built-in-providers/microsoft_resources.yaml rename to deploy/manifest/built-in-providers/dev/microsoft_resources.yaml index b2c24733bb..f5f13a7b9f 100644 --- a/deploy/manifest/built-in-providers/microsoft_resources.yaml +++ b/deploy/manifest/built-in-providers/dev/microsoft_resources.yaml @@ -1,8 +1,10 @@ name: Microsoft.Resources +locations: + global: + address: "http://localhost:5017" types: deployments: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: [] - diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_core.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_core.yaml new file mode 100644 index 0000000000..8700134816 --- /dev/null +++ b/deploy/manifest/built-in-providers/self-hosted/applications_core.yaml @@ -0,0 +1,40 @@ +name: Applications.Core +locations: + global: + address: "http://applications-rp.radius-system:5443" +types: + containers: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: [] + applications: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: [] + environments: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: [] + gateways: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: [] + secretStores: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: [] + extenders: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] + volumes: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: [] diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml new file mode 100644 index 0000000000..daaa4fd33d --- /dev/null +++ b/deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml @@ -0,0 +1,25 @@ +name: Applications.Dapr +locations: + global: + address: "http://applications-rp.radius-system:5443" +types: + configurationStores: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] + pubSubBrokers: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] + secretStores: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] + stateStores: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml new file mode 100644 index 0000000000..5d40939fe6 --- /dev/null +++ b/deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml @@ -0,0 +1,20 @@ +name: Applications.Datastores +locations: + global: + address: "http://applications-rp.radius-system:5443" +types: + mongoDatabases: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] + sqlDatabases: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] + redisCaches: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml new file mode 100644 index 0000000000..8cb7c16206 --- /dev/null +++ b/deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml @@ -0,0 +1,10 @@ +name: Applications.Messaging +locations: + global: + address: "http://applications-rp.radius-system:5443" +types: + rabbitMQQueues: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: ["Recipes"] diff --git a/deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml b/deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml new file mode 100644 index 0000000000..f041b89f90 --- /dev/null +++ b/deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml @@ -0,0 +1,10 @@ +name: Microsoft.Resources +locations: + global: + address: "http://bicep-de.radius-system:6443" +types: + deployments: + apiVersions: + "2023-10-01-preview": + schema: {} + capabilities: [] diff --git a/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go b/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go index 9ee2929d5f..b36c7471fb 100644 --- a/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go +++ b/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go @@ -24,6 +24,7 @@ import ( v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" "github.com/radius-project/radius/pkg/armrpc/asyncoperation/controller" "github.com/radius-project/radius/pkg/components/database" + "github.com/radius-project/radius/pkg/to" "github.com/radius-project/radius/pkg/ucp/datamodel" "github.com/radius-project/radius/pkg/ucp/resources" "github.com/radius-project/radius/pkg/ucp/trackedresource" @@ -47,10 +48,15 @@ func Test_Run(t *testing.T) { id := resources.MustParse("/planes/test/local/resourceGroups/test-rg/providers/Applications.Test/testResources/my-resource") trackingID := trackedresource.IDFor(id) + data := datamodel.GenericResourceFromID(id, trackingID) + data.Properties.APIVersion = "2025-01-01" resourceTypeID, err := datamodel.ResourceTypeIDFromResourceID(id) require.NoError(t, err) + locationID, err := datamodel.ResourceProviderLocationIDFromResourceID(id, "global") + require.NoError(t, err) + plane := datamodel.RadiusPlane{ Properties: datamodel.RadiusPlaneProperties{ ResourceProviders: map[string]string{ @@ -58,8 +64,42 @@ func Test_Run(t *testing.T) { }, }, } - resourceGroup := datamodel.ResourceGroup{} - data := datamodel.GenericResourceFromID(id, trackingID) + resourceGroup := &datamodel.ResourceGroup{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + ID: id.RootScope(), + }, + }, + } + + resourceTypeResource := &datamodel.ResourceType{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + Name: "testResources", + ID: resourceTypeID.String(), + }, + }, + Properties: datamodel.ResourceTypeProperties{}, + } + + locationResource := &datamodel.Location{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + Name: "global", + ID: locationID.String(), + }, + }, + Properties: datamodel.LocationProperties{ + Address: to.Ptr("https://localhost:1234"), + ResourceTypes: map[string]datamodel.LocationResourceTypeConfiguration{ + "testResources": { + APIVersions: map[string]datamodel.LocationAPIVersionConfiguration{ + "2025-01-01": {}, + }, + }, + }, + }, + } // Most of the heavy lifting is done by the updater. We just need to test that we're calling it correctly. t.Run("Success", func(t *testing.T) { @@ -70,17 +110,21 @@ func Test_Run(t *testing.T) { Return(&database.Object{Data: data}, nil).Times(1) databaseClient.EXPECT(). - Get(gomock.Any(), "/planes/"+trackingID.PlaneNamespace(), gomock.Any()). + Get(gomock.Any(), trackingID.PlaneScope(), gomock.Any()). Return(&database.Object{Data: plane}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). - Return(nil, &database.ErrNotFound{}).Times(1) + Return(&database.Object{Data: resourceTypeResource}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), trackingID.RootScope(), gomock.Any()). Return(&database.Object{Data: resourceGroup}, nil).Times(1) + databaseClient.EXPECT(). + Get(gomock.Any(), locationResource.ID). + Return(&database.Object{Data: locationResource}, nil).Times(1) + result, err := pc.Run(testcontext.New(t), &controller.Request{ResourceID: trackingID.String()}) require.Equal(t, controller.Result{}, result) require.NoError(t, err) @@ -94,17 +138,21 @@ func Test_Run(t *testing.T) { Return(&database.Object{Data: data}, nil).Times(1) databaseClient.EXPECT(). - Get(gomock.Any(), "/planes/"+trackingID.PlaneNamespace(), gomock.Any()). + Get(gomock.Any(), trackingID.PlaneScope(), gomock.Any()). Return(&database.Object{Data: plane}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). - Return(nil, &database.ErrNotFound{}).Times(1) + Return(&database.Object{Data: resourceTypeResource}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), trackingID.RootScope(), gomock.Any()). Return(&database.Object{Data: resourceGroup}, nil).Times(1) + databaseClient.EXPECT(). + Get(gomock.Any(), locationResource.ID). + Return(&database.Object{Data: locationResource}, nil).Times(1) + // Force a retry. updater.Result = &trackedresource.InProgressErr{} @@ -155,6 +203,7 @@ func Test_Run(t *testing.T) { require.Equal(t, expected, result) require.NoError(t, err) }) + } type mockUpdater struct { diff --git a/pkg/ucp/datamodel/radiusplane.go b/pkg/ucp/datamodel/radiusplane.go index 4c47a3d2a8..08243b1989 100644 --- a/pkg/ucp/datamodel/radiusplane.go +++ b/pkg/ucp/datamodel/radiusplane.go @@ -17,8 +17,6 @@ limitations under the License. package datamodel import ( - "strings" - v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" ) @@ -46,15 +44,3 @@ type RadiusPlane struct { func (p RadiusPlane) ResourceTypeName() string { return p.Type } - -// LookupResourceProvider checks if the input provider is in the list of configured providers. -func (plane RadiusPlane) LookupResourceProvider(key string) string { - var value string - for k, v := range plane.Properties.ResourceProviders { - if strings.EqualFold(k, key) { - value = v - break - } - } - return value -} diff --git a/pkg/ucp/frontend/controller/radius/proxy_test.go b/pkg/ucp/frontend/controller/radius/proxy_test.go index 063105e599..4629db95fd 100644 --- a/pkg/ucp/frontend/controller/radius/proxy_test.go +++ b/pkg/ucp/frontend/controller/radius/proxy_test.go @@ -29,6 +29,7 @@ import ( "github.com/radius-project/radius/pkg/armrpc/frontend/controller" "github.com/radius-project/radius/pkg/armrpc/rest" "github.com/radius-project/radius/pkg/components/database" + "github.com/radius-project/radius/pkg/to" "github.com/radius-project/radius/pkg/ucp/datamodel" "github.com/radius-project/radius/pkg/ucp/resources" "github.com/radius-project/radius/pkg/ucp/trackedresource" @@ -68,11 +69,12 @@ func createController(t *testing.T) (*ProxyController, *database.MockClient, *mo func Test_Run(t *testing.T) { id := resources.MustParse("/planes/test/local/resourceGroups/test-rg/providers/Applications.Test/testResources/my-resource") - // This test covers the legacy (pre-UDT) behavior for looking up the downstream URL. Update - // this when the old behavior is removed. resourceTypeID, err := datamodel.ResourceTypeIDFromResourceID(id) require.NoError(t, err) + locationID, err := datamodel.ResourceProviderLocationIDFromResourceID(id, "global") + require.NoError(t, err) + plane := datamodel.RadiusPlane{ Properties: datamodel.RadiusPlaneProperties{ ResourceProviders: map[string]string{ @@ -80,7 +82,42 @@ func Test_Run(t *testing.T) { }, }, } - resourceGroup := datamodel.ResourceGroup{} + resourceGroup := &datamodel.ResourceGroup{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + ID: id.RootScope(), + }, + }, + } + + resourceTypeResource := &datamodel.ResourceType{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + Name: "testResources", + ID: resourceTypeID.String(), + }, + }, + Properties: datamodel.ResourceTypeProperties{}, + } + + locationResource := &datamodel.Location{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + Name: "global", + ID: locationID.String(), + }, + }, + Properties: datamodel.LocationProperties{ + Address: to.Ptr("https://localhost:1234"), + ResourceTypes: map[string]datamodel.LocationResourceTypeConfiguration{ + "testResources": { + APIVersions: map[string]datamodel.LocationAPIVersionConfiguration{ + "2025-01-01": {}, + }, + }, + }, + }, + } t.Run("success (non-tracked)", func(t *testing.T) { p, databaseClient, _, roundTripper, _ := createController(t) @@ -98,17 +135,21 @@ func Test_Run(t *testing.T) { req := httptest.NewRequest(http.MethodGet, id.String()+"?api-version="+apiVersion, nil) databaseClient.EXPECT(). - Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). - Return(nil, &database.ErrNotFound{}).Times(1) + Get(gomock.Any(), id.PlaneScope(), gomock.Any()). + Return(&database.Object{Data: plane}, nil).Times(1) databaseClient.EXPECT(). - Get(gomock.Any(), "/planes/"+id.PlaneNamespace(), gomock.Any()). - Return(&database.Object{Data: plane}, nil).Times(1) + Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). + Return(&database.Object{Data: resourceTypeResource}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), id.RootScope(), gomock.Any()). Return(&database.Object{Data: resourceGroup}, nil).Times(1) + databaseClient.EXPECT(). + Get(gomock.Any(), locationResource.ID). + Return(&database.Object{Data: locationResource}, nil).Times(1) + downstreamResponse := httptest.NewRecorder() downstreamResponse.WriteHeader(http.StatusOK) roundTripper.Response = downstreamResponse.Result() @@ -134,17 +175,21 @@ func Test_Run(t *testing.T) { req := httptest.NewRequest(http.MethodDelete, id.String()+"?api-version="+apiVersion, nil) databaseClient.EXPECT(). - Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). - Return(nil, &database.ErrNotFound{}).Times(1) + Get(gomock.Any(), id.PlaneScope(), gomock.Any()). + Return(&database.Object{Data: plane}, nil).Times(1) databaseClient.EXPECT(). - Get(gomock.Any(), "/planes/"+id.PlaneNamespace(), gomock.Any()). - Return(&database.Object{Data: plane}, nil).Times(1) + Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). + Return(&database.Object{Data: resourceTypeResource}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), id.RootScope(), gomock.Any()). Return(&database.Object{Data: resourceGroup}, nil).Times(1) + databaseClient.EXPECT(). + Get(gomock.Any(), locationResource.ID). + Return(&database.Object{Data: locationResource}, nil).Times(1) + downstreamResponse := httptest.NewRecorder() downstreamResponse.WriteHeader(http.StatusOK) roundTripper.Response = downstreamResponse.Result() @@ -173,17 +218,21 @@ func Test_Run(t *testing.T) { req := httptest.NewRequest(http.MethodDelete, id.String()+"?api-version="+apiVersion, nil) databaseClient.EXPECT(). - Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). - Return(nil, &database.ErrNotFound{}).Times(1) + Get(gomock.Any(), id.PlaneScope(), gomock.Any()). + Return(&database.Object{Data: plane}, nil).Times(1) databaseClient.EXPECT(). - Get(gomock.Any(), "/planes/"+id.PlaneNamespace(), gomock.Any()). - Return(&database.Object{Data: plane}, nil).Times(1) + Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). + Return(&database.Object{Data: resourceTypeResource}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), id.RootScope(), gomock.Any()). Return(&database.Object{Data: resourceGroup}, nil).Times(1) + databaseClient.EXPECT(). + Get(gomock.Any(), locationResource.ID). + Return(&database.Object{Data: locationResource}, nil).Times(1) + // Tracking entry created databaseClient.EXPECT(). Get(gomock.Any(), gomock.Any(), gomock.Any()). @@ -224,17 +273,21 @@ func Test_Run(t *testing.T) { req := httptest.NewRequest(http.MethodDelete, id.String()+"?api-version="+apiVersion, nil) databaseClient.EXPECT(). - Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). - Return(nil, &database.ErrNotFound{}).Times(1) + Get(gomock.Any(), id.PlaneScope(), gomock.Any()). + Return(&database.Object{Data: plane}, nil).Times(1) databaseClient.EXPECT(). - Get(gomock.Any(), "/planes/"+id.PlaneNamespace(), gomock.Any()). - Return(&database.Object{Data: plane}, nil).Times(1) + Get(gomock.Any(), resourceTypeID.String(), gomock.Any()). + Return(&database.Object{Data: resourceTypeResource}, nil).Times(1) databaseClient.EXPECT(). Get(gomock.Any(), id.RootScope(), gomock.Any()). Return(&database.Object{Data: resourceGroup}, nil).Times(1) + databaseClient.EXPECT(). + Get(gomock.Any(), locationResource.ID). + Return(&database.Object{Data: locationResource}, nil).Times(1) + // Tracking entry created existingEntry := &database.Object{ Data: &datamodel.GenericResource{ @@ -343,6 +396,7 @@ func Test_ProxyController_PrepareProxyRequest(t *testing.T) { require.Equal(t, "failed to parse downstream URL: parse \"\\ninvalid\": net/url: invalid control character in URL", err.Error()) require.Nil(t, proxyReq) }) + } type mockUpdater struct { diff --git a/pkg/ucp/frontend/controller/resourcegroups/util.go b/pkg/ucp/frontend/controller/resourcegroups/util.go index 6c9ab112a3..5d41849821 100644 --- a/pkg/ucp/frontend/controller/resourcegroups/util.go +++ b/pkg/ucp/frontend/controller/resourcegroups/util.go @@ -123,12 +123,7 @@ func ValidateResourceType(ctx context.Context, client database.Client, id resour _, err = database.GetResource[datamodel.ResourceType](ctx, client, resourceTypeID.String()) if errors.Is(err, &database.ErrNotFound{}) { - - // Return the error as-is to fallback to the legacy routing behavior. - return nil, err - - // Uncomment this when we remove the legacy routing behavior. - // return nil, &InvalidError{Message: fmt.Sprintf("resource type %q not found", id.Type())} + return nil, &InvalidError{Message: fmt.Sprintf("resource type %q not found", id.Type())} } else if err != nil { return nil, fmt.Errorf("failed to fetch resource type %q: %w", id.Type(), err) } @@ -141,12 +136,7 @@ func ValidateResourceType(ctx context.Context, client database.Client, id resour location, err := database.GetResource[datamodel.Location](ctx, client, locationID.String()) if errors.Is(err, &database.ErrNotFound{}) { - - // Return the error as-is to fallback to the legacy routing behavior. - return nil, err - - // Uncomment this when we remove the legacy routing behavior. - // return nil, &InvalidError{Message: fmt.Sprintf("location %q not found for resource provider %q", locationName, id.ProviderNamespace())} + return nil, &InvalidError{Message: fmt.Sprintf("location %q not found for resource provider %q", locationName, id.ProviderNamespace())} } else if err != nil { return nil, fmt.Errorf("failed to fetch location %q: %w", locationID.String(), err) } @@ -230,22 +220,6 @@ func isOperationResourceType(id resources.ID) bool { return false } -// ValidateLegacyResourceProvider validates that the resource provider specified in the id exists. Returns InvalidError if the plane -// contains invalid data. -func ValidateLegacyResourceProvider(ctx context.Context, client database.Client, id resources.ID, plane *datamodel.RadiusPlane) (*url.URL, error) { - downstream := plane.LookupResourceProvider(id.ProviderNamespace()) - if downstream == "" { - return nil, &InvalidError{Message: fmt.Sprintf("resource provider %s not configured", id.ProviderNamespace())} - } - - downstreamURL, err := url.Parse(downstream) - if err != nil { - return nil, &InvalidError{Message: fmt.Sprintf("failed to parse downstream URL: %v", err.Error())} - } - - return downstreamURL, nil -} - // ValidateDownstream can be used to find and validate the downstream URL for a resource. // Returns NotFoundError for the case where the plane or resource group does not exist. // Returns InvalidError for cases where the data is invalid, like when the resource provider is not configured. @@ -255,12 +229,11 @@ func ValidateDownstream(ctx context.Context, client database.Client, id resource // - The plane exists // - The resource group exists // - The resource provider is configured .. either: - // - As part of the plane (legacy routing) // - As part of a resource provider resource (System.Resources/resourceProviders) (new/UDT routing) // // The plane exists. - plane, err := ValidateRadiusPlane(ctx, client, id) + _, err := ValidateRadiusPlane(ctx, client, id) if err != nil { return nil, err } @@ -273,10 +246,7 @@ func ValidateDownstream(ctx context.Context, client database.Client, id resource // If this returns success, it means the resource type is configured using new/UDT routing. downstreamURL, err := ValidateResourceType(ctx, client, id, location, apiVersion) - if errors.Is(err, &database.ErrNotFound{}) { - // If the resource provider is not found, treat it like a legacy provider. - return ValidateLegacyResourceProvider(ctx, client, id, plane) - } else if err != nil { + if err != nil { return nil, err } diff --git a/pkg/ucp/frontend/controller/resourcegroups/util_test.go b/pkg/ucp/frontend/controller/resourcegroups/util_test.go index 3b80d21bc3..085f1de9b2 100644 --- a/pkg/ucp/frontend/controller/resourcegroups/util_test.go +++ b/pkg/ucp/frontend/controller/resourcegroups/util_test.go @@ -409,211 +409,3 @@ func Test_ValidateDownstream(t *testing.T) { require.Nil(t, downstreamURL) }) } - -// This test validates the pre-UDT before where resource providers are registered as part of the plane. -// This can be deleted once the legacy routing behavior is removed. -func Test_ValidateDownstream_Legacy(t *testing.T) { - id, err := resources.ParseResource("/planes/radius/local/resourceGroups/test-group/providers/System.TestRP/testResources/name") - require.NoError(t, err) - - idWithoutResourceGroup, err := resources.Parse("/planes/radius/local/providers/System.TestRP/testResources") - require.NoError(t, err) - - resourceTypeID, err := datamodel.ResourceTypeIDFromResourceID(id) - require.NoError(t, err) - - downstream := "http://localhost:7443" - - plane := &datamodel.RadiusPlane{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.PlaneScope(), - }, - }, - Properties: datamodel.RadiusPlaneProperties{ - ResourceProviders: map[string]string{ - "System.TestRP": downstream, - }, - }, - } - - setup := func(t *testing.T) *database.MockClient { - ctrl := gomock.NewController(t) - return database.NewMockClient(ctrl) - } - - t.Run("success (resource group)", func(t *testing.T) { - resourceGroup := &datamodel.ResourceGroup{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.RootScope(), - }, - }, - } - - databaseClient := setup(t) - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(&database.Object{Data: plane}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), id.RootScope()).Return(&database.Object{Data: resourceGroup}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), resourceTypeID.String()).Return(nil, &database.ErrNotFound{}).Times(1) - - expectedURL, err := url.Parse(downstream) - require.NoError(t, err) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.NoError(t, err) - require.Equal(t, expectedURL, downstreamURL) - }) - - t.Run("success (non resource group)", func(t *testing.T) { - databaseClient := setup(t) - databaseClient.EXPECT().Get(gomock.Any(), idWithoutResourceGroup.PlaneScope()).Return(&database.Object{Data: plane}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), resourceTypeID.String()).Return(nil, &database.ErrNotFound{}).Times(1) - - expectedURL, err := url.Parse(downstream) - require.NoError(t, err) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, idWithoutResourceGroup, location, apiVersion) - require.NoError(t, err) - require.Equal(t, expectedURL, downstreamURL) - }) - - t.Run("plane not found", func(t *testing.T) { - databaseClient := setup(t) - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(nil, &database.ErrNotFound{}).Times(1) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.Error(t, err) - require.Equal(t, &NotFoundError{Message: "plane \"/planes/radius/local\" not found"}, err) - require.Nil(t, downstreamURL) - }) - - t.Run("plane retrieval failure", func(t *testing.T) { - databaseClient := setup(t) - - expected := fmt.Errorf("failed to fetch plane \"/planes/radius/local\": %w", errors.New("test error")) - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(nil, errors.New("test error")).Times(1) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.Error(t, err) - require.Equal(t, expected, err) - require.Nil(t, downstreamURL) - }) - - t.Run("resource group not found", func(t *testing.T) { - databaseClient := setup(t) - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(&database.Object{Data: plane}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), id.RootScope()).Return(nil, &database.ErrNotFound{}).Times(1) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.Error(t, err) - require.Equal(t, &NotFoundError{Message: "resource group \"/planes/radius/local/resourceGroups/test-group\" not found"}, err) - require.Nil(t, downstreamURL) - }) - - t.Run("resource group err", func(t *testing.T) { - databaseClient := setup(t) - - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(&database.Object{Data: plane}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), id.RootScope()).Return(nil, errors.New("test error")).Times(1) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.Error(t, err) - require.Equal(t, "failed to fetch resource group \"/planes/radius/local/resourceGroups/test-group\": test error", err.Error()) - require.Nil(t, downstreamURL) - }) - - t.Run("legacy resource provider not configured", func(t *testing.T) { - plane := &datamodel.RadiusPlane{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.PlaneScope(), - }, - }, - Properties: datamodel.RadiusPlaneProperties{ - ResourceProviders: map[string]string{}, - }, - } - - resourceGroup := &datamodel.ResourceGroup{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.RootScope(), - }, - }, - } - - databaseClient := setup(t) - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(&database.Object{Data: plane}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), id.RootScope()).Return(&database.Object{Data: resourceGroup}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), resourceTypeID.String()).Return(nil, &database.ErrNotFound{}).Times(1) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.Error(t, err) - require.Equal(t, &InvalidError{Message: "resource provider System.TestRP not configured"}, err) - require.Nil(t, downstreamURL) - }) - - t.Run("location not found", func(t *testing.T) { - plane := &datamodel.RadiusPlane{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.PlaneScope(), - }, - }, - Properties: datamodel.RadiusPlaneProperties{ - ResourceProviders: map[string]string{}, - }, - } - - resourceGroup := &datamodel.ResourceGroup{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.RootScope(), - }, - }, - } - - databaseClient := setup(t) - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(&database.Object{Data: plane}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), id.RootScope()).Return(&database.Object{Data: resourceGroup}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), resourceTypeID.String()).Return(nil, &database.ErrNotFound{}).Times(1) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.Error(t, err) - require.Equal(t, &InvalidError{Message: "resource provider System.TestRP not configured"}, err) - require.Nil(t, downstreamURL) - }) - - t.Run("resource provider invalid URL", func(t *testing.T) { - plane := &datamodel.RadiusPlane{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.PlaneScope(), - }, - }, - Properties: datamodel.RadiusPlaneProperties{ - ResourceProviders: map[string]string{ - "System.TestRP": "\ninvalid", - }, - }, - } - - resourceGroup := &datamodel.ResourceGroup{ - BaseResource: v1.BaseResource{ - TrackedResource: v1.TrackedResource{ - ID: id.RootScope(), - }, - }, - } - - databaseClient := setup(t) - databaseClient.EXPECT().Get(gomock.Any(), id.PlaneScope()).Return(&database.Object{Data: plane}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), id.RootScope()).Return(&database.Object{Data: resourceGroup}, nil).Times(1) - databaseClient.EXPECT().Get(gomock.Any(), resourceTypeID.String()).Return(nil, &database.ErrNotFound{}).Times(1) - - downstreamURL, err := ValidateDownstream(testcontext.New(t), databaseClient, id, location, apiVersion) - require.Error(t, err) - require.Equal(t, &InvalidError{Message: "failed to parse downstream URL: parse \"\\ninvalid\": net/url: invalid control character in URL"}, err) - require.Nil(t, downstreamURL) - }) -} diff --git a/pkg/ucp/integrationtests/radius/proxy_test.go b/pkg/ucp/integrationtests/radius/proxy_test.go index 5275034f31..b98dec935f 100644 --- a/pkg/ucp/integrationtests/radius/proxy_test.go +++ b/pkg/ucp/integrationtests/radius/proxy_test.go @@ -36,11 +36,14 @@ import ( const ( apiVersionParameter = "api-version=2023-10-01-preview" - testRadiusPlaneID = "/planes/radius/test" + testRadiusPlaneID = "/planes/radius/local" testResourceNamespace = "System.Test" testResourceGroupID = testRadiusPlaneID + "/resourceGroups/test-rg" + testResourceProviderID = "/planes/radius/local/providers/System.Resources/resourceproviders/System.Test" testResourceCollectionID = testResourceGroupID + "/providers/System.Test/testResources" testResourceID = testResourceCollectionID + "/test-resource" + resourceTypeURL = "/planes/radius/local/providers/System.Resources/resourceproviders/System.Test/resourcetypes/testResources" + locationID = "/planes/radius/local/providers/System.Resources/resourceproviders/System.Test/locations/global" assertTimeout = time.Second * 10 assertRetry = time.Second * 2 @@ -57,21 +60,27 @@ func Test_RadiusPlane_Proxy_ResourceGroupDoesNotExist(t *testing.T) { response := ucp.MakeRequest(http.MethodGet, testResourceID+"?api-version="+testrp.Version, nil) response.EqualsErrorCode(http.StatusNotFound, "NotFound") - require.Equal(t, "the resource with id '/planes/radius/test/resourceGroups/test-rg/providers/System.Test/testResources/test-resource' was not found: resource group \"/planes/radius/test/resourceGroups/test-rg\" not found", response.Error.Error.Message) + require.Equal(t, "the resource with id '/planes/radius/local/resourceGroups/test-rg/providers/System.Test/testResources/test-resource' was not found: resource group \"/planes/radius/local/resourceGroups/test-rg\" not found", response.Error.Error.Message) } func Test_RadiusPlane_ResourceSync(t *testing.T) { ucp := testhost.Start(t) rp := testrp.Start(t) rp.Handler = testrp.SyncResource(t, ucp, testResourceGroupID) - + address := to.Ptr("http://" + rp.Address()) rps := map[string]*string{ - testResourceNamespace: to.Ptr("http://" + rp.Address()), + testResourceNamespace: address, } createRadiusPlane(ucp, rps) createResourceGroup(ucp, testResourceGroupID) + createResourceProvider(ucp) + + createResourceType(ucp, resourceTypeURL) + + createLocation(ucp, address) + message := "here is some test data" expectedTrackedResource := v20231001preview.GenericResource{ @@ -89,7 +98,10 @@ func Test_RadiusPlane_ResourceSync(t *testing.T) { body, err := json.Marshal(data) require.NoError(t, err) - response := ucp.MakeRequest(http.MethodPut, testResourceID+"?api-version="+testrp.Version, body) + response := ucp.MakeRequest(http.MethodGet, resourceTypeURL+"?api-version="+testrp.Version, nil) + response.EqualsStatusCode(http.StatusOK) + + response = ucp.MakeRequest(http.MethodPut, testResourceID+"?api-version="+testrp.Version, body) response.EqualsStatusCode(http.StatusOK) resource := &testrp.TestResource{} @@ -184,14 +196,21 @@ func Test_RadiusPlane_ResourceAsync(t *testing.T) { } rp.Handler = testrp.AsyncResource(t, ucp, testResourceGroupID, onPut, onDelete) - + address := to.Ptr("http://" + rp.Address()) rps := map[string]*string{ - testResourceNamespace: to.Ptr("http://" + rp.Address()), + testResourceNamespace: address, } + createRadiusPlane(ucp, rps) createResourceGroup(ucp, testResourceGroupID) + createResourceProvider(ucp) + + createResourceType(ucp, resourceTypeURL) + + createLocation(ucp, address) + message := "here is some test data" expectedTrackedResource := v20231001preview.GenericResource{ @@ -400,3 +419,44 @@ func createResourceGroup(ucp *testhost.TestHost, id string) { response := ucp.MakeTypedRequest(http.MethodPut, id+"?"+apiVersionParameter, body) response.EqualsStatusCode(http.StatusOK) } + +func createResourceProvider(ucp *testhost.TestHost) { + body := v20231001preview.ResourceProviderResource{ + Location: to.Ptr(v1.LocationGlobal), + Properties: &v20231001preview.ResourceProviderProperties{}, + } + response := ucp.MakeTypedRequest("PUT", testResourceProviderID+"?"+apiVersionParameter, body) + response.WaitForOperationComplete(nil) + response.EqualsStatusCode(http.StatusCreated) +} + +func createResourceType(ucp *testhost.TestHost, id string) { + body := v20231001preview.ResourceTypeResource{ + Properties: &v20231001preview.ResourceTypeProperties{ + DefaultAPIVersion: to.Ptr("2023-10-01-preview"), + }, + } + + response := ucp.MakeTypedRequest(http.MethodPut, id+"?"+apiVersionParameter, body) + response.WaitForOperationComplete(nil) + response.EqualsStatusCode(http.StatusCreated) +} + +func createLocation(server *testhost.TestHost, address *string) { + body := v20231001preview.LocationResource{ + Properties: &v20231001preview.LocationProperties{ + Address: address, + ResourceTypes: map[string]*v20231001preview.LocationResourceType{ + "testResources": { + APIVersions: map[string]map[string]any{ + "2023-10-01-preview": {}, + }, + }, + }, + }, + } + + response := server.MakeTypedRequest("PUT", locationID+"?"+apiVersionParameter, body) + response.WaitForOperationComplete(nil) + response.EqualsStatusCode(http.StatusCreated) +} diff --git a/test/functional-portable/ucp/noncloud/testdata/resourceprovider.yaml b/test/functional-portable/ucp/noncloud/testdata/resourceprovider.yaml index c3348b0229..84dbc04431 100644 --- a/test/functional-portable/ucp/noncloud/testdata/resourceprovider.yaml +++ b/test/functional-portable/ucp/noncloud/testdata/resourceprovider.yaml @@ -2,6 +2,6 @@ name: MyCompany.Resources types: testResources: apiVersions: - "2025-01-01-preview": + "2023-10-01-preview": schema: {} capabilities: ["SupportsRecipes"] From 8a2af96d311cfeaada8db60dc4d49a7179a619e9 Mon Sep 17 00:00:00 2001 From: lakshmimsft Date: Fri, 10 Jan 2025 00:35:28 -0800 Subject: [PATCH 2/3] enable register manifest Signed-off-by: lakshmimsft --- build/docker.mk | 18 +++++-- cmd/ucpd/ucp-dev.yaml | 2 +- deploy/Chart/templates/ucp/configmaps.yaml | 2 +- deploy/images/ucpd/Dockerfile | 3 ++ .../dev/applications_core.yaml | 4 +- .../dev/applications_dapr.yaml | 4 +- .../dev/applications_datastores.yaml | 4 +- .../dev/applications_messaging.yaml | 4 +- .../dev/microsoft_resources.yaml | 8 +-- .../self-hosted/applications_core.yaml | 6 +-- .../self-hosted/applications_dapr.yaml | 12 ++--- .../self-hosted/applications_datastores.yaml | 10 ++-- .../self-hosted/applications_messaging.yaml | 6 +-- .../self-hosted/microsoft_resources.yaml | 8 +-- .../create/testdata/valid.yaml | 3 ++ .../resourcetype/create/testdata/valid.yaml | 4 +- pkg/cli/manifest/manifest.go | 3 ++ pkg/cli/manifest/manifest_test.go | 3 ++ pkg/cli/manifest/registermanifest.go | 49 ++++++++++++++++--- pkg/cli/manifest/registermanifest_test.go | 2 +- .../testdata/missing-required-field.json | 2 +- .../resourceprovider-valid2.yaml | 3 ++ pkg/cli/manifest/testdata/valid.yaml | 3 ++ .../trackedresourceprocess_test.go | 1 - .../frontend/controller/radius/proxy_test.go | 1 - pkg/ucp/integrationtests/radius/proxy_test.go | 10 ++-- .../manifests/resourceprovider-valid1.yaml | 3 ++ .../ucp/noncloud/resourceprovider_test.go | 2 +- 28 files changed, 124 insertions(+), 56 deletions(-) diff --git a/build/docker.mk b/build/docker.mk index 7adcdcaa6b..0fe2268b30 100644 --- a/build/docker.mk +++ b/build/docker.mk @@ -17,6 +17,7 @@ DOCKER_REGISTRY?=$(shell whoami) DOCKER_TAG_VERSION?=latest IMAGE_SRC?=https://github.com/radius-project/radius +MANIFEST_DIR?=deploy/manifest/built-in-providers/self-hosted ##@ Docker Images @@ -106,6 +107,17 @@ APPS_MAP := ucpd:./deploy/images/ucpd \ testrp:./test/testrp \ magpiego:./test/magpiego +# copy_manifests copies the manifests to the output directory +.PHONY: copy-manifests +copy-manifests: + @if [ ! -d "$(MANIFEST_DIR)" ] || [ -z "$$(ls -A $(MANIFEST_DIR))" ]; then \ + echo "MANIFEST_DIR '$(MANIFEST_DIR)' does not exist or is empty"; \ + exit 1; \ + fi + @mkdir -p $(OUT_DIR)/manifest/built-in-providers/ + @echo "Copying manifests from $(MANIFEST_DIR) to $(OUT_DIR)/manifest/built-in-providers/" + @cp -v $(MANIFEST_DIR)/* $(OUT_DIR)/manifest/built-in-providers/ + # Function to extract the name and the directory of the Dockerfile from the app string define parseApp $(eval NAME := $(shell echo $(1) | cut -d: -f1)) @@ -132,7 +144,7 @@ DOCKER_PUSH_MULTI_TARGETS := $(foreach APP,$(APPS_MAP),$(eval $(call parseApp,$( # targets to build development images .PHONY: docker-build -docker-build: $(DOCKER_BUILD_TARGETS) ## Builds all Docker images. +docker-build: copy-manifests $(DOCKER_BUILD_TARGETS) ## Builds all Docker images. .PHONY: docker-push docker-push: $(DOCKER_PUSH_TARGETS) ## Pushes all Docker images (without building). @@ -140,7 +152,7 @@ docker-push: $(DOCKER_PUSH_TARGETS) ## Pushes all Docker images (without buildin # targets to build and push multi arch images. If you run this target in your machine, # ensure you have qemu and buildx installed by running make configure-buildx. .PHONY: docker-multi-arch-build -docker-multi-arch-build: $(DOCKER_BUILD_MULTI_TARGETS) ## Builds all docker images for multiple architectures. +docker-multi-arch-build: copy-manifests $(DOCKER_BUILD_MULTI_TARGETS) ## Builds all docker images for multiple architectures. .PHONY: docker-multi-arch-push -docker-multi-arch-push: $(DOCKER_PUSH_MULTI_TARGETS) ## Pushes all docker images for multiple architectures after building. +docker-multi-arch-push: copy-manifests $(DOCKER_PUSH_MULTI_TARGETS) ## Pushes all docker images for multiple architectures after building. diff --git a/cmd/ucpd/ucp-dev.yaml b/cmd/ucpd/ucp-dev.yaml index ddabe6bb0b..ae0da2ff5e 100644 --- a/cmd/ucpd/ucp-dev.yaml +++ b/cmd/ucpd/ucp-dev.yaml @@ -53,7 +53,7 @@ initialization: Microsoft.Resources: "http://localhost:5017" kind: "UCPNative" # This is the directory location which contains manifests to be registered. - manifestDirectory: "" + manifestDirectory: "manifest/built-in-providers/" identity: authMethod: default diff --git a/deploy/Chart/templates/ucp/configmaps.yaml b/deploy/Chart/templates/ucp/configmaps.yaml index 2047e006a8..4b29bfdb47 100644 --- a/deploy/Chart/templates/ucp/configmaps.yaml +++ b/deploy/Chart/templates/ucp/configmaps.yaml @@ -50,7 +50,7 @@ data: - id: "/planes/aws/aws" properties: kind: "AWS" - manifestDirectory: "" + manifestDirectory: "/manifest/built-in-providers" identity: authMethod: UCPCredential diff --git a/deploy/images/ucpd/Dockerfile b/deploy/images/ucpd/Dockerfile index 44ff6e5be3..b2243c39ad 100644 --- a/deploy/images/ucpd/Dockerfile +++ b/deploy/images/ucpd/Dockerfile @@ -10,6 +10,9 @@ WORKDIR / # Copy the application binary for the specified architecture COPY ./linux_${TARGETARCH:-amd64}/release/ucpd / +# Copy the manifest files for the built-in providers +COPY ./manifest/built-in-providers/ /manifest/built-in-providers/ + # Set the user to non-root (65532:65532 is the default non-root user in distroless) USER 65532:65532 diff --git a/deploy/manifest/built-in-providers/dev/applications_core.yaml b/deploy/manifest/built-in-providers/dev/applications_core.yaml index 6e8d34f65e..48fa2c996c 100644 --- a/deploy/manifest/built-in-providers/dev/applications_core.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_core.yaml @@ -1,7 +1,7 @@ name: Applications.Core -locations: +location: global: - address: "http://localhost:8080" + "http://localhost:8080" types: containers: apiVersions: diff --git a/deploy/manifest/built-in-providers/dev/applications_dapr.yaml b/deploy/manifest/built-in-providers/dev/applications_dapr.yaml index 11cd13567e..57b4c9d6dc 100644 --- a/deploy/manifest/built-in-providers/dev/applications_dapr.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_dapr.yaml @@ -1,7 +1,7 @@ name: Applications.Dapr -locations: +location: global: - address: "http://localhost:8080" + "http://localhost:8080" types: configurationStores: apiVersions: diff --git a/deploy/manifest/built-in-providers/dev/applications_datastores.yaml b/deploy/manifest/built-in-providers/dev/applications_datastores.yaml index 767ed81ca1..30c78a5641 100644 --- a/deploy/manifest/built-in-providers/dev/applications_datastores.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_datastores.yaml @@ -1,7 +1,7 @@ name: Applications.Datastores -locations: +location: global: - address: "http://localhost:8080" + "http://localhost:8080" types: mongoDatabases: apiVersions: diff --git a/deploy/manifest/built-in-providers/dev/applications_messaging.yaml b/deploy/manifest/built-in-providers/dev/applications_messaging.yaml index 10db9242da..ba41b3a11b 100644 --- a/deploy/manifest/built-in-providers/dev/applications_messaging.yaml +++ b/deploy/manifest/built-in-providers/dev/applications_messaging.yaml @@ -1,7 +1,7 @@ name: Applications.Messaging -locations: +location: global: - address: "http://localhost:8080" + "http://localhost:8080" types: rabbitMQQueues: apiVersions: diff --git a/deploy/manifest/built-in-providers/dev/microsoft_resources.yaml b/deploy/manifest/built-in-providers/dev/microsoft_resources.yaml index f5f13a7b9f..e780319a1c 100644 --- a/deploy/manifest/built-in-providers/dev/microsoft_resources.yaml +++ b/deploy/manifest/built-in-providers/dev/microsoft_resources.yaml @@ -1,10 +1,12 @@ name: Microsoft.Resources -locations: +location: global: - address: "http://localhost:5017" + "http://localhost:5017" types: deployments: apiVersions: - "2023-10-01-preview": + "2020-10-01": schema: {} + "2022-09-01": + schema: {} capabilities: [] diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_core.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_core.yaml index 8700134816..e7038d710d 100644 --- a/deploy/manifest/built-in-providers/self-hosted/applications_core.yaml +++ b/deploy/manifest/built-in-providers/self-hosted/applications_core.yaml @@ -1,7 +1,7 @@ name: Applications.Core -locations: +location: global: - address: "http://applications-rp.radius-system:5443" + "http://applications-rp.radius-system:5443" types: containers: apiVersions: @@ -32,7 +32,7 @@ types: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] volumes: apiVersions: "2023-10-01-preview": diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml index daaa4fd33d..01e0400565 100644 --- a/deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml +++ b/deploy/manifest/built-in-providers/self-hosted/applications_dapr.yaml @@ -1,25 +1,25 @@ name: Applications.Dapr -locations: +location: global: - address: "http://applications-rp.radius-system:5443" + "http://applications-rp.radius-system:5443" types: configurationStores: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] pubSubBrokers: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] secretStores: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] stateStores: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml index 5d40939fe6..80a6b24a4b 100644 --- a/deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml +++ b/deploy/manifest/built-in-providers/self-hosted/applications_datastores.yaml @@ -1,20 +1,20 @@ name: Applications.Datastores -locations: +location: global: - address: "http://applications-rp.radius-system:5443" + "http://applications-rp.radius-system:5443" types: mongoDatabases: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] sqlDatabases: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] redisCaches: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] diff --git a/deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml b/deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml index 8cb7c16206..b00483559f 100644 --- a/deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml +++ b/deploy/manifest/built-in-providers/self-hosted/applications_messaging.yaml @@ -1,10 +1,10 @@ name: Applications.Messaging -locations: +location: global: - address: "http://applications-rp.radius-system:5443" + "http://applications-rp.radius-system:5443" types: rabbitMQQueues: apiVersions: "2023-10-01-preview": schema: {} - capabilities: ["Recipes"] + capabilities: ["SupportsRecipes"] diff --git a/deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml b/deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml index f041b89f90..969a2e491e 100644 --- a/deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml +++ b/deploy/manifest/built-in-providers/self-hosted/microsoft_resources.yaml @@ -1,10 +1,12 @@ name: Microsoft.Resources -locations: +location: global: - address: "http://bicep-de.radius-system:6443" + "http://bicep-de.radius-system:6443" types: deployments: apiVersions: - "2023-10-01-preview": + "2020-10-01": schema: {} + "2022-09-01": + schema: {} capabilities: [] diff --git a/pkg/cli/cmd/resourceprovider/create/testdata/valid.yaml b/pkg/cli/cmd/resourceprovider/create/testdata/valid.yaml index a6f26f7fb4..f2eee239d6 100644 --- a/pkg/cli/cmd/resourceprovider/create/testdata/valid.yaml +++ b/pkg/cli/cmd/resourceprovider/create/testdata/valid.yaml @@ -1,4 +1,7 @@ name: MyCompany.Resources +location: + global: + 'http://localhost:8080' types: testResources: apiVersions: diff --git a/pkg/cli/cmd/resourcetype/create/testdata/valid.yaml b/pkg/cli/cmd/resourcetype/create/testdata/valid.yaml index a6f26f7fb4..621c3926c3 100644 --- a/pkg/cli/cmd/resourcetype/create/testdata/valid.yaml +++ b/pkg/cli/cmd/resourcetype/create/testdata/valid.yaml @@ -2,6 +2,6 @@ name: MyCompany.Resources types: testResources: apiVersions: - '2025-01-01-preview': + '2023-10-01-preview': schema: {} - capabilities: ["SupportsRecipes"] \ No newline at end of file + capabilities: ["SupportsRecipes"] diff --git a/pkg/cli/manifest/manifest.go b/pkg/cli/manifest/manifest.go index d7a8a5855e..9e112f0cf4 100644 --- a/pkg/cli/manifest/manifest.go +++ b/pkg/cli/manifest/manifest.go @@ -21,6 +21,9 @@ type ResourceProvider struct { // Name is the resource provider name. This is also the namespace of the types defined by the resource provider. Name string `yaml:"name" validate:"required,resourceProviderNamespace"` + // Location is a map of location name to address in the resource provider. + Location map[string]string `yaml:"location,omitempty"` + // Types is a map of resource types in the resource provider. Types map[string]*ResourceType `yaml:"types" validate:"dive,keys,resourceType,endkeys,required"` } diff --git a/pkg/cli/manifest/manifest_test.go b/pkg/cli/manifest/manifest_test.go index 23c11de187..431ed1fc40 100644 --- a/pkg/cli/manifest/manifest_test.go +++ b/pkg/cli/manifest/manifest_test.go @@ -25,6 +25,9 @@ import ( func TestReadFileYAML(t *testing.T) { expected := &ResourceProvider{ Name: "MyCompany.Resources", + Location: map[string]string{ + "global": "http://localhost:8080", + }, Types: map[string]*ResourceType{ "testResources": { APIVersions: map[string]*ResourceTypeAPIVersion{ diff --git a/pkg/cli/manifest/registermanifest.go b/pkg/cli/manifest/registermanifest.go index 8f785def4b..7ba5fdbe83 100644 --- a/pkg/cli/manifest/registermanifest.go +++ b/pkg/cli/manifest/registermanifest.go @@ -38,9 +38,21 @@ func RegisterFile(ctx context.Context, clientFactory *v20231001preview.ClientFac return err } - logIfEnabled(logger, "Creating resource provider %s", resourceProvider.Name) + var locationName string + var address string + + if resourceProvider.Location == nil { + locationName = v1.LocationGlobal + } else { + for locationName, address = range resourceProvider.Location { + // We support one location per resourceProvider + break + } + } + + logIfEnabled(logger, "Creating resource provider %s at location %s", resourceProvider.Name, locationName) resourceProviderPoller, err := clientFactory.NewResourceProvidersClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, v20231001preview.ResourceProviderResource{ - Location: to.Ptr(v1.LocationGlobal), + Location: to.Ptr(locationName), Properties: &v20231001preview.ResourceProviderProperties{}, }, nil) if err != nil { @@ -101,8 +113,12 @@ func RegisterFile(ctx context.Context, clientFactory *v20231001preview.ClientFac 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 address != "" { + locationResource.Properties.Address = to.Ptr(address) + } + + logIfEnabled(logger, "Creating location %s/%s/%s", resourceProvider.Name, locationName, address) + locationPoller, err := clientFactory.NewLocationsClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, locationName, locationResource, nil) if err != nil { return err } @@ -167,9 +183,21 @@ func RegisterType(ctx context.Context, clientFactory *v20231001preview.ClientFac return err } + var locationName string + var address string + + if resourceProvider.Location == nil { + locationName = v1.LocationGlobal + } else { + for locationName, address = range resourceProvider.Location { + // We support one location per resourceProvider + break + } + } + resourceType, ok := resourceProvider.Types[typeName] if !ok { - return fmt.Errorf("Type %s not found in manifest file %s", typeName, filePath) + return fmt.Errorf("type %s not found in manifest file %s", typeName, filePath) } logIfEnabled(logger, "Creating resource type %s/%s", resourceProvider.Name, typeName) @@ -203,7 +231,7 @@ func RegisterType(ctx context.Context, clientFactory *v20231001preview.ClientFac } // get the existing location resource and update it with new resource type. We have to revisit this code once schema is finalized and validated. - locationResourceGetResponse, err := clientFactory.NewLocationsClient().Get(ctx, planeName, resourceProvider.Name, v1.LocationGlobal, nil) + locationResourceGetResponse, err := clientFactory.NewLocationsClient().Get(ctx, planeName, resourceProvider.Name, locationName, nil) if err != nil { return err } @@ -214,15 +242,20 @@ func RegisterType(ctx context.Context, clientFactory *v20231001preview.ClientFac } else { defaultAPIVersion = *resourceType.DefaultAPIVersion } + locationResource := locationResourceGetResponse.LocationResource + if address != "" { + locationResource.Properties.Address = to.Ptr(address) + } + locationResource.Properties.ResourceTypes[typeName] = &v20231001preview.LocationResourceType{ APIVersions: map[string]map[string]any{ defaultAPIVersion: {}, }, } - logIfEnabled(logger, "Updating location %s/%s with new resource type", resourceProvider.Name, v1.LocationGlobal) - locationPoller, err := clientFactory.NewLocationsClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, v1.LocationGlobal, locationResource, nil) + logIfEnabled(logger, "Updating location %s/%s with new resource type", resourceProvider.Name, locationName) + locationPoller, err := clientFactory.NewLocationsClient().BeginCreateOrUpdate(ctx, planeName, resourceProvider.Name, locationName, locationResource, nil) if err != nil { return err } diff --git a/pkg/cli/manifest/registermanifest_test.go b/pkg/cli/manifest/registermanifest_test.go index 8026c6b898..847939b8bc 100644 --- a/pkg/cli/manifest/registermanifest_test.go +++ b/pkg/cli/manifest/registermanifest_test.go @@ -190,7 +190,7 @@ func TestRegisterType(t *testing.T) { resourceTypeName: "testResource5", filePath: "testdata/registerdirectory/resourceprovider-valid2.yaml", expectError: true, - expectedErrorMessage: "Type testResource5 not found in manifest file testdata/registerdirectory/resourceprovider-valid2.yaml", + expectedErrorMessage: "type testResource5 not found in manifest file testdata/registerdirectory/resourceprovider-valid2.yaml", expectedResourceProvider: "", expectedResourceTypeName: "", }, diff --git a/pkg/cli/manifest/testdata/missing-required-field.json b/pkg/cli/manifest/testdata/missing-required-field.json index c6ef38a2f2..8a200cbec9 100644 --- a/pkg/cli/manifest/testdata/missing-required-field.json +++ b/pkg/cli/manifest/testdata/missing-required-field.json @@ -4,7 +4,7 @@ "apiVersions": { "2025-01-01-preview": { "schema": {}, - "capabilities": ["Recipes"] + "capabilities": ["SupportsRecipes"] } } } diff --git a/pkg/cli/manifest/testdata/registerdirectory/resourceprovider-valid2.yaml b/pkg/cli/manifest/testdata/registerdirectory/resourceprovider-valid2.yaml index a2ffd310e7..0b70586ad3 100644 --- a/pkg/cli/manifest/testdata/registerdirectory/resourceprovider-valid2.yaml +++ b/pkg/cli/manifest/testdata/registerdirectory/resourceprovider-valid2.yaml @@ -1,4 +1,7 @@ name: MyCompany2.CompanyName2 +location: + global: + 'http://localhost:8080' types: testResource3: apiVersions: diff --git a/pkg/cli/manifest/testdata/valid.yaml b/pkg/cli/manifest/testdata/valid.yaml index a6f26f7fb4..f2eee239d6 100644 --- a/pkg/cli/manifest/testdata/valid.yaml +++ b/pkg/cli/manifest/testdata/valid.yaml @@ -1,4 +1,7 @@ name: MyCompany.Resources +location: + global: + 'http://localhost:8080' types: testResources: apiVersions: diff --git a/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go b/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go index b36c7471fb..2d9deeeb14 100644 --- a/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go +++ b/pkg/ucp/backend/controller/resourcegroups/trackedresourceprocess_test.go @@ -203,7 +203,6 @@ func Test_Run(t *testing.T) { require.Equal(t, expected, result) require.NoError(t, err) }) - } type mockUpdater struct { diff --git a/pkg/ucp/frontend/controller/radius/proxy_test.go b/pkg/ucp/frontend/controller/radius/proxy_test.go index 4629db95fd..108f543731 100644 --- a/pkg/ucp/frontend/controller/radius/proxy_test.go +++ b/pkg/ucp/frontend/controller/radius/proxy_test.go @@ -396,7 +396,6 @@ func Test_ProxyController_PrepareProxyRequest(t *testing.T) { require.Equal(t, "failed to parse downstream URL: parse \"\\ninvalid\": net/url: invalid control character in URL", err.Error()) require.Nil(t, proxyReq) }) - } type mockUpdater struct { diff --git a/pkg/ucp/integrationtests/radius/proxy_test.go b/pkg/ucp/integrationtests/radius/proxy_test.go index b98dec935f..5c93754d61 100644 --- a/pkg/ucp/integrationtests/radius/proxy_test.go +++ b/pkg/ucp/integrationtests/radius/proxy_test.go @@ -36,14 +36,14 @@ import ( const ( apiVersionParameter = "api-version=2023-10-01-preview" - testRadiusPlaneID = "/planes/radius/local" + testRadiusPlaneID = "/planes/radius/test" testResourceNamespace = "System.Test" testResourceGroupID = testRadiusPlaneID + "/resourceGroups/test-rg" - testResourceProviderID = "/planes/radius/local/providers/System.Resources/resourceproviders/System.Test" + testResourceProviderID = testRadiusPlaneID + "/providers/System.Resources/resourceproviders/System.Test" testResourceCollectionID = testResourceGroupID + "/providers/System.Test/testResources" testResourceID = testResourceCollectionID + "/test-resource" - resourceTypeURL = "/planes/radius/local/providers/System.Resources/resourceproviders/System.Test/resourcetypes/testResources" - locationID = "/planes/radius/local/providers/System.Resources/resourceproviders/System.Test/locations/global" + resourceTypeURL = testResourceProviderID + "/resourcetypes/testResources" + locationID = testResourceProviderID + "/locations/global" assertTimeout = time.Second * 10 assertRetry = time.Second * 2 @@ -60,7 +60,7 @@ func Test_RadiusPlane_Proxy_ResourceGroupDoesNotExist(t *testing.T) { response := ucp.MakeRequest(http.MethodGet, testResourceID+"?api-version="+testrp.Version, nil) response.EqualsErrorCode(http.StatusNotFound, "NotFound") - require.Equal(t, "the resource with id '/planes/radius/local/resourceGroups/test-rg/providers/System.Test/testResources/test-resource' was not found: resource group \"/planes/radius/local/resourceGroups/test-rg\" not found", response.Error.Error.Message) + require.Equal(t, "the resource with id '/planes/radius/test/resourceGroups/test-rg/providers/System.Test/testResources/test-resource' was not found: resource group \"/planes/radius/test/resourceGroups/test-rg\" not found", response.Error.Error.Message) } func Test_RadiusPlane_ResourceSync(t *testing.T) { diff --git a/pkg/ucp/integrationtests/resourceproviders/testdata/manifests/resourceprovider-valid1.yaml b/pkg/ucp/integrationtests/resourceproviders/testdata/manifests/resourceprovider-valid1.yaml index 4523f045df..02118b74c2 100644 --- a/pkg/ucp/integrationtests/resourceproviders/testdata/manifests/resourceprovider-valid1.yaml +++ b/pkg/ucp/integrationtests/resourceproviders/testdata/manifests/resourceprovider-valid1.yaml @@ -1,4 +1,7 @@ name: TestProvider.TestCompany +location: + global: + 'http://localhost:8080' types: testResourcesAbc: apiVersions: diff --git a/test/functional-portable/ucp/noncloud/resourceprovider_test.go b/test/functional-portable/ucp/noncloud/resourceprovider_test.go index ba70e34263..95f46fb63b 100644 --- a/test/functional-portable/ucp/noncloud/resourceprovider_test.go +++ b/test/functional-portable/ucp/noncloud/resourceprovider_test.go @@ -38,7 +38,7 @@ func Test_ResourceProviderRegistration(t *testing.T) { manifestPath = "testdata/resourceprovider.yaml" resourceProviderName = "MyCompany.Resources" expectedResourceTypeName = "testResources" - expectedApiVersion = "2025-01-01-preview" + expectedApiVersion = "2023-10-01-preview" ) expectedData := map[string]any{ From 22ac115a10681102501645a334dea3fd06ac1f20 Mon Sep 17 00:00:00 2001 From: lakshmimsft Date: Fri, 17 Jan 2025 14:44:24 -0800 Subject: [PATCH 3/3] waiting for registered manifests Signed-off-by: lakshmimsft --- .github/workflows/functional-test-cloud.yaml | 43 +++++++++++++++++++ .../workflows/functional-test-noncloud.yaml | 43 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/.github/workflows/functional-test-cloud.yaml b/.github/workflows/functional-test-cloud.yaml index a15b0c6e22..2613e5c616 100644 --- a/.github/workflows/functional-test-cloud.yaml +++ b/.github/workflows/functional-test-cloud.yaml @@ -657,6 +657,49 @@ jobs: --set global.azureWorkloadIdentity.enabled=true \ --set global.aws.irsa.enabled=true + echo "*** Verify manifests are registered ***" + rm -f registermanifest_logs.txt + # Find the pod with container "ucp" + POD_NAME=$( + kubectl get pods -n radius-system \ + -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.spec.containers[*].name}{"\n"}{end}' \ + | grep "ucp" \ + | head -n1 \ + | cut -d" " -f1 + ) + echo "Found ucp pod: $POD_NAME" + + if [ -z "$POD_NAME" ]; then + echo "No pod with container 'ucp' found in namespace radius-system." + exit 1 + fi + + # Poll logs for up to iterations, 30 seconds each (upto 3 minutes total) + for i in {1..6}; do + kubectl logs "$POD_NAME" -n radius-system | tee registermanifest_logs.txt > /dev/null + + # Exit on error + if grep -qi "error" registermanifest_logs.txt; then + echo "Error found in ucp logs." + exit 1 + fi + + # Check for success + if grep -q "Successfully registered manifests" registermanifest_logs.txt; then + echo "Successfully registered manifests - message found." + break + fi + + echo "Logs not ready, waiting 30 seconds..." + sleep 30 + done + + # Final check to ensure success message was found + if ! grep -q "Successfully registered manifests" registermanifest_logs.txt; then + echo "Manifests not registered after 3 minutes." + exit 1 + fi + echo "*** Create workspace, group and environment for test ***" rad workspace create kubernetes rad group create kind-radius diff --git a/.github/workflows/functional-test-noncloud.yaml b/.github/workflows/functional-test-noncloud.yaml index a0af5c4844..0ff7586d9b 100644 --- a/.github/workflows/functional-test-noncloud.yaml +++ b/.github/workflows/functional-test-noncloud.yaml @@ -290,6 +290,49 @@ jobs: echo "*** Installing Radius to Kubernetes ***" eval $RAD_COMMAND + echo "*** Verify manifests are registered ***" + rm -f registermanifest_logs.txt + # Find the pod with container "ucp" + POD_NAME=$( + kubectl get pods -n radius-system \ + -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.spec.containers[*].name}{"\n"}{end}' \ + | grep "ucp" \ + | head -n1 \ + | cut -d" " -f1 + ) + echo "Found ucp pod: $POD_NAME" + + if [ -z "$POD_NAME" ]; then + echo "No pod with container 'ucp' found in namespace radius-system." + exit 1 + fi + + # Poll logs for up to iterations, 30 seconds each (upto 3 minutes total) + for i in {1..6}; do + kubectl logs "$POD_NAME" -n radius-system | tee registermanifest_logs.txt > /dev/null + + # Exit on error + if grep -qi "error" registermanifest_logs.txt; then + echo "Error found in ucp logs." + exit 1 + fi + + # Check for success + if grep -q "Successfully registered manifests" registermanifest_logs.txt; then + echo "Successfully registered manifests - message found." + break + fi + + echo "Logs not ready, waiting 30 seconds..." + sleep 30 + done + + # Final check to ensure success message was found + if ! grep -q "Successfully registered manifests" registermanifest_logs.txt; then + echo "Manifests not registered after 3 minutes." + exit 1 + fi + echo "*** Create workspace, group and environment for test ***" rad workspace create kubernetes rad group create kind-radius