diff --git a/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json b/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json index 794fc677c2..7b95e10918 100644 --- a/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json +++ b/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json @@ -805,12 +805,19 @@ "$type": "ObjectType", "name": "ProvidersAws", "properties": { - "scope": { + "accountId": { "type": { "$ref": "#/0" }, "flags": 1, - "description": "Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'." + "description": "AWS account ID for AWS resources to be deployed into." + }, + "region": { + "type": { + "$ref": "#/0" + }, + "flags": 1, + "description": "AWS region for AWS resources to be deployed into." } } }, diff --git a/pkg/cli/cmd/env/show/preview/show.go b/pkg/cli/cmd/env/show/preview/show.go index e47800943e..2d2fe9776d 100644 --- a/pkg/cli/cmd/env/show/preview/show.go +++ b/pkg/cli/cmd/env/show/preview/show.go @@ -73,6 +73,15 @@ type EnvRecipes struct { RecipeLocation string } +// EnvProviders represents a provider and its properties for an environment. +type EnvProviders struct { + // Provider is the type of the provider (e.g., "azure", "aws", "kubernetes"). + Provider string + // Properties contains the provider details in a comma-separated key-value format. + // e.g., "subscriptionId: 'sub-id', resourceGroupName: 'rg-name'" for azure provider." + Properties string +} + // Runner is the runner implementation for the `rad env show` preview command. type Runner struct { ConfigHolder *framework.ConfigHolder @@ -136,6 +145,32 @@ func (r *Runner) Run(ctx context.Context) error { return err } + envProviders := []EnvProviders{} + if resp.EnvironmentResource.Properties.Providers != nil { + if resp.EnvironmentResource.Properties.Providers.Azure != nil { + azureProvider := EnvProviders{ + Provider: "azure", + } + azureProvider.Properties = "subscriptionId: '" + *resp.EnvironmentResource.Properties.Providers.Azure.SubscriptionID + "', resourceGroupName: '" + *resp.EnvironmentResource.Properties.Providers.Azure.ResourceGroupName + "'" + envProviders = append(envProviders, azureProvider) + } + + if resp.EnvironmentResource.Properties.Providers.Aws != nil { + awsProvider := EnvProviders{ + Provider: "aws", + } + awsProvider.Properties = "accountId: '" + *resp.EnvironmentResource.Properties.Providers.Aws.AccountID + "', region: '" + *resp.EnvironmentResource.Properties.Providers.Aws.Region + "'" + envProviders = append(envProviders, awsProvider) + } + if resp.EnvironmentResource.Properties.Providers.Kubernetes != nil { + k8sProvider := EnvProviders{ + Provider: "kubernetes", + } + k8sProvider.Properties = "namespace: '" + *resp.EnvironmentResource.Properties.Providers.Kubernetes.Namespace + "'" + envProviders = append(envProviders, k8sProvider) + } + } + recipepackClient := r.RadiusCoreClientFactory.NewRecipePacksClient() envRecipes := []EnvRecipes{} for _, rp := range resp.EnvironmentResource.Properties.RecipePacks { @@ -183,6 +218,12 @@ func (r *Runner) Run(ctx context.Context) error { if err != nil { return err } + r.Output.LogInfo("") + + err = r.Output.WriteFormatted(r.Format, envProviders, objectformats.GetProvidersForEnvironmentTableFormat()) + if err != nil { + return err + } r.Output.LogInfo("") err = r.Output.WriteFormatted(r.Format, envRecipes, objectformats.GetRecipesForEnvironmentTableFormat()) diff --git a/pkg/cli/cmd/env/show/preview/show_test.go b/pkg/cli/cmd/env/show/preview/show_test.go index ffe73ade4d..36cfadd36d 100644 --- a/pkg/cli/cmd/env/show/preview/show_test.go +++ b/pkg/cli/cmd/env/show/preview/show_test.go @@ -118,6 +118,19 @@ func Test_Run(t *testing.T) { RecipePacks: []*string{ to.Ptr("/planes/radius/local/resourceGroups/test-group/providers/Radius.Core/recipePacks/test-recipe-pack"), }, + Providers: &corerpv20250801.Providers{ + Azure: &corerpv20250801.ProvidersAzure{ + SubscriptionID: to.Ptr("test-subscription-id"), + ResourceGroupName: to.Ptr("test-resource-group"), + }, + Aws: &corerpv20250801.ProvidersAws{ + AccountID: to.Ptr("test-account-id"), + Region: to.Ptr("test-region"), + }, + Kubernetes: &corerpv20250801.ProvidersKubernetes{ + Namespace: to.Ptr("test-namespace"), + }, + }, }, }, Options: objectformats.GetResourceTableFormat(), @@ -125,6 +138,27 @@ func Test_Run(t *testing.T) { output.LogOutput{ Format: "", }, + output.FormattedOutput{ + Format: "table", + Obj: []EnvProviders{ + { + Provider: "azure", + Properties: "subscriptionId: 'test-subscription-id', resourceGroupName: 'test-resource-group'", + }, + { + Provider: "aws", + Properties: "accountId: 'test-account-id', region: 'test-region'", + }, + { + Provider: "kubernetes", + Properties: "namespace: 'test-namespace'", + }, + }, + Options: objectformats.GetProvidersForEnvironmentTableFormat(), + }, + output.LogOutput{ + Format: "", + }, output.FormattedOutput{ Format: "table", Obj: []EnvRecipes{ diff --git a/pkg/cli/cmd/env/update/preview/update.go b/pkg/cli/cmd/env/update/preview/update.go index 0f9ee12b1c..0f1d6ac7af 100644 --- a/pkg/cli/cmd/env/update/preview/update.go +++ b/pkg/cli/cmd/env/update/preview/update.go @@ -18,7 +18,6 @@ package preview import ( "context" - "fmt" "github.com/spf13/cobra" @@ -37,7 +36,6 @@ import ( const ( envNotFoundErrMessageFmt = "The environment %q does not exist. Please select a new environment and try again." - awsScopeTemplate = "/planes/aws/aws/accounts/%s/regions/%s" ) // NewCommand creates an instance of the command and runner for the `rad env update` preview command. @@ -87,8 +85,8 @@ rad env update myenv --clear-kubernetes commonflags.AddResourceGroupFlag(cmd) cmd.Flags().Bool(commonflags.ClearEnvAzureFlag, false, "Specify if azure provider needs to be cleared on env") cmd.Flags().Bool(commonflags.ClearEnvAWSFlag, false, "Specify if aws provider needs to be cleared on env") - cmd.Flags().Bool(commonflags.ClearEnvKubernetesFlag, false, "Specify if kubernetes provider needs to be cleared on env (preview)") - cmd.Flags().StringArrayP("recipe-packs", "", []string{}, "Specify recipe packs to be added to the environment (preview)") + cmd.Flags().Bool(commonflags.ClearEnvKubernetesFlag, false, "Specify if kubernetes provider needs to be cleared on env (--preview)") + cmd.Flags().StringArrayP("recipe-packs", "", []string{}, "Specify recipe packs to be added to the environment (--preview)") commonflags.AddAzureScopeFlags(cmd) commonflags.AddAWSScopeFlags(cmd) commonflags.AddKubernetesScopeFlags(cmd) @@ -185,7 +183,8 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { return err } - r.providers.Aws.Scope = to.Ptr(fmt.Sprintf(awsScopeTemplate, awsAccountId, awsRegion)) + r.providers.Aws.Region = to.Ptr(awsRegion) + r.providers.Aws.AccountID = to.Ptr(awsAccountId) } r.clearEnvAws, err = cmd.Flags().GetBool(commonflags.ClearEnvAWSFlag) @@ -257,10 +256,11 @@ func (r *Runner) Run(ctx context.Context) error { // only update aws provider info if user requires it. if r.clearEnvAws && env.Properties.Providers != nil { env.Properties.Providers.Aws = nil - } else if r.providers.Aws != nil && r.providers.Aws.Scope != nil { + } else if r.providers.Aws != nil && (r.providers.Aws.AccountID != nil && r.providers.Aws.Region != nil) { if env.Properties.Providers == nil { env.Properties.Providers = &corerpv20250801.Providers{} } + env.Properties.Providers.Aws = r.providers.Aws } diff --git a/pkg/cli/cmd/env/update/preview/update_test.go b/pkg/cli/cmd/env/update/preview/update_test.go index 137e3b8dd0..0718ed3f8c 100644 --- a/pkg/cli/cmd/env/update/preview/update_test.go +++ b/pkg/cli/cmd/env/update/preview/update_test.go @@ -151,7 +151,8 @@ func Test_Run(t *testing.T) { ResourceGroupName: to.Ptr("testResourceGroup"), }, Aws: &v20250801preview.ProvidersAws{ - Scope: to.Ptr("test-aws-scope"), + Region: to.Ptr("us-west-2"), + AccountID: to.Ptr("testAWSAccount"), }, Kubernetes: &v20250801preview.ProvidersKubernetes{ Namespace: to.Ptr("test-namespace"), diff --git a/pkg/cli/objectformats/objectformats.go b/pkg/cli/objectformats/objectformats.go index ef4efd7710..16ae8233a1 100644 --- a/pkg/cli/objectformats/objectformats.go +++ b/pkg/cli/objectformats/objectformats.go @@ -150,3 +150,18 @@ func GetRecipesForEnvironmentTableFormat() output.FormatterOptions { }, } } + +func GetProvidersForEnvironmentTableFormat() output.FormatterOptions { + return output.FormatterOptions{ + Columns: []output.Column{ + { + Heading: "PROVIDER", + JSONPath: "{ .Provider }", + }, + { + Heading: "PROPERTIES", + JSONPath: "{ .Properties }", + }, + }, + } +} diff --git a/pkg/cli/test_client_factory/radius_core.go b/pkg/cli/test_client_factory/radius_core.go index cce0feffe2..6dfdea051e 100644 --- a/pkg/cli/test_client_factory/radius_core.go +++ b/pkg/cli/test_client_factory/radius_core.go @@ -108,6 +108,19 @@ func WithEnvironmentServerNoError() corerpfake.EnvironmentsServer { EnvironmentResource: v20250801preview.EnvironmentResource{ Name: to.Ptr(environmentName), Properties: &v20250801preview.EnvironmentProperties{ + Providers: &v20250801preview.Providers{ + Azure: &v20250801preview.ProvidersAzure{ + SubscriptionID: to.Ptr("test-subscription-id"), + ResourceGroupName: to.Ptr("test-resource-group"), + }, + Aws: &v20250801preview.ProvidersAws{ + AccountID: to.Ptr("test-account-id"), + Region: to.Ptr("test-region"), + }, + Kubernetes: &v20250801preview.ProvidersKubernetes{ + Namespace: to.Ptr("test-namespace"), + }, + }, RecipePacks: []*string{ to.Ptr("/planes/radius/local/resourceGroups/test-group/providers/Radius.Core/recipePacks/test-recipe-pack"), }, diff --git a/pkg/corerp/api/v20250801preview/environment_conversion.go b/pkg/corerp/api/v20250801preview/environment_conversion.go index 1a3221c822..664b6f4bfc 100644 --- a/pkg/corerp/api/v20250801preview/environment_conversion.go +++ b/pkg/corerp/api/v20250801preview/environment_conversion.go @@ -142,7 +142,8 @@ func toProvidersDataModel(providers *Providers) *datamodel.Providers_v20250801pr // Convert AWS provider if providers.Aws != nil { result.AWS = &datamodel.ProvidersAWS_v20250801preview{ - Scope: to.String(providers.Aws.Scope), + Region: to.String(providers.Aws.Region), + AccountID: to.String(providers.Aws.AccountID), } } @@ -184,7 +185,8 @@ func fromProvidersDataModel(providers *datamodel.Providers_v20250801preview) *Pr // Convert AWS provider if providers.AWS != nil { result.Aws = &ProvidersAws{ - Scope: to.Ptr(providers.AWS.Scope), + Region: to.Ptr(providers.AWS.Region), + AccountID: to.Ptr(providers.AWS.AccountID), } } diff --git a/pkg/corerp/api/v20250801preview/zz_generated_models.go b/pkg/corerp/api/v20250801preview/zz_generated_models.go index 0d3e1bbb5f..6cc3a1a5c5 100644 --- a/pkg/corerp/api/v20250801preview/zz_generated_models.go +++ b/pkg/corerp/api/v20250801preview/zz_generated_models.go @@ -394,8 +394,11 @@ type Providers struct { // ProvidersAws - The AWS cloud provider definition. type ProvidersAws struct { - // REQUIRED; Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'. - Scope *string + // REQUIRED; AWS account ID for AWS resources to be deployed into. + AccountID *string + + // REQUIRED; AWS region for AWS resources to be deployed into. + Region *string } // ProvidersAzure - The Azure cloud provider definition. diff --git a/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go b/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go index 8cc8a0adca..56b3d37efb 100644 --- a/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go +++ b/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go @@ -961,7 +961,8 @@ func (p *Providers) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaller interface for type ProvidersAws. func (p ProvidersAws) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) - populate(objectMap, "scope", p.Scope) + populate(objectMap, "accountId", p.AccountID) + populate(objectMap, "region", p.Region) return json.Marshal(objectMap) } @@ -974,8 +975,11 @@ func (p *ProvidersAws) UnmarshalJSON(data []byte) error { for key, val := range rawMsg { var err error switch key { - case "scope": - err = unpopulate(val, "Scope", &p.Scope) + case "accountId": + err = unpopulate(val, "AccountID", &p.AccountID) + delete(rawMsg, key) + case "region": + err = unpopulate(val, "Region", &p.Region) delete(rawMsg, key) } if err != nil { diff --git a/pkg/corerp/datamodel/environment_v20250801preview.go b/pkg/corerp/datamodel/environment_v20250801preview.go index 049c02cb94..3d40a59218 100644 --- a/pkg/corerp/datamodel/environment_v20250801preview.go +++ b/pkg/corerp/datamodel/environment_v20250801preview.go @@ -84,6 +84,9 @@ type ProvidersKubernetes_v20250801preview struct { // ProvidersAWS_v20250801preview represents the AWS provider configuration. type ProvidersAWS_v20250801preview struct { - // Scope is the target scope for AWS resources to be deployed into. - Scope string `json:"scope"` + // AccountID is the AWS account ID hosting deployed resources. + AccountID string `json:"accountId"` + + // Region is the AWS region hosting deployed resources. + Region string `json:"region"` } diff --git a/pkg/recipes/configloader/environment.go b/pkg/recipes/configloader/environment.go index 894b3fa6e3..00dfaad979 100644 --- a/pkg/recipes/configloader/environment.go +++ b/pkg/recipes/configloader/environment.go @@ -169,7 +169,7 @@ func getConfigurationV20250801(environment *v20250801preview.EnvironmentResource } if envDatamodel.Properties.Providers.AWS != nil { config.Providers.AWS = datamodel.ProvidersAWS{ - Scope: envDatamodel.Properties.Providers.AWS.Scope, + Scope: "/planes/aws/aws/accounts/" + envDatamodel.Properties.Providers.AWS.AccountID + "/regions/" + envDatamodel.Properties.Providers.AWS.Region, } } } diff --git a/pkg/recipes/configloader/environment_test.go b/pkg/recipes/configloader/environment_test.go index ef98ed08d5..7a3da020e9 100644 --- a/pkg/recipes/configloader/environment_test.go +++ b/pkg/recipes/configloader/environment_test.go @@ -435,7 +435,8 @@ func TestGetConfigurationV20250801(t *testing.T) { Properties: &modelv20250801.EnvironmentProperties{ Providers: &modelv20250801.Providers{ Aws: &modelv20250801.ProvidersAws{ - Scope: to.Ptr(awsScope), + AccountID: to.Ptr("000"), + Region: to.Ptr("cool-region"), }, Kubernetes: &modelv20250801.ProvidersKubernetes{ Namespace: to.Ptr(envNamespace), diff --git a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json index 7f03a3cb4f..b44da4f9a3 100644 --- a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json +++ b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json @@ -1304,13 +1304,18 @@ "type": "object", "description": "The AWS cloud provider definition.", "properties": { - "scope": { + "accountId": { "type": "string", - "description": "Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'." + "description": "AWS account ID for AWS resources to be deployed into." + }, + "region": { + "type": "string", + "description": "AWS region for AWS resources to be deployed into." } }, "required": [ - "scope" + "accountId", + "region" ] }, "ProvidersAzure": { diff --git a/typespec/Radius.Core/environments.tsp b/typespec/Radius.Core/environments.tsp index 58a4c38496..fb54e66122 100644 --- a/typespec/Radius.Core/environments.tsp +++ b/typespec/Radius.Core/environments.tsp @@ -88,8 +88,11 @@ model ProvidersKubernetes { @doc("The AWS cloud provider definition.") model ProvidersAws { - @doc("Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'.") - scope: string; + @doc("AWS account ID for AWS resources to be deployed into.") + accountId: string; + + @doc("AWS region for AWS resources to be deployed into.") + region: string; } model Providers {