Skip to content

Commit

Permalink
resource/container_group: add registry credential (#1529)
Browse files Browse the repository at this point in the history
* Added imageRegistryCredentials to container group

* Update docs to add image_registry_credentials

* Added test and fixes from pr #1509

* Fix up review feedback

* Further tests and tweaks

* Reverting the LinuxBasic test

Tests pass:

```
$ acctests azurerm TestAccAzureRMContainerGroup_linuxBasic
=== RUN   TestAccAzureRMContainerGroup_linuxBasic
--- PASS: TestAccAzureRMContainerGroup_linuxBasic (86.67s)
=== RUN   TestAccAzureRMContainerGroup_linuxBasicUpdate
--- PASS: TestAccAzureRMContainerGroup_linuxBasicUpdate (107.92s)
PASS
ok  	github.com/terraform-providers/terraform-provider-azurerm/azurerm	194.641s
```
  • Loading branch information
lawrencegripper authored and tombuildsstuff committed Jul 16, 2018
1 parent d04b82c commit fe9975d
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 2 deletions.
91 changes: 89 additions & 2 deletions azurerm/resource_arm_container_group.go
Expand Up @@ -49,6 +49,37 @@ func resourceArmContainerGroup() *schema.Resource {
}, true),
},

"image_registry_credential": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"server": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.NoZeroValues,
ForceNew: true,
},

"username": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.NoZeroValues,
ForceNew: true,
},

"password": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
ValidateFunc: validation.NoZeroValues,
ForceNew: true,
},
},
},
},

"tags": tagsForceNewSchema(),

"restart_policy": {
Expand Down Expand Up @@ -218,8 +249,9 @@ func resourceArmContainerGroupCreate(d *schema.ResourceData, meta interface{}) e
Type: &IPAddressType,
Ports: containerGroupPorts,
},
OsType: containerinstance.OperatingSystemTypes(OSType),
Volumes: containerGroupVolumes,
OsType: containerinstance.OperatingSystemTypes(OSType),
Volumes: containerGroupVolumes,
ImageRegistryCredentials: expandContainerImageRegistryCredentials(d),
},
}

Expand Down Expand Up @@ -277,6 +309,10 @@ func resourceArmContainerGroupRead(d *schema.ResourceData, meta interface{}) err
}
flattenAndSetTags(d, resp.Tags)

if err := d.Set("image_registry_credential", flattenContainerImageRegistryCredentials(d, resp.ImageRegistryCredentials)); err != nil {
return fmt.Errorf("Error setting `capabilities`: %+v", err)
}

d.Set("os_type", string(resp.OsType))
if address := resp.IPAddress; address != nil {
d.Set("ip_address_type", address.Type)
Expand Down Expand Up @@ -531,6 +567,57 @@ func expandContainerEnvironmentVariables(input interface{}) *[]containerinstance
return &output
}

func expandContainerImageRegistryCredentials(d *schema.ResourceData) *[]containerinstance.ImageRegistryCredential {
credsRaw := d.Get("image_registry_credential").([]interface{})
if len(credsRaw) == 0 {
return nil
}

output := make([]containerinstance.ImageRegistryCredential, 0, len(credsRaw))

for _, c := range credsRaw {
credConfig := c.(map[string]interface{})

output = append(output, containerinstance.ImageRegistryCredential{
Server: utils.String(credConfig["server"].(string)),
Password: utils.String(credConfig["password"].(string)),
Username: utils.String(credConfig["username"].(string)),
})
}

return &output
}

func flattenContainerImageRegistryCredentials(d *schema.ResourceData, credsPtr *[]containerinstance.ImageRegistryCredential) []interface{} {
if credsPtr == nil {
return nil
}
configsOld := d.Get("image_registry_credential").([]interface{})

creds := *credsPtr
output := make([]interface{}, 0, len(creds))
for i, cred := range creds {
credConfig := make(map[string]interface{})
if cred.Server != nil {
credConfig["server"] = *cred.Server
}
if cred.Username != nil {
credConfig["username"] = *cred.Username
}

data := configsOld[i].(map[string]interface{})
oldServer := data["server"].(string)
if cred.Server != nil && *cred.Server == oldServer {
if v, ok := d.GetOk(fmt.Sprintf("image_registry_credential.%d.password", i)); ok {
credConfig["password"] = v.(string)
}
}

output = append(output, credConfig)
}
return output
}

func expandContainerVolumes(input interface{}) (*[]containerinstance.VolumeMount, *[]containerinstance.Volume) {
volumesRaw := input.([]interface{})

Expand Down
157 changes: 157 additions & 0 deletions azurerm/resource_arm_container_group_test.go
Expand Up @@ -11,6 +11,73 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func TestAccAzureRMContainerGroup_imageRegistryCredentials(t *testing.T) {
resourceName := "azurerm_container_group.test"
ri := acctest.RandInt()

config := testAccAzureRMContainerGroup_imageRegistryCredentials(ri, testLocation())

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMContainerGroupDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMContainerGroupExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.#", "2"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.server", "hub.docker.com"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.username", "yourusername"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.password", "yourpassword"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.1.server", "mine.acr.io"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.1.username", "acrusername"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.1.password", "acrpassword"),
),
},
},
})
}

