diff --git a/internal/services/containerapps/container_app_job_resource.go b/internal/services/containerapps/container_app_job_resource.go index d2621538acc9..c19b11b4a18c 100644 --- a/internal/services/containerapps/container_app_job_resource.go +++ b/internal/services/containerapps/container_app_job_resource.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/go-azure-sdk/resource-manager/containerapps/2023-05-01/jobs" "github.com/hashicorp/go-azure-sdk/resource-manager/containerapps/2023-05-01/managedenvironmentsstorages" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/services/containerapps/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/containerapps/validate" @@ -37,8 +38,10 @@ type ContainerAppJobModel struct { Template []helpers.JobTemplateModel `tfschema:"template"` ReplicaRetryLimit int64 `tfschema:"replica_retry_limit"` ReplicaTimeoutInSeconds int64 `tfschema:"replica_timeout_in_seconds"` - Secrets []helpers.Secret `tfschema:"secrets"` - Registries []helpers.Registry `tfschema:"registries"` + Secrets []helpers.Secret `tfschema:"secret"` + SecretsDeprecated []helpers.Secret `tfschema:"secrets,removedInNextMajorVersion"` + Registries []helpers.Registry `tfschema:"registry"` + RegistriesDeprecated []helpers.Registry `tfschema:"registries,removedInNextMajorVersion"` EventTriggerConfig []helpers.EventTriggerConfiguration `tfschema:"event_trigger_config"` ManualTriggerConfig []helpers.ManualTriggerConfiguration `tfschema:"manual_trigger_config"` ScheduleTriggerConfig []helpers.ScheduleTriggerConfiguration `tfschema:"schedule_trigger_config"` @@ -65,7 +68,7 @@ func (r ContainerAppJobResource) IDValidationFunc() pluginsdk.SchemaValidateFunc } func (r ContainerAppJobResource) Arguments() map[string]*schema.Schema { - return map[string]*pluginsdk.Schema{ + schema := map[string]*pluginsdk.Schema{ "name": { Type: pluginsdk.TypeString, Required: true, @@ -93,7 +96,7 @@ func (r ContainerAppJobResource) Arguments() map[string]*schema.Schema { "template": helpers.JobTemplateSchema(), - "secrets": helpers.SecretsSchema(), + "secret": helpers.SecretsSchema(), "replica_retry_limit": { Type: pluginsdk.TypeInt, @@ -101,7 +104,7 @@ func (r ContainerAppJobResource) Arguments() map[string]*schema.Schema { ValidateFunc: validation.IntAtLeast(0), }, - "registries": helpers.ContainerAppRegistrySchema(), + "registry": helpers.ContainerAppRegistrySchema(), "event_trigger_config": { Type: pluginsdk.TypeList, @@ -202,6 +205,24 @@ func (r ContainerAppJobResource) Arguments() map[string]*schema.Schema { "tags": commonschema.Tags(), } + + if !features.FourPointOhBeta() { + schema["secrets"] = helpers.SecretsSchema() + schema["secrets"].ConflictsWith = []string{"secret"} + schema["secrets"].Computed = true + schema["secrets"].Deprecated = "`secrets` has been renamed to `secret` and will be removed in version 4.0 of the AzureRM Provider." + schema["secret"].ConflictsWith = []string{"secrets"} + schema["secret"].Computed = true + + schema["registries"] = helpers.ContainerAppRegistrySchema() + schema["registries"].ConflictsWith = []string{"registry"} + schema["registries"].Computed = true + schema["registries"].Deprecated = "`registries` has been renamed to `registry` and will be removed in version 4.0 of the AzureRM Provider." + schema["registry"].ConflictsWith = []string{"registries"} + schema["registry"].Computed = true + } + + return schema } func (r ContainerAppJobResource) Attributes() map[string]*schema.Schema { @@ -251,6 +272,17 @@ func (r ContainerAppJobResource) Create() sdk.ResourceFunc { if err != nil { return fmt.Errorf("expanding registry config for %s: %v", id, err) } + if !features.FourPointOhBeta() && len(model.RegistriesDeprecated) > 0 { + registries, err = helpers.ExpandContainerAppJobRegistries(model.RegistriesDeprecated) + if err != nil { + return fmt.Errorf("expanding registry config for %s: %v", id, err) + } + } + + secrets := helpers.ExpandContainerAppJobSecrets(model.Secrets) + if !features.FourPointOhBeta() && len(model.SecretsDeprecated) > 0 { + secrets = helpers.ExpandContainerAppJobSecrets(model.SecretsDeprecated) + } job := jobs.Job{ Location: location.Normalize(model.Location), @@ -258,7 +290,7 @@ func (r ContainerAppJobResource) Create() sdk.ResourceFunc { Configuration: &jobs.JobConfiguration{ ReplicaRetryLimit: pointer.To(model.ReplicaRetryLimit), ReplicaTimeout: model.ReplicaTimeoutInSeconds, - Secrets: helpers.ExpandContainerAppJobSecrets(model.Secrets), + Secrets: secrets, Registries: registries, }, EnvironmentId: pointer.To(model.ContainerAppEnvironmentId), @@ -349,6 +381,9 @@ func (r ContainerAppJobResource) Read() sdk.ResourceFunc { state.Template = helpers.FlattenContainerAppJobTemplate(props.Template) if config := props.Configuration; config != nil { state.Registries = helpers.FlattenContainerAppJobRegistries(config.Registries) + if !features.FourPointOhBeta() { + state.RegistriesDeprecated = helpers.FlattenContainerAppJobRegistries(config.Registries) + } state.ReplicaTimeoutInSeconds = config.ReplicaTimeout if config.ReplicaRetryLimit != nil { state.ReplicaRetryLimit = pointer.From(config.ReplicaRetryLimit) @@ -372,6 +407,9 @@ func (r ContainerAppJobResource) Read() sdk.ResourceFunc { return fmt.Errorf("listing secrets for %s: %+v", *id, err) } state.Secrets = helpers.FlattenContainerAppJobSecrets(secretResp.Model) + if !features.FourPointOhBeta() { + state.SecretsDeprecated = helpers.FlattenContainerAppJobSecrets(secretResp.Model) + } return metadata.Encode(&state) }, @@ -419,11 +457,11 @@ func (r ContainerAppJobResource) Update() sdk.ResourceFunc { d := metadata.ResourceData - if metadata.ResourceData.HasChange("secrets") { + if d.HasChange("secret") { model.Properties.Configuration.Secrets = helpers.ExpandContainerAppJobSecrets(state.Secrets) } - if d.HasChange("registries") { + if d.HasChange("registry") { model.Properties.Configuration.Registries, err = helpers.ExpandContainerAppJobRegistries(state.Registries) if err != nil { return fmt.Errorf("invalid registry config for %s: %v", id, err) @@ -466,6 +504,18 @@ func (r ContainerAppJobResource) Update() sdk.ResourceFunc { model.Tags = tags.Expand(state.Tags) } + if !features.FourPointOhBeta() { + if d.HasChange("secrets") { + model.Properties.Configuration.Secrets = helpers.ExpandContainerAppJobSecrets(state.SecretsDeprecated) + } + if d.HasChange("registries") { + model.Properties.Configuration.Registries, err = helpers.ExpandContainerAppJobRegistries(state.RegistriesDeprecated) + if err != nil { + return fmt.Errorf("invalid registry config for %s: %v", id, err) + } + } + } + model.Properties.Template = helpers.ExpandContainerAppJobTemplate(state.Template) if err := client.CreateOrUpdateThenPoll(ctx, *id, *model); err != nil { diff --git a/internal/services/containerapps/container_app_job_resource_test.go b/internal/services/containerapps/container_app_job_resource_test.go index aee85b1aaf88..74b15e6f3ef9 100644 --- a/internal/services/containerapps/container_app_job_resource_test.go +++ b/internal/services/containerapps/container_app_job_resource_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -229,6 +230,24 @@ func TestAccContainerAppJob_complete(t *testing.T) { }) } +func TestAccContainerAppJob_completeDeprecated(t *testing.T) { + if features.FourPointOhBeta() { + t.Skip("Skipped as `secrets` and `registries` removed in 4.0") + } + data := acceptance.BuildTestData(t, "azurerm_container_app_job", "test") + r := ContainerAppJobResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.completeDeprecated(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccContainerAppJob_completeUpdate(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_container_app_job", "test") r := ContainerAppJobResource{} @@ -621,6 +640,104 @@ func (r ContainerAppJobResource) complete(data acceptance.TestData) string { %[1]s +resource "azurerm_container_app_job" "test" { + name = "acctest-cajob%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + container_app_environment_id = azurerm_container_app_environment.test.id + + identity { + type = "SystemAssigned" + } + + replica_timeout_in_seconds = 10 + replica_retry_limit = 10 + manual_trigger_config { + parallelism = 4 + replica_completion_count = 1 + } + secret { + name = "registry-password" + value = azurerm_container_registry.test.admin_password + } + registry { + server = azurerm_container_registry.test.login_server + username = azurerm_container_registry.test.admin_username + password_secret_name = "registry-password" + } + + template { + volume { + name = azurerm_container_app_environment_storage.test.name + storage_type = "AzureFile" + storage_name = azurerm_container_app_environment_storage.test.name + } + container { + args = [ + "-c", + "while true; do echo hello; sleep 10;done", + ] + command = [ + "/bin/sh", + ] + image = "jackofallops/azure-containerapps-python-acctest:v0.0.1" + name = "testcontainerappsjob0" + readiness_probe { + transport = "HTTP" + port = 5000 + } + + liveness_probe { + transport = "HTTP" + port = 5000 + path = "/health" + + header { + name = "Cache-Control" + value = "no-cache" + } + + initial_delay = 5 + interval_seconds = 20 + timeout = 2 + failure_count_threshold = 1 + } + startup_probe { + transport = "TCP" + port = 5000 + } + + cpu = 0.5 + memory = "1Gi" + volume_mounts { + path = "/appsettings" + name = azurerm_container_app_environment_storage.test.name + } + } + + init_container { + name = "init-cont-%[2]d" + image = "jackofallops/azure-containerapps-python-acctest:v0.0.1" + cpu = 0.25 + memory = "0.5Gi" + volume_mounts { + name = azurerm_container_app_environment_storage.test.name + path = "/appsettings" + } + } + } + tags = { + ENV = "test" + } +} +`, ContainerAppResource{}.templatePlusExtras(data), data.RandomInteger) +} + +func (r ContainerAppJobResource) completeDeprecated(data acceptance.TestData) string { + return fmt.Sprintf(` + +%[1]s + resource "azurerm_container_app_job" "test" { name = "acctest-cajob%[2]d" resource_group_name = azurerm_resource_group.test.name @@ -738,17 +855,17 @@ resource "azurerm_container_app_job" "test" { replica_completion_count = 2 } - secrets { + secret { name = "registry-password" value = azurerm_container_registry.test.admin_password } - secrets { + secret { name = "foo" value = "bar" } - registries { + registry { server = azurerm_container_registry.test.login_server username = azurerm_container_registry.test.admin_username password_secret_name = "registry-password" diff --git a/website/docs/r/container_app_job.html.markdown b/website/docs/r/container_app_job.html.markdown index 45e9c8795544..317e86b69deb 100644 --- a/website/docs/r/container_app_job.html.markdown +++ b/website/docs/r/container_app_job.html.markdown @@ -102,9 +102,9 @@ The following arguments are supported: * `replica_retry_limit` - (Optional) The maximum number of times a replica is allowed to retry. -* `secrets` - (Optional) A `secrets` block as defined below. +* `secret` - (Optional) One or more `secret` blocks as defined below. -* `registries` - (Optional) A `registries` block as defined below. +* `registry` - (Optional) One or more `registry` blocks as defined below. * `manual_trigger_config` - (Optional) A `manual_trigger_config` block as defined below. @@ -312,7 +312,7 @@ A `volume` block supports the following: --- -A `secrets` block supports the following: +A `secret` block supports the following: * `name` - (required) Name of the secret. @@ -320,7 +320,7 @@ A `secrets` block supports the following: --- -A `registries` block supports the following: +A `registry` block supports the following: * `identity` - (Optional) A Managed Identity to use to authenticate with Azure Container Registry.