Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_container_app - suppot for the init_container block #23955

Merged
merged 10 commits into from
Dec 14, 2023
11 changes: 11 additions & 0 deletions internal/services/containerapps/container_app_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,17 @@ resource "azurerm_container_app" "test" {
}
}

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 = "/tmp/testdata"
}
}
jackofallops marked this conversation as resolved.
Show resolved Hide resolved

volume {
name = azurerm_container_app_environment_storage.test.name
storage_type = "AzureFile"
Expand Down
246 changes: 241 additions & 5 deletions internal/services/containerapps/helpers/container_apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ func ContainerAppEnvironmentDaprMetadataSchema() *pluginsdk.Schema {

type ContainerTemplate struct {
Containers []Container `tfschema:"container"`
InitContainers []BaseContainer `tfschema:"init_container"`
Suffix string `tfschema:"revision_suffix"`
MinReplicas int `tfschema:"min_replicas"`
MaxReplicas int `tfschema:"max_replicas"`
Expand All @@ -705,6 +706,8 @@ func ContainerTemplateSchema() *pluginsdk.Schema {
Schema: map[string]*pluginsdk.Schema{
"container": ContainerAppContainerSchema(),

"init_container": InitContainerAppContainerSchema(),

"min_replicas": {
Type: pluginsdk.TypeInt,
Optional: true,
Expand Down Expand Up @@ -750,6 +753,8 @@ func ContainerTemplateSchemaComputed() *pluginsdk.Schema {
Schema: map[string]*pluginsdk.Schema{
"container": ContainerAppContainerSchemaComputed(),

"init_container": InitContainerAppContainerSchemaComputed(),

"min_replicas": {
Type: pluginsdk.TypeInt,
Computed: true,
Expand Down Expand Up @@ -788,8 +793,9 @@ func ExpandContainerAppTemplate(input []ContainerTemplate, metadata sdk.Resource

config := input[0]
template := &containerapps.Template{
Containers: expandContainerAppContainers(config.Containers),
Volumes: expandContainerAppVolumes(config.Volumes),
Containers: expandContainerAppContainers(config.Containers),
InitContainers: expandInitContainerAppContainers(config.InitContainers),
Volumes: expandContainerAppVolumes(config.Volumes),
}

if config.MaxReplicas != 0 {
Expand Down Expand Up @@ -828,9 +834,10 @@ func FlattenContainerAppTemplate(input *containerapps.Template) []ContainerTempl
return []ContainerTemplate{}
}
result := ContainerTemplate{
Containers: flattenContainerAppContainers(input.Containers),
Suffix: pointer.From(input.RevisionSuffix),
Volumes: flattenContainerAppVolumes(input.Volumes),
Containers: flattenContainerAppContainers(input.Containers),
InitContainers: flattenInitContainerAppContainers(input.InitContainers),
Suffix: pointer.From(input.RevisionSuffix),
Volumes: flattenContainerAppVolumes(input.Volumes),
}

if scale := input.Scale; scale != nil {
Expand Down Expand Up @@ -1007,6 +1014,213 @@ func ContainerAppContainerSchemaComputed() *pluginsdk.Schema {
}
}

type BaseContainer struct {
Name string `tfschema:"name"`
Image string `tfschema:"image"`
CPU float64 `tfschema:"cpu"`
Memory string `tfschema:"memory"`
EphemeralStorage string `tfschema:"ephemeral_storage"`
Env []ContainerEnvVar `tfschema:"env"`
Args []string `tfschema:"args"`
Command []string `tfschema:"command"`
VolumeMounts []ContainerVolumeMount `tfschema:"volume_mounts"`
}

func InitContainerAppContainerSchema() *pluginsdk.Schema {
return &pluginsdk.Schema{
Type: pluginsdk.TypeList,
Optional: true,
MinItems: 1,
Elem: &pluginsdk.Resource{
jackofallops marked this conversation as resolved.
Show resolved Hide resolved
Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.ContainerAppContainerName,
Description: "The name of the container.",
},

"image": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The image to use to create the container.",
},

"cpu": {
Type: pluginsdk.TypeFloat,
Optional: true,
ValidateFunc: validate.ContainerCpu,
Description: "The amount of vCPU to allocate to the container. Possible values include `0.25`, `0.5`, `0.75`, `1.0`, `1.25`, `1.5`, `1.75`, and `2.0`. **NOTE:** `cpu` and `memory` must be specified in `0.25'/'0.5Gi` combination increments. e.g. `1.0` / `2.0` or `0.5` / `1.0`",
},

"memory": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"0.5Gi",
"1Gi",
"1.5Gi",
"2Gi",
"2.5Gi",
"3Gi",
"3.5Gi",
"4Gi",
}, false),
Description: "The amount of memory to allocate to the container. Possible values include `0.5Gi`, `1.0Gi`, `1.5Gi`, `2.0Gi`, `2.5Gi`, `3.0Gi`, `3.5Gi`, and `4.0Gi`. **NOTE:** `cpu` and `memory` must be specified in `0.25'/'0.5Gi` combination increments. e.g. `1.25` / `2.5Gi` or `0.75` / `1.5Gi`",
},

"ephemeral_storage": {
Type: pluginsdk.TypeString,
Computed: true,
Description: "The amount of ephemeral storage available to the Container App.",
},

"env": ContainerEnvVarSchema(),

"args": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
Description: "A list of args to pass to the container.",
},

"command": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
Description: "A command to pass to the container to override the default. This is provided as a list of command line elements without spaces.",
},

"volume_mounts": ContainerVolumeMountSchema(),
},
},
}
}

func InitContainerAppContainerSchemaComputed() *pluginsdk.Schema {
return &pluginsdk.Schema{
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Computed: true,
Description: "The name of the container.",
},

"image": {
Type: pluginsdk.TypeString,
Computed: true,
Description: "The image to use to create the container.",
},

"cpu": {
Type: pluginsdk.TypeFloat,
Computed: true,
Description: "The amount of vCPU to allocate to the container. Possible values include `0.25`, `0.5`, `0.75`, `1.0`, `1.25`, `1.5`, `1.75`, and `2.0`. **NOTE:** `cpu` and `memory` must be specified in `0.25'/'0.5Gi` combination increments. e.g. `1.0` / `2.0` or `0.5` / `1.0`",
},

"memory": {
Type: pluginsdk.TypeString,
Computed: true,
Description: "The amount of memory to allocate to the container. Possible values include `0.5Gi`, `1.0Gi`, `1.5Gi`, `2.0Gi`, `2.5Gi`, `3.0Gi`, `3.5Gi`, and `4.0Gi`. **NOTE:** `cpu` and `memory` must be specified in `0.25'/'0.5Gi` combination increments. e.g. `1.25` / `2.5Gi` or `0.75` / `1.5Gi`",
},

"ephemeral_storage": {
Type: pluginsdk.TypeString,
Computed: true,
Description: "The amount of ephemeral storage available to the Container App.",
},

"env": ContainerEnvVarSchemaComputed(),

"args": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
Description: "A list of args to pass to the container.",
},

"command": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
Description: "A command to pass to the container to override the default. This is provided as a list of command line elements without spaces.",
},

"volume_mounts": ContainerVolumeMountSchemaComputed(),
},
},
}
}

