From 885e38ca8113988b0874b05c65ac72262a6319e4 Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 13 Oct 2025 16:29:19 +0800 Subject: [PATCH 1/2] azurerm_container_app: Add support for kind --- .../container_app_data_source.go | 11 ++ .../containerapps/container_app_resource.go | 25 +++- .../container_app_resource_test.go | 112 ++++++++++++++++++ website/docs/d/container_app.html.markdown | 2 + website/docs/r/container_app.html.markdown | 2 + 5 files changed, 151 insertions(+), 1 deletion(-) diff --git a/internal/services/containerapps/container_app_data_source.go b/internal/services/containerapps/container_app_data_source.go index 7376abd4ce16..6c7b190834e0 100644 --- a/internal/services/containerapps/container_app_data_source.go +++ b/internal/services/containerapps/container_app_data_source.go @@ -29,6 +29,7 @@ type ContainerAppDataSourceModel struct { ResourceGroup string `tfschema:"resource_group_name"` ManagedEnvironmentId string `tfschema:"container_app_environment_id"` Location string `tfschema:"location"` + Kind string `tfschema:"kind"` RevisionMode string `tfschema:"revision_mode"` MaxInactiveRevisions int64 `tfschema:"max_inactive_revisions"` Ingress []helpers.Ingress `tfschema:"ingress"` @@ -73,6 +74,12 @@ func (r ContainerAppDataSource) Attributes() map[string]*pluginsdk.Schema { Computed: true, }, + "kind": { + Type: pluginsdk.TypeString, + Computed: true, + Description: "The kind of container app.", + }, + "ingress": helpers.ContainerAppIngressSchemaComputed(), "registry": helpers.ContainerAppRegistrySchemaComputed(), @@ -163,6 +170,10 @@ func (r ContainerAppDataSource) Read() sdk.ResourceFunc { containerApp.Location = location.Normalize(model.Location) containerApp.Tags = tags.Flatten(model.Tags) + if model.Kind != nil { + containerApp.Kind = string(pointer.From(model.Kind)) + } + if props := model.Properties; props != nil { envId, err := managedenvironments.ParseManagedEnvironmentIDInsensitively(pointer.From(props.ManagedEnvironmentId)) if err != nil { diff --git a/internal/services/containerapps/container_app_resource.go b/internal/services/containerapps/container_app_resource.go index 9079ffcf9679..c3750efd53e8 100644 --- a/internal/services/containerapps/container_app_resource.go +++ b/internal/services/containerapps/container_app_resource.go @@ -32,6 +32,7 @@ type ContainerAppModel struct { ManagedEnvironmentId string `tfschema:"container_app_environment_id"` Location string `tfschema:"location"` + Kind string `tfschema:"kind"` RevisionMode string `tfschema:"revision_mode"` Ingress []helpers.Ingress `tfschema:"ingress"` Registries []helpers.Registry `tfschema:"registry"` @@ -97,7 +98,15 @@ func (r ContainerAppResource) Arguments() map[string]*pluginsdk.Schema { }, false), }, - "ingress": helpers.ContainerAppIngressSchema(), + "kind": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(containerapps.KindFunctionapp), + string(containerapps.KindWorkflowapp), + }, false), + Description: "The kind of container app. Possible values include: `functionapp`, `workflowapp`. This value is not returned by the API and will be stored in the Terraform state only.", + }, "ingress": helpers.ContainerAppIngressSchema(), "registry": helpers.ContainerAppRegistrySchema(), @@ -219,6 +228,10 @@ func (r ContainerAppResource) Create() sdk.ResourceFunc { Tags: tags.Expand(app.Tags), } + if app.Kind != "" { + containerApp.Kind = pointer.To(containerapps.Kind(app.Kind)) + } + ident, err := identity.ExpandSystemAndUserAssignedMapFromModel(app.Identity) if err != nil { return err @@ -262,6 +275,8 @@ func (r ContainerAppResource) Read() sdk.ResourceFunc { state.Name = id.ContainerAppName state.ResourceGroup = id.ResourceGroupName + state.Kind = metadata.ResourceData.Get("kind").(string) + if model := existing.Model; model != nil { state.Location = location.Normalize(model.Location) state.Tags = tags.Flatten(model.Tags) @@ -427,6 +442,14 @@ func (r ContainerAppResource) Update() sdk.ResourceFunc { model.Tags = tags.Expand(state.Tags) } + if metadata.ResourceData.HasChange("kind") { + if state.Kind != "" { + model.Kind = pointer.To(containerapps.Kind(state.Kind)) + } else { + model.Kind = nil + } + } + model.Properties.Template = helpers.ExpandContainerAppTemplate(state.Template, metadata) if err := client.CreateOrUpdateThenPoll(ctx, *id, *model); err != nil { diff --git a/internal/services/containerapps/container_app_resource_test.go b/internal/services/containerapps/container_app_resource_test.go index 5093668e56a5..49cbcc15a652 100644 --- a/internal/services/containerapps/container_app_resource_test.go +++ b/internal/services/containerapps/container_app_resource_test.go @@ -35,6 +35,72 @@ func TestAccContainerAppResource_basic(t *testing.T) { }) } +func TestAccContainerAppResource_kindFunctionApp(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_app", "test") + r := ContainerAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withKindFunctionApp(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("kind"), + }) +} + +func TestAccContainerAppResource_kindWorkflowApp(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_app", "test") + r := ContainerAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withKindWorkflowApp(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("kind"), + }) +} + +func TestAccContainerAppResource_kindUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_app", "test") + r := ContainerAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("kind"), + { + Config: r.withKindFunctionApp(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("kind"), + { + Config: r.withKindWorkflowApp(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("kind"), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("kind"), + }) +} + func TestAccContainerAppResource_workloadProfile(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_container_app", "test") r := ContainerAppResource{} @@ -663,6 +729,52 @@ resource "azurerm_container_app" "test" { `, r.template(data), data.RandomInteger) } +func (r ContainerAppResource) withKindFunctionApp(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_container_app" "test" { + name = "acctest-capp-%[2]d" + resource_group_name = azurerm_resource_group.test.name + container_app_environment_id = azurerm_container_app_environment.test.id + revision_mode = "Single" + kind = "functionapp" + + template { + container { + name = "acctest-cont-%[2]d" + image = "jackofallops/azure-containerapps-python-acctest:v0.0.1" + cpu = 0.25 + memory = "0.5Gi" + } + } +} +`, r.template(data), data.RandomInteger) +} + +func (r ContainerAppResource) withKindWorkflowApp(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_container_app" "test" { + name = "acctest-capp-%[2]d" + resource_group_name = azurerm_resource_group.test.name + container_app_environment_id = azurerm_container_app_environment.test.id + revision_mode = "Single" + kind = "workflowapp" + + template { + container { + name = "acctest-cont-%[2]d" + image = "jackofallops/azure-containerapps-python-acctest:v0.0.1" + cpu = 0.25 + memory = "0.5Gi" + } + } +} +`, r.template(data), data.RandomInteger) +} + func (r ContainerAppResource) withSystemIdentity(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/website/docs/d/container_app.html.markdown b/website/docs/d/container_app.html.markdown index 59efdd81daad..9a46cf6b19a0 100644 --- a/website/docs/d/container_app.html.markdown +++ b/website/docs/d/container_app.html.markdown @@ -35,6 +35,8 @@ In addition to the Arguments listed above - the following Attributes are exporte * `revision_mode` - The revision mode of the Container App. +* `kind` - The kind of container app. + * `template` - A `template` block as detailed below. * `dapr` - A `dapr` block as detailed below. diff --git a/website/docs/r/container_app.html.markdown b/website/docs/r/container_app.html.markdown index 3472fa93e78d..10e0ab7c9f2c 100644 --- a/website/docs/r/container_app.html.markdown +++ b/website/docs/r/container_app.html.markdown @@ -72,6 +72,8 @@ The following arguments are supported: * `ingress` - (Optional) An `ingress` block as detailed below. +* `kind` - (Optional) The kind of container app. Possible values include `functionapp` and `workflowapp`. + * `registry` - (Optional) A `registry` block as detailed below. * `secret` - (Optional) One or more `secret` block as detailed below. From d27b74fc1550bf32ea036e33f7d1de2b4e7f2430 Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 13 Oct 2025 17:19:28 +0800 Subject: [PATCH 2/2] Fix vendor issue --- .../search/2025-05-01/services/constants.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2025-05-01/services/constants.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2025-05-01/services/constants.go index 2d4d847f4463..e34dbde0df07 100644 --- a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2025-05-01/services/constants.go +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2025-05-01/services/constants.go @@ -53,8 +53,8 @@ func parseAadAuthFailureMode(input string) (*AadAuthFailureMode, error) { type ComputeType string const ( - ComputeTypeConfidential ComputeType = "confidential" - ComputeTypeDefault ComputeType = "default" + ComputeTypeConfidential ComputeType = "Confidential" + ComputeTypeDefault ComputeType = "Default" ) func PossibleValuesForComputeType() []string { @@ -94,8 +94,8 @@ func parseComputeType(input string) (*ComputeType, error) { type HostingMode string const ( - HostingModeDefault HostingMode = "default" - HostingModeHighDensity HostingMode = "highDensity" + HostingModeDefault HostingMode = "Default" + HostingModeHighDensity HostingMode = "HighDensity" ) func PossibleValuesForHostingMode() []string { @@ -279,8 +279,8 @@ func parseProvisioningState(input string) (*ProvisioningState, error) { type PublicNetworkAccess string const ( - PublicNetworkAccessDisabled PublicNetworkAccess = "disabled" - PublicNetworkAccessEnabled PublicNetworkAccess = "enabled" + PublicNetworkAccessDisabled PublicNetworkAccess = "Disabled" + PublicNetworkAccessEnabled PublicNetworkAccess = "Enabled" ) func PossibleValuesForPublicNetworkAccess() []string {