Skip to content

Commit

Permalink
azurerm_container_app: add identity field to registry block
Browse files Browse the repository at this point in the history
Fixes #20412
  • Loading branch information
jsok committed Feb 15, 2023
1 parent e128e98 commit 89e5cb4
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 15 deletions.
7 changes: 6 additions & 1 deletion internal/services/containerapps/container_app_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,19 @@ func (r ContainerAppResource) Create() sdk.ResourceFunc {
return fmt.Errorf("reading %s for %s: %+v", *envId, id, err)
}

registries, err := helpers.ExpandContainerAppRegistries(app.Registries)
if err != nil {
return fmt.Errorf("invalid registry config for %s: %+v", id, err)
}

containerApp := containerapps.ContainerApp{
Location: location.Normalize(env.Model.Location),
Properties: &containerapps.ContainerAppProperties{
Configuration: &containerapps.Configuration{
Ingress: helpers.ExpandContainerAppIngress(app.Ingress, id.ContainerAppName),
Dapr: helpers.ExpandContainerAppDapr(app.Dapr),
Secrets: helpers.ExpandContainerSecrets(app.Secrets),
Registries: helpers.ExpandContainerAppRegistries(app.Registries),
Registries: registries,
},
ManagedEnvironmentId: pointer.To(app.ManagedEnvironmentId),
Template: helpers.ExpandContainerAppTemplate(app.Template, metadata),
Expand Down
45 changes: 34 additions & 11 deletions internal/services/containerapps/helpers/container_apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Registry struct {
PasswordSecretRef string `tfschema:"password_secret_name"`
Server string `tfschema:"server"`
UserName string `tfschema:"username"`
Identity string `tfschema:"identity"`
}

func ContainerAppRegistrySchema() *pluginsdk.Schema {
Expand All @@ -35,38 +36,59 @@ func ContainerAppRegistrySchema() *pluginsdk.Schema {
},

"username": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The username to use for this Container Registry.",
Type: pluginsdk.TypeString,
Required: false,
Description: "The username to use for this Container Registry.",
},

"password_secret_name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The name of the Secret Reference containing the password value for this user on the Container Registry.",
Type: pluginsdk.TypeString,
Required: false,
Description: "The name of the Secret Reference containing the password value for this user on the Container Registry.",
},

"identity": {
Type: pluginsdk.TypeString,
Required: false,
Description: "ID of the System or User Managed Identity used to pull images from the Container Registry",
},
},
},
}
}

func ExpandContainerAppRegistries(input []Registry) *[]containerapps.RegistryCredentials {
func ValidateContainerAppRegistry(r Registry) error {
if r.Identity != "" && (r.UserName != "" || r.PasswordSecretRef != "") {
return fmt.Errorf("identity and username/password_secret_name are mutually exclusive")
}
if r.Identity == "" && r.UserName == "" && r.PasswordSecretRef == "" {
return fmt.Errorf("must supply either identity or username/password_secret_name")
}
if (r.UserName != "" && r.PasswordSecretRef == "") || (r.UserName == "" && r.PasswordSecretRef != "") {
return fmt.Errorf("must supply both username and password_secret_name")
}
return nil
}

func ExpandContainerAppRegistries(input []Registry) (*[]containerapps.RegistryCredentials, error) {
if input == nil {
return nil
return nil, nil
}

registries := make([]containerapps.RegistryCredentials, 0)
for _, v := range input {
if err := ValidateContainerAppRegistry(v); err != nil {
return nil, err
}
registries = append(registries, containerapps.RegistryCredentials{
Server: pointer.To(v.Server),
Username: pointer.To(v.UserName),
PasswordSecretRef: pointer.To(v.PasswordSecretRef),
Identity: pointer.To(v.Identity),
})
}

return &registries
return &registries, nil
}

func FlattenContainerAppRegistries(input *[]containerapps.RegistryCredentials) []Registry {
Expand All @@ -80,6 +102,7 @@ func FlattenContainerAppRegistries(input *[]containerapps.RegistryCredentials) [
PasswordSecretRef: pointer.From(v.PasswordSecretRef),
Server: pointer.From(v.Server),
UserName: pointer.From(v.Username),
Identity: pointer.From(v.Identity),
})
}

Expand Down
66 changes: 66 additions & 0 deletions internal/services/containerapps/helpers/container_apps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package helpers

import (
"testing"
)

func TestValidateContainerAppRegistry(t *testing.T) {
cases := []struct {
Input Registry
Valid bool
}{
{
Input: Registry{
Server: "registry.example.com",
UserName: "user",
PasswordSecretRef: "secretref",
},
Valid: true,
},
{
Input: Registry{
Server: "registry.example.com",
Identity: "identity",
},
Valid: true,
},
{
Input: Registry{
Server: "registry.example.com",
},
Valid: false,
},
{
Input: Registry{
Server: "registry.example.com",
UserName: "user",
PasswordSecretRef: "secretref",
Identity: "identity",
},
Valid: false,
},
{
Input: Registry{
Server: "registry.example.com",
PasswordSecretRef: "secretref",
},
Valid: false,
},
{
Input: Registry{
Server: "registry.example.com",
UserName: "user",
},
Valid: false,
},
}

for _, tc := range cases {
t.Logf("[DEBUG] Testing Value %s", tc.Input)
err := ValidateContainerAppRegistry(tc.Input)
valid := err == nil
if tc.Valid != valid {
t.Fatalf("Expected %t but got %t for %s", tc.Valid, valid, tc.Input)
}
}
}
11 changes: 8 additions & 3 deletions website/docs/r/container_app.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -315,11 +315,16 @@ A `dapr` block supports the following:

A `registry` block supports the following:

* `password_secret_name` - (Required) The name of the Secret Reference containing the password value for this user on the Container Registry.

* `server` - (Required) The hostname for the Container Registry.

* `username` - (Required) The username to use for this Container Registry.
The authentication details must also be supplied, `identity` and `username`/`password_secret_name` are mutually exclusive.

* `identity` - (Optional) Resource ID for the User Assigned Managed identity to use when pulling from the Container Registry.

* `password_secret_name` - (Optional) The name of the Secret Reference containing the password value for this user on the Container Registry, `username` must also be supplied.

* `username` - (Optional) The username to use for this Container Registry, `password_secret_name` must also be supplied..



## Attributes Reference
Expand Down

0 comments on commit 89e5cb4

Please sign in to comment.