func expandInitContainerAppContainers(input []BaseContainer) *[]containerapps.BaseContainer {
if input == nil {
return nil
}

result := make([]containerapps.BaseContainer, 0)
for _, v := range input {
container := containerapps.BaseContainer{
Env: expandInitContainerEnvVar(v),
Image: pointer.To(v.Image),
Name: pointer.To(v.Name),
Resources: &containerapps.ContainerResources{
Cpu: pointer.To(v.CPU),
EphemeralStorage: pointer.To(v.EphemeralStorage),
Memory: pointer.To(v.Memory),
},
VolumeMounts: expandContainerVolumeMounts(v.VolumeMounts),
}
if len(v.Args) != 0 {
container.Args = pointer.To(v.Args)
}
if len(v.Command) != 0 {
container.Command = pointer.To(v.Command)
}

result = append(result, container)
}

return &result
}

func flattenInitContainerAppContainers(input *[]containerapps.BaseContainer) []BaseContainer {
if input == nil || len(*input) == 0 {
return []BaseContainer{}
}
result := make([]BaseContainer, 0)
for _, v := range *input {
container := BaseContainer{
Name: pointer.From(v.Name),
Image: pointer.From(v.Image),
Args: pointer.From(v.Args),
Command: pointer.From(v.Command),
Env: flattenContainerEnvVar(v.Env),
VolumeMounts: flattenContainerVolumeMounts(v.VolumeMounts),
}

if resources := v.Resources; resources != nil {
container.CPU = pointer.From(resources.Cpu)
container.Memory = pointer.From(resources.Memory)
container.EphemeralStorage = pointer.From(resources.EphemeralStorage)
}

result = append(result, container)
}
return result
}