func TestAccAzureRMContainerGroup_imageRegistryCredentialsUpdate(t *testing.T) {
resourceName := "azurerm_container_group.test"
ri := acctest.RandInt()

config := testAccAzureRMContainerGroup_imageRegistryCredentials(ri, testLocation())
updated := testAccAzureRMContainerGroup_imageRegistryCredentialsUpdated(ri, testLocation())

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMContainerGroupDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMContainerGroupExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.#", "2"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.server", "hub.docker.com"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.username", "yourusername"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.password", "yourpassword"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.1.server", "mine.acr.io"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.1.username", "acrusername"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.1.password", "acrpassword"),
),
},
{
Config: updated,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMContainerGroupExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.#", "1"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.server", "hub.docker.com"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.username", "updatedusername"),
resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.password", "updatedpassword"),
),
},
},
})
}

func TestAccAzureRMContainerGroup_linuxBasic(t *testing.T) {
resourceName := "azurerm_container_group.test"
ri := acctest.RandInt()
Expand Down Expand Up @@ -176,6 +243,96 @@ resource "azurerm_container_group" "test" {
`, ri, location, ri)
}

func testAccAzureRMContainerGroup_imageRegistryCredentials(ri int, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}
resource "azurerm_container_group" "test" {
name = "acctestcontainergroup-%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
ip_address_type = "public"
os_type = "linux"
container {
name = "hw"
image = "microsoft/aci-helloworld:latest"
cpu = "0.5"
memory = "0.5"
port = "80"
}
image_registry_credential {
server = "hub.docker.com"
username = "yourusername"
password = "yourpassword"
}
image_registry_credential {
server = "mine.acr.io"
username = "acrusername"
password = "acrpassword"
}
container {
name = "sidecar"
image = "microsoft/aci-tutorial-sidecar"
cpu = "0.5"
memory = "0.5"
}
tags {
environment = "Testing"
}
}
`, ri, location, ri)
}

func testAccAzureRMContainerGroup_imageRegistryCredentialsUpdated(ri int, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}
resource "azurerm_container_group" "test" {
name = "acctestcontainergroup-%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
ip_address_type = "public"
os_type = "linux"
container {
name = "hw"
image = "microsoft/aci-helloworld:latest"
cpu = "0.5"
memory = "0.5"
port = "80"
}
image_registry_credential {
server = "hub.docker.com"
username = "updatedusername"
password = "updatedpassword"
}
container {
name = "sidecar"
image = "microsoft/aci-tutorial-sidecar"
cpu = "0.5"
memory = "0.5"
}
tags {
environment = "Testing"
}
}
`, ri, location, ri)
}

func testAccAzureRMContainerGroup_linuxBasicUpdated(ri int, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
Expand Down
43 changes: 43 additions & 0 deletions examples/aci-image-registry-credentials/main.tf
@@ -0,0 +1,43 @@
resource "azurerm_resource_group" "aci-rg" {
name = "aci-test-creds"
location = "west us"
}

resource "azurerm_container_group" "aci-test" {
name = "my-aci-hw"
location = "${azurerm_resource_group.aci-rg.location}"
resource_group_name = "${azurerm_resource_group.aci-rg.name}"
ip_address_type = "public"
os_type = "linux"

image_registry_credential {
server = "hub.docker.com"
username = "yourusername1"
password = "yourpassword"
}

image_registry_credential {
server = "2hub.docker.com"
username = "2yourusername1"
password = "2yourpassword"
}

container {
name = "hw"
image = "microsoft/aci-helloworld:latest"
cpu = "0.5"
memory = "1.5"
port = "80"
}

container {
name = "sidecar"
image = "microsoft/aci-tutorial-sidecar"
cpu = "0.5"
memory = "1.5"
}

tags {
environment = "testing"
}
}
10 changes: 10 additions & 0 deletions website/docs/r/container_group.html.markdown
Expand Up @@ -99,6 +99,8 @@ The following arguments are supported:

* `restart_policy` - (Optional) Restart policy for the container group. Allowed values are `Always`, `Never`, `OnFailure`. Defaults to `Always`.

* `image_registry_credential` - (Optional) Set image registry credentials for the group as documented in the `image_registry_credential` block below

* `container` - (Required) The definition of a container that is part of the group as documented in the `container` block below. Changing this forces a new resource to be created.

~> **Note:** if `os_type` is set to `Windows` currently only a single `container` block is supported.
Expand Down Expand Up @@ -135,6 +137,14 @@ The `volume` block supports:

* `share_name` - (Required) The Azure storage share that is to be mounted as a volume. This must be created on the storage account specified as above. Changing this forces a new resource to be created.

The `image_registry_credential` block supports:

* `username` - (Required) The username with which to connect to the registry.

* `password` - (Required) The password with which to connect to the registry.

* `server` - (Required) The address to use to connect to the registry without protocol ("https"/"http"). For example: "myacr.acr.io"

## Attributes Reference

The following attributes are exported:
Expand Down

0 comments on commit fe9975d

Please sign in to comment.