From 39a052a52198a7e8ab012d7eaa34eb70aa90a86f Mon Sep 17 00:00:00 2001 From: aristosvo <8375124+aristosvo@users.noreply.github.com> Date: Mon, 1 Jan 2024 14:03:37 +0100 Subject: [PATCH 1/5] `r/azurerm_container_app_environment`: add `infrastructure_resource_group_name` --- .../container_app_environment_resource.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/internal/services/containerapps/container_app_environment_resource.go b/internal/services/containerapps/container_app_environment_resource.go index a8edc920dace..449379d12bcd 100644 --- a/internal/services/containerapps/container_app_environment_resource.go +++ b/internal/services/containerapps/container_app_environment_resource.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourcegroups" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" "github.com/hashicorp/go-azure-sdk/resource-manager/containerapps/2023-05-01/managedenvironments" "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" @@ -36,6 +37,7 @@ type ContainerAppEnvironmentModel struct { ZoneRedundant bool `tfschema:"zone_redundancy_enabled"` Tags map[string]interface{} `tfschema:"tags"` WorkloadProfiles []helpers.WorkloadProfileModel `tfschema:"workload_profile"` + InfrastructureResourceGroup string `tfschema:"infrastructure_resource_group_name"` DefaultDomain string `tfschema:"default_domain"` DockerBridgeCidr string `tfschema:"docker_bridge_cidr"` @@ -89,6 +91,14 @@ func (r ContainerAppEnvironmentResource) Arguments() map[string]*pluginsdk.Schem Description: "The ID for the Log Analytics Workspace to link this Container Apps Managed Environment to.", }, + "infrastructure_resource_group_name": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: resourcegroups.ValidateName, + Description: "Name of the platform-managed resource group created for the Managed Environment to host infrastructure resources. If `infrastructure_subnet_id` is specified, this resource group will be created in the same subscription as `infrastructure_subnet_id`.", + }, + "infrastructure_subnet_id": { Type: pluginsdk.TypeString, Optional: true, @@ -195,6 +205,10 @@ func (r ContainerAppEnvironmentResource) Create() sdk.ResourceFunc { managedEnvironment.Properties.DaprAIConnectionString = pointer.To(containerAppEnvironment.DaprApplicationInsightsConnectionString) } + if containerAppEnvironment.InfrastructureResourceGroup != "" { + managedEnvironment.Properties.InfrastructureResourceGroup = pointer.To(containerAppEnvironment.InfrastructureResourceGroup) + } + if containerAppEnvironment.LogAnalyticsWorkspaceId != "" { logAnalyticsId, err := workspaces.ParseWorkspaceID(containerAppEnvironment.LogAnalyticsWorkspaceId) if err != nil { @@ -286,6 +300,7 @@ func (r ContainerAppEnvironmentResource) Read() sdk.ResourceFunc { state.StaticIP = pointer.From(props.StaticIP) state.DefaultDomain = pointer.From(props.DefaultDomain) state.WorkloadProfiles = helpers.FlattenWorkloadProfiles(props.WorkloadProfiles) + state.InfrastructureResourceGroup = pointer.From(props.InfrastructureResourceGroup) } } From 8c229eceedfc7daccecdaa99217eea6352e8d2eb Mon Sep 17 00:00:00 2001 From: aristosvo <8375124+aristosvo@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:53:31 +0100 Subject: [PATCH 2/5] tests: add first test --- ...container_app_environment_resource_test.go | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/internal/services/containerapps/container_app_environment_resource_test.go b/internal/services/containerapps/container_app_environment_resource_test.go index e304eeaf018d..066a2d5746b9 100644 --- a/internal/services/containerapps/container_app_environment_resource_test.go +++ b/internal/services/containerapps/container_app_environment_resource_test.go @@ -160,6 +160,21 @@ func TestAccContainerAppEnvironment_zoneRedundant(t *testing.T) { }) } +func TestAccContainerAppEnvironment_infraResourceGroup(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_app_environment", "test") + r := ContainerAppEnvironmentResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.infraResourceGroup(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (r ContainerAppEnvironmentResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := managedenvironments.ParseManagedEnvironmentID(state.ID) if err != nil { @@ -399,3 +414,57 @@ resource "azurerm_subnet" "control" { `, r.template(data), data.RandomInteger) } + +func (r ContainerAppEnvironmentResource) infraResourceGroup(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%[1]s + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%[2]d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "control" { + name = "control-plane" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.0.0/23"] + delegation { + name = "acctestdelegation%[2]d" + service_delegation { + actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"] + name = "Microsoft.App/environments" + } + } +} + +resource "azurerm_container_app_environment" "test" { + name = "acctest-CAEnv%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + infrastructure_subnet_id = azurerm_subnet.control.id + + infrastructure_resource_group_name = "rg-acctest-CAEnv%[2]d" + + workload_profile { + maximum_count = 2 + minimum_count = 0 + name = "My-GP-01" + workload_profile_type = "D4" + } + + zone_redundancy_enabled = true + + tags = { + Foo = "Bar" + secret = "sauce" + } +} +`, r.template(data), data.RandomInteger) +} From 4ac932949e170b55ee01cc18ea9bcedc7969890c Mon Sep 17 00:00:00 2001 From: aristosvo <8375124+aristosvo@users.noreply.github.com> Date: Mon, 1 Jan 2024 19:58:21 +0100 Subject: [PATCH 3/5] feat: make `workload_profile` required with `infrastructure_resource_group_name` --- .../containerapps/container_app_environment_resource.go | 2 +- .../containerapps/helpers/container_app_environment.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/services/containerapps/container_app_environment_resource.go b/internal/services/containerapps/container_app_environment_resource.go index 449379d12bcd..bfc2303e0b7f 100644 --- a/internal/services/containerapps/container_app_environment_resource.go +++ b/internal/services/containerapps/container_app_environment_resource.go @@ -96,7 +96,7 @@ func (r ContainerAppEnvironmentResource) Arguments() map[string]*pluginsdk.Schem Optional: true, ForceNew: true, ValidateFunc: resourcegroups.ValidateName, - Description: "Name of the platform-managed resource group created for the Managed Environment to host infrastructure resources. If `infrastructure_subnet_id` is specified, this resource group will be created in the same subscription as `infrastructure_subnet_id`.", + Description: "Name of the platform-managed resource group created for the Managed Environment to host infrastructure resources. **Note:** Only valid if a `workload_profile` is specified. If `infrastructure_subnet_id` is specified, this resource group will be created in the same subscription as `infrastructure_subnet_id`.", }, "infrastructure_subnet_id": { diff --git a/internal/services/containerapps/helpers/container_app_environment.go b/internal/services/containerapps/helpers/container_app_environment.go index 736798edb5ae..ab0da5f72534 100644 --- a/internal/services/containerapps/helpers/container_app_environment.go +++ b/internal/services/containerapps/helpers/container_app_environment.go @@ -23,8 +23,9 @@ type WorkloadProfileModel struct { func WorkloadProfileSchema() *pluginsdk.Schema { return &pluginsdk.Schema{ - Type: pluginsdk.TypeSet, - Optional: true, + Type: pluginsdk.TypeSet, + Optional: true, + RequiredWith: []string{"infrastructure_resource_group_name"}, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "name": { From 7baf3540bbc92f776246886e432b398b8ba557a1 Mon Sep 17 00:00:00 2001 From: aristosvo <8375124+aristosvo@users.noreply.github.com> Date: Mon, 1 Jan 2024 20:48:39 +0100 Subject: [PATCH 4/5] fix: reverse RequiredWith attribute --- .../containerapps/container_app_environment_resource.go | 2 ++ .../containerapps/helpers/container_app_environment.go | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/services/containerapps/container_app_environment_resource.go b/internal/services/containerapps/container_app_environment_resource.go index bfc2303e0b7f..936bd80d025e 100644 --- a/internal/services/containerapps/container_app_environment_resource.go +++ b/internal/services/containerapps/container_app_environment_resource.go @@ -94,7 +94,9 @@ func (r ContainerAppEnvironmentResource) Arguments() map[string]*pluginsdk.Schem "infrastructure_resource_group_name": { Type: pluginsdk.TypeString, Optional: true, + Computed: true, ForceNew: true, + RequiredWith: []string{"workload_profile"}, ValidateFunc: resourcegroups.ValidateName, Description: "Name of the platform-managed resource group created for the Managed Environment to host infrastructure resources. **Note:** Only valid if a `workload_profile` is specified. If `infrastructure_subnet_id` is specified, this resource group will be created in the same subscription as `infrastructure_subnet_id`.", }, diff --git a/internal/services/containerapps/helpers/container_app_environment.go b/internal/services/containerapps/helpers/container_app_environment.go index ab0da5f72534..736798edb5ae 100644 --- a/internal/services/containerapps/helpers/container_app_environment.go +++ b/internal/services/containerapps/helpers/container_app_environment.go @@ -23,9 +23,8 @@ type WorkloadProfileModel struct { func WorkloadProfileSchema() *pluginsdk.Schema { return &pluginsdk.Schema{ - Type: pluginsdk.TypeSet, - Optional: true, - RequiredWith: []string{"infrastructure_resource_group_name"}, + Type: pluginsdk.TypeSet, + Optional: true, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "name": { From 8857e9701d89d7e4f72c1ac668ec8099aadaf849 Mon Sep 17 00:00:00 2001 From: aristosvo <8375124+aristosvo@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:31:09 +0100 Subject: [PATCH 5/5] Docs --- website/docs/r/container_app_environment.html.markdown | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/website/docs/r/container_app_environment.html.markdown b/website/docs/r/container_app_environment.html.markdown index 608042096844..94a232cd965e 100644 --- a/website/docs/r/container_app_environment.html.markdown +++ b/website/docs/r/container_app_environment.html.markdown @@ -48,6 +48,10 @@ The following arguments are supported: * `dapr_application_insights_connection_string` - (Optional) Application Insights connection string used by Dapr to export Service to Service communication telemetry. Changing this forces a new resource to be created. +* `infrastructure_resource_group_name` - (Optional) Name of the platform-managed resource group created for the Managed Environment to host infrastructure resources. Changing this forces a new resource to be created. + +~> **Note:** Only valid if a `workload_profile` is specified. If `infrastructure_subnet_id` is specified, this resource group will be created in the same subscription as `infrastructure_subnet_id`. + * `infrastructure_subnet_id` - (Optional) The existing Subnet to use for the Container Apps Control Plane. Changing this forces a new resource to be created. ~> **NOTE:** The Subnet must have a `/21` or larger address space. @@ -74,9 +78,9 @@ A `workload_profile` block supports the following: * `workload_profile_type` - (Required) Workload profile type for the workloads to run on. Possible values include `D4`, `D8`, `D16`, `D32`, `E4`, `E8`, `E16` and `E32`. -* `maximum_count` - (Optional) The maximum number of instances of workload profile that can be deployed in the Container App Environment. +* `maximum_count` - (Required) The maximum number of instances of workload profile that can be deployed in the Container App Environment. -* `minimum_count` - (Optional) The minimum number of instances of workload profile that can be deployed in the Container App Environment. +* `minimum_count` - (Required) The minimum number of instances of workload profile that can be deployed in the Container App Environment. ## Attributes Reference