func expandContainerAppContainers(input []Container) *[]containerapps.Container {
if input == nil {
return nil
Expand Down Expand Up @@ -1335,6 +1549,28 @@ func ContainerEnvVarSchemaComputed() *pluginsdk.Schema {
}
}

func expandInitContainerEnvVar(input BaseContainer) *[]containerapps.EnvironmentVar {
envs := make([]containerapps.EnvironmentVar, 0)
if input.Env == nil || len(input.Env) == 0 {
return &envs
}

for _, v := range input.Env {
env := containerapps.EnvironmentVar{
Name: pointer.To(v.Name),
}
if v.SecretReference != "" {
env.SecretRef = pointer.To(v.SecretReference)
} else {
env.Value = pointer.To(v.Value)
}

envs = append(envs, env)
}

return &envs
}

func expandContainerEnvVar(input Container) *[]containerapps.EnvironmentVar {
envs := make([]containerapps.EnvironmentVar, 0)
if input.Env == nil || len(input.Env) == 0 {
Expand Down
24 changes: 24 additions & 0 deletions website/docs/d/container_app.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ A `secret` block supports the following:

A `template` block supports the following:

* `init_container` - One or more `init_container` blocks as detailed below.

* `container` - One or more `container` blocks as detailed below.

* `max_replicas` - The maximum number of replicas for this container.
Expand All @@ -85,6 +87,28 @@ A `volume` block supports the following:

---

A `init_container` block supports the following:

* `args` - A list of extra arguments to pass to the container.

* `command` - A command to pass to the container to override the default. This is provided as a list of command line elements without spaces.

* `cpu` - The amount of vCPU to allocate to the container. Possible values include `0.25`, `0.5`, `0.75`, `1.0`, `1.25`, `1.5`, `1.75`, and `2.0`.

* `env` - One or more `env` blocks as detailed below.

* `ephemeral_storage` - The amount of ephemeral storage available to the Container App.

* `image` - The image to use to create the container.

* `memory` - The amount of memory to allocate to the container. Possible values include `0.5Gi`, `1Gi`, `1.5Gi`, `2Gi`, `2.5Gi`, `3Gi`, `3.5Gi`, and `4Gi`.

* `name` - The name of the container

* `volume_mounts` - A `volume_mounts` block as detailed below.

---

A `container` block supports the following:

* `args` - A list of extra arguments to pass to the container.
Expand Down
30 changes: 30 additions & 0 deletions website/docs/r/container_app.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ A `secret` block supports the following:

A `template` block supports the following:

* `init_container` - (Optional) The definition of an init container that is part of the group as documented in the `init_container` block below.

* `container` - (Required) One or more `container` blocks as detailed below.

* `max_replicas` - (Optional) The maximum number of replicas for this container.
Expand Down Expand Up @@ -173,6 +175,34 @@ A `volume` block supports the following:

---

An `init_container` block supports:

* `args` - (Optional) A list of extra arguments to pass to the container.

* `command` - (Optional) A command to pass to the container to override the default. This is provided as a list of command line elements without spaces.

* `cpu` - (Required) The amount of vCPU to allocate to the container. Possible values include `0.25`, `0.5`, `0.75`, `1.0`, `1.25`, `1.5`, `1.75`, and `2.0`.

~> **NOTE:** `cpu` and `memory` must be specified in `0.25'/'0.5Gi` combination increments. e.g. `1.0` / `2.0` or `0.5` / `1.0`

* `env` - (Optional) One or more `env` blocks as detailed below.

* `ephemeral_storage` - The amount of ephemeral storage available to the Container App.

~> **NOTE:** `ephemeral_storage` is currently in preview and not configurable at this time.

* `image` - (Required) The image to use to create the container.

* `memory` - (Required) The amount of memory to allocate to the container. Possible values are `0.5Gi`, `1Gi`, `1.5Gi`, `2Gi`, `2.5Gi`, `3Gi`, `3.5Gi` and `4Gi`.

~> **NOTE:** `cpu` and `memory` must be specified in `0.25'/'0.5Gi` combination increments. e.g. `1.25` / `2.5Gi` or `0.75` / `1.5Gi`

* `name` - (Required) The name of the container

* `volume_mounts` - (Optional) A `volume_mounts` block as detailed below.

---

A `container` block supports the following:

* `args` - (Optional) A list of extra arguments to pass to the container.
Expand Down
Loading