From 6e57154f6760a5d212ff2aa1551ced8702da39ba Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Fri, 14 Sep 2018 11:54:16 -0500 Subject: [PATCH 01/13] Adding Ports To Container Groups 1. Adding ports field to allow for multiple port exposures 2. Refactore tests --- azurerm/resource_arm_container_group.go | 23 ++++++++++++++++++++ azurerm/resource_arm_container_group_test.go | 14 ++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 15e14b2cc5b2..032aeb56c72b 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -149,9 +149,20 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeInt, Optional: true, ForceNew: true, + Deprecated: "Use `ports` instead.", ValidateFunc: validation.IntBetween(1, 65535), }, + "ports": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validation.IntBetween(1, 65535), + }, + }, + "protocol": { Type: schema.TypeString, Optional: true, @@ -564,6 +575,18 @@ func expandContainerGroupContainers(d *schema.ResourceData) (*[]containerinstanc containerGroupPorts = append(containerGroupPorts, containerGroupPort) } + if v, ok := data["ports"]; ok { + p := v.([]interface{}) + var ports []containerinstance.ContainerPort + for _, v := range p { + port := int32(v.(int)) + ports = append(ports, containerinstance.ContainerPort{ + Port: &port, + }) + } + container.Ports = &ports + } + if v, ok := data["environment_variables"]; ok { container.EnvironmentVariables = expandContainerEnvironmentVariables(v) } diff --git a/azurerm/resource_arm_container_group_test.go b/azurerm/resource_arm_container_group_test.go index 4889930c97d8..256ea5f95d6d 100644 --- a/azurerm/resource_arm_container_group_test.go +++ b/azurerm/resource_arm_container_group_test.go @@ -277,7 +277,7 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - port = "80" + ports = ["80"] } tags { @@ -306,7 +306,7 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - port = "80" + ports = ["80"] } image_registry_credential { @@ -354,7 +354,7 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - port = "80" + ports = ["80"] } image_registry_credential { @@ -396,7 +396,7 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - port = "80" + ports = ["80"] } container { @@ -432,7 +432,7 @@ resource "azurerm_container_group" "test" { image = "microsoft/windowsservercore:latest" cpu = "2.0" memory = "3.5" - port = "80" + ports = ["80"] } tags { @@ -463,7 +463,7 @@ resource "azurerm_container_group" "test" { image = "microsoft/windowsservercore:latest" cpu = "2.0" memory = "3.5" - port = "80" + ports = ["80"] environment_variables { "foo" = "bar" @@ -518,7 +518,7 @@ resource "azurerm_container_group" "test" { cpu = "1" memory = "1.5" - port = "80" + ports = ["80"] protocol = "TCP" volume { From d0886d7118e7afb57ca14852092a367ad77ca923 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Tue, 16 Oct 2018 05:43:22 -0500 Subject: [PATCH 02/13] merging with master, adding more robust tests, also deprecating protocol --- azurerm/resource_arm_container_group.go | 40 ++- azurerm/resource_arm_container_group_test.go | 311 ++++++++++++++----- 2 files changed, 268 insertions(+), 83 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 032aeb56c72b..8d631f419485 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -154,12 +154,30 @@ func resourceArmContainerGroup() *schema.Resource { }, "ports": { - Type: schema.TypeList, - Optional: true, - ForceNew: true, - Elem: &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validation.IntBetween(1, 65535), + Type: schema.TypeList, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"port", "protocol"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "protocol": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + Default: string("TCP"), + ValidateFunc: validation.StringInSlice([]string{ + "tcp", + "udp", + }, true), + }, + "port": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(1, 65535), + }, + }, }, }, @@ -167,6 +185,7 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Deprecated: "Use `ports` instead.", DiffSuppressFunc: ignoreCaseDiffSuppressFunc, ValidateFunc: validation.StringInSlice([]string{ "tcp", @@ -579,9 +598,14 @@ func expandContainerGroupContainers(d *schema.ResourceData) (*[]containerinstanc p := v.([]interface{}) var ports []containerinstance.ContainerPort for _, v := range p { - port := int32(v.(int)) + portObj := v.(map[string]interface{}) + portI := portObj["port"] + port := int32(portI.(int)) + protoI := portObj["protocol"] + proto := protoI.(string) ports = append(ports, containerinstance.ContainerPort{ - Port: &port, + Protocol: containerinstance.ContainerNetworkProtocol(strings.ToUpper(proto)), + Port: &port, }) } container.Ports = &ports diff --git a/azurerm/resource_arm_container_group_test.go b/azurerm/resource_arm_container_group_test.go index 256ea5f95d6d..80df616965f9 100644 --- a/azurerm/resource_arm_container_group_test.go +++ b/azurerm/resource_arm_container_group_test.go @@ -9,8 +9,12 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + + "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-04-01/containerinstance" ) +var emptyCheck = func(cg containerinstance.ContainerGroup) error { return nil } + func TestAccAzureRMContainerGroup_imageRegistryCredentials(t *testing.T) { resourceName := "azurerm_container_group.test" ri := acctest.RandInt() @@ -25,7 +29,7 @@ func TestAccAzureRMContainerGroup_imageRegistryCredentials(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, emptyCheck), 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"), @@ -63,7 +67,7 @@ func TestAccAzureRMContainerGroup_imageRegistryCredentialsUpdate(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, emptyCheck), 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"), @@ -71,16 +75,38 @@ func TestAccAzureRMContainerGroup_imageRegistryCredentialsUpdate(t *testing.T) { 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"), + resource.TestCheckResourceAttr(resourceName, "container.0.port", "5443"), + resource.TestCheckResourceAttr(resourceName, "container.0.protocol", "UDP"), ), }, { Config: updated, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, func(cg containerinstance.ContainerGroup) error { + if cg.Containers == nil || len(*cg.Containers) != 1 { + return fmt.Errorf("unexpected number of containers created") + } + containers := *cg.Containers + if containers[0].Ports == nil || len(*containers[0].Ports) != 1 { + return fmt.Errorf("unexpected number of ports created") + } + ports := *containers[0].Ports + if *ports[0].Port != 80 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[0].Protocol) != "TCP" { + return fmt.Errorf("expected port to be TCP, instead got %s", string(ports[0].Protocol)) + } + return nil + }), 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"), + resource.TestCheckResourceAttr(resourceName, "container.0.port", "81"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), ), }, }, @@ -101,9 +127,26 @@ func TestAccAzureRMContainerGroup_linuxBasic(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, func(cg containerinstance.ContainerGroup) error { + if cg.Containers == nil || len(*cg.Containers) != 1 { + return fmt.Errorf("unexpected number of containers created") + } + containers := *cg.Containers + if containers[0].Ports == nil || len(*containers[0].Ports) != 1 { + return fmt.Errorf("unexpected number of ports created") + } + ports := *containers[0].Ports + if *ports[0].Port != 80 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[0].Protocol) != "TCP" { + return fmt.Errorf("expected port to be TCP, instead got %s", string(ports[0].Protocol)) + } + return nil + }), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), resource.TestCheckResourceAttr(resourceName, "os_type", "Linux"), + resource.TestCheckResourceAttr(resourceName, "container.0.port", "80"), ), }, { @@ -134,15 +177,42 @@ func TestAccAzureRMContainerGroup_linuxBasicUpdate(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, emptyCheck), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), ), }, { Config: updatedConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, func(cg containerinstance.ContainerGroup) error { + if cg.Containers == nil || len(*cg.Containers) != 1 { + return fmt.Errorf("unexpected number of containers created") + } + containers := *cg.Containers + if containers[0].Ports == nil || len(*containers[0].Ports) != 2 { + return fmt.Errorf("unexpected number of ports created") + } + ports := *containers[0].Ports + if *ports[0].Port != 80 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[0].Protocol) != "TCP" { + return fmt.Errorf("expected port to be TCP, instead got %s", string(ports[0].Protocol)) + } + if *ports[1].Port != 5443 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[1].Protocol) != "UDP" { + return fmt.Errorf("expected port to be UDP, instead got %s", string(ports[0].Protocol)) + } + return nil + }), resource.TestCheckResourceAttr(resourceName, "container.#", "2"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "2"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.1.port", "5443"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.1.protocol", "UDP"), ), }, }, @@ -163,8 +233,28 @@ func TestAccAzureRMContainerGroup_linuxComplete(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, func(cg containerinstance.ContainerGroup) error { + if cg.Containers == nil || len(*cg.Containers) != 1 { + return fmt.Errorf("unexpected number of containers created") + } + containers := *cg.Containers + if containers[0].Ports == nil || len(*containers[0].Ports) != 1 { + return fmt.Errorf("unexpected number of ports created") + } + ports := *containers[0].Ports + if *ports[0].Port != 80 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[0].Protocol) != "TCP" { + return fmt.Errorf("expected port to be TCP, instead got %s", string(ports[0].Protocol)) + } + return nil + }), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), + resource.TestCheckResourceAttr(resourceName, "container.0.protocol", "UDP"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.port", "80"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.protocol", "TCP"), resource.TestCheckResourceAttr(resourceName, "container.0.command", "/bin/bash -c ls"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.#", "3"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.0", "/bin/bash"), @@ -207,9 +297,36 @@ func TestAccAzureRMContainerGroup_windowsBasic(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, func(cg containerinstance.ContainerGroup) error { + if cg.Containers == nil || len(*cg.Containers) != 1 { + return fmt.Errorf("unexpected number of containers created") + } + containers := *cg.Containers + if containers[0].Ports == nil || len(*containers[0].Ports) != 2 { + return fmt.Errorf("unexpected number of ports created") + } + ports := *containers[0].Ports + if *ports[0].Port != 80 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[0].Protocol) != "TCP" { + return fmt.Errorf("expected port to be TCP, instead got %s", string(ports[0].Protocol)) + } + if *ports[1].Port != 443 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[1].Protocol) != "TCP" { + return fmt.Errorf("expected port to be TCP, instead got %s", string(ports[0].Protocol)) + } + return nil + }), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), resource.TestCheckResourceAttr(resourceName, "os_type", "Windows"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "2"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), ), }, { @@ -235,8 +352,28 @@ func TestAccAzureRMContainerGroup_windowsComplete(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName), + testCheckAzureRMContainerGroupExists(resourceName, func(cg containerinstance.ContainerGroup) error { + if cg.Containers == nil || len(*cg.Containers) != 1 { + return fmt.Errorf("unexpected number of containers created") + } + containers := *cg.Containers + if containers[0].Ports == nil || len(*containers[0].Ports) != 1 { + return fmt.Errorf("unexpected number of ports created") + } + ports := *containers[0].Ports + if *ports[0].Port != 80 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[0].Protocol) != "TCP" { + return fmt.Errorf("expected port to be TCP, instead got %s", string(ports[0].Protocol)) + } + return nil + }), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), + resource.TestCheckResourceAttr(resourceName, "container.0.protocol", "TCP"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), resource.TestCheckResourceAttr(resourceName, "container.0.command", "cmd.exe echo hi"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.#", "3"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.0", "cmd.exe"), @@ -277,7 +414,7 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - ports = ["80"] + port = 80 } tags { @@ -302,11 +439,12 @@ resource "azurerm_container_group" "test" { os_type = "linux" container { - name = "hw" - image = "microsoft/aci-helloworld:latest" - cpu = "0.5" - memory = "0.5" - ports = ["80"] + name = "hw" + image = "microsoft/aci-helloworld:latest" + cpu = "0.5" + memory = "0.5" + port = 5443 + protocol = "udp" } image_registry_credential { @@ -354,7 +492,10 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - ports = ["80"] + port = 81 + ports = { + port = 80 + } } image_registry_credential { @@ -396,7 +537,13 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - ports = ["80"] + ports = { + port = 80 + } + ports = { + port = 5443 + protocol = "udp" + } } container { @@ -432,7 +579,14 @@ resource "azurerm_container_group" "test" { image = "microsoft/windowsservercore:latest" cpu = "2.0" memory = "3.5" - ports = ["80"] + ports = { + port = 80 + protocol = "tcp" + } + ports = { + port = 443 + protocol = "tcp" + } } tags { @@ -463,13 +617,17 @@ resource "azurerm_container_group" "test" { image = "microsoft/windowsservercore:latest" cpu = "2.0" memory = "3.5" - ports = ["80"] - - environment_variables { - "foo" = "bar" - "foo1" = "bar1" - } - commands = ["cmd.exe", "echo", "hi"] + ports = { + port = 80 + protocol = "tcp" + } + protocol = "TCP" + + environment_variables { + "foo" = "bar" + "foo1" = "bar1" + } + commands = ["cmd.exe", "echo", "hi"] } tags { @@ -482,71 +640,75 @@ resource "azurerm_container_group" "test" { func testAccAzureRMContainerGroup_linuxComplete(ri int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" + name = "acctestRG-%d" + location = "%s" } resource "azurerm_storage_account" "test" { - name = "accsa%d" - resource_group_name = "${azurerm_resource_group.test.name}" - location = "${azurerm_resource_group.test.location}" - account_tier = "Standard" - account_replication_type = "LRS" + name = "accsa%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" } resource "azurerm_storage_share" "test" { - name = "acctestss-%d" + name = "acctestss-%d" - resource_group_name = "${azurerm_resource_group.test.name}" - storage_account_name = "${azurerm_storage_account.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" - quota = 50 + quota = 50 } 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" - dns_name_label = "acctestcontainergroup-%d" - os_type = "linux" - restart_policy = "OnFailure" - - container { - name = "hf" - image = "seanmckenna/aci-hellofiles" - cpu = "1" - memory = "1.5" - - ports = ["80"] - protocol = "TCP" - - volume { - name = "logs" - mount_path = "/aci/logs" - read_only = false - share_name = "${azurerm_storage_share.test.name}" - - storage_account_name = "${azurerm_storage_account.test.name}" - storage_account_key = "${azurerm_storage_account.test.primary_access_key}" - } - - environment_variables { - "foo" = "bar" - "foo1" = "bar1" - } + name = "acctestcontainergroup-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + ip_address_type = "public" + dns_name_label = "acctestcontainergroup-%d" + os_type = "linux" + restart_policy = "OnFailure" - commands = ["/bin/bash", "-c", "ls"] - } + container { + name = "hf" + image = "seanmckenna/aci-hellofiles" + cpu = "1" + memory = "1.5" + + ports = { + port = 80 + protocol = "tcp" + } + + protocol = "UDP" + + volume { + name = "logs" + mount_path = "/aci/logs" + read_only = false + share_name = "${azurerm_storage_share.test.name}" + + storage_account_name = "${azurerm_storage_account.test.name}" + storage_account_key = "${azurerm_storage_account.test.primary_access_key}" + } + + environment_variables { + "foo" = "bar" + "foo1" = "bar1" + } + + commands = ["/bin/bash", "-c", "ls"] + } - tags { - environment = "Testing" - } + tags { + environment = "Testing" + } } `, ri, location, ri, ri, ri, ri) } -func testCheckAzureRMContainerGroupExists(name string) resource.TestCheckFunc { +func testCheckAzureRMContainerGroupExists(name string, checkResp func(containerinstance.ContainerGroup) error) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] @@ -570,8 +732,7 @@ func testCheckAzureRMContainerGroupExists(name string) resource.TestCheckFunc { } return fmt.Errorf("Bad: Get on containerGroupsClient: %+v", err) } - - return nil + return checkResp(resp) } } From b2c6c2e6488bfcf8676d0f6deb083f7a260c12d0 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Tue, 16 Oct 2018 05:55:32 -0500 Subject: [PATCH 03/13] use port number validation, remove parts of test that are conflicting --- azurerm/resource_arm_container_group.go | 5 ++-- azurerm/resource_arm_container_group_test.go | 25 +++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 8d631f419485..6ab3017a8abf 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -8,6 +8,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-04-01/containerinstance" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -150,7 +151,7 @@ func resourceArmContainerGroup() *schema.Resource { Optional: true, ForceNew: true, Deprecated: "Use `ports` instead.", - ValidateFunc: validation.IntBetween(1, 65535), + ValidateFunc: validate.PortNumber, }, "ports": { @@ -175,7 +176,7 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeInt, Required: true, ForceNew: true, - ValidateFunc: validation.IntBetween(1, 65535), + ValidateFunc: validate.PortNumber, }, }, }, diff --git a/azurerm/resource_arm_container_group_test.go b/azurerm/resource_arm_container_group_test.go index 80df616965f9..021f755d8cbd 100644 --- a/azurerm/resource_arm_container_group_test.go +++ b/azurerm/resource_arm_container_group_test.go @@ -67,7 +67,23 @@ func TestAccAzureRMContainerGroup_imageRegistryCredentialsUpdate(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMContainerGroupExists(resourceName, emptyCheck), + testCheckAzureRMContainerGroupExists(resourceName, func(cg containerinstance.ContainerGroup) error { + if cg.Containers == nil || len(*cg.Containers) != 1 { + return fmt.Errorf("unexpected number of containers created") + } + containers := *cg.Containers + if containers[0].Ports == nil || len(*containers[0].Ports) != 1 { + return fmt.Errorf("unexpected number of ports created") + } + ports := *containers[0].Ports + if *ports[0].Port != 5443 { + return fmt.Errorf("expected port to be 80, instead got %d", ports[0].Port) + } + if string(ports[0].Protocol) != "UDP" { + return fmt.Errorf("expected port to be UDP, instead got %s", string(ports[0].Protocol)) + } + return nil + }), 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"), @@ -103,7 +119,6 @@ func TestAccAzureRMContainerGroup_imageRegistryCredentialsUpdate(t *testing.T) { 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"), - resource.TestCheckResourceAttr(resourceName, "container.0.port", "81"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), @@ -251,7 +266,6 @@ func TestAccAzureRMContainerGroup_linuxComplete(t *testing.T) { return nil }), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), - resource.TestCheckResourceAttr(resourceName, "container.0.protocol", "UDP"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.port", "80"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.protocol", "TCP"), @@ -370,7 +384,6 @@ func TestAccAzureRMContainerGroup_windowsComplete(t *testing.T) { return nil }), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), - resource.TestCheckResourceAttr(resourceName, "container.0.protocol", "TCP"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), @@ -492,7 +505,6 @@ resource "azurerm_container_group" "test" { image = "microsoft/aci-helloworld:latest" cpu = "0.5" memory = "0.5" - port = 81 ports = { port = 80 } @@ -621,7 +633,6 @@ resource "azurerm_container_group" "test" { port = 80 protocol = "tcp" } - protocol = "TCP" environment_variables { "foo" = "bar" @@ -681,8 +692,6 @@ resource "azurerm_container_group" "test" { protocol = "tcp" } - protocol = "UDP" - volume { name = "logs" mount_path = "/aci/logs" From dba2ecc54f54aca7b849de8a450636b5819e34a0 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Tue, 16 Oct 2018 06:11:44 -0500 Subject: [PATCH 04/13] fixing bad ports reference --- azurerm/resource_arm_container_group.go | 12 +++++++----- azurerm/resource_arm_container_group_test.go | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 6ab3017a8abf..f7aa0ca5ca2b 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -147,11 +147,12 @@ func resourceArmContainerGroup() *schema.Resource { }, "port": { - Type: schema.TypeInt, - Optional: true, - ForceNew: true, - Deprecated: "Use `ports` instead.", - ValidateFunc: validate.PortNumber, + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"ports"}, + Deprecated: "Use `ports` instead.", + ValidateFunc: validate.PortNumber, }, "ports": { @@ -186,6 +187,7 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + ConflictsWith: []string{"ports"}, Deprecated: "Use `ports` instead.", DiffSuppressFunc: ignoreCaseDiffSuppressFunc, ValidateFunc: validation.StringInSlice([]string{ diff --git a/azurerm/resource_arm_container_group_test.go b/azurerm/resource_arm_container_group_test.go index 021f755d8cbd..0605a50c410f 100644 --- a/azurerm/resource_arm_container_group_test.go +++ b/azurerm/resource_arm_container_group_test.go @@ -267,8 +267,8 @@ func TestAccAzureRMContainerGroup_linuxComplete(t *testing.T) { }), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.port", "80"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.protocol", "TCP"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), resource.TestCheckResourceAttr(resourceName, "container.0.command", "/bin/bash -c ls"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.#", "3"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.0", "/bin/bash"), From 8f55e168a37dc3c62c0c80b21e878b6517870407 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Thu, 25 Oct 2018 14:44:10 -0500 Subject: [PATCH 05/13] conflict with the specific element --- azurerm/resource_arm_container_group.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 6898b017a286..75e4bb01fadb 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -150,7 +150,7 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeInt, Optional: true, ForceNew: true, - ConflictsWith: []string{"ports"}, + ConflictsWith: []string{"container.0.ports"}, Deprecated: "Use `ports` instead.", ValidateFunc: validate.PortNumber, }, @@ -159,7 +159,7 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeList, Optional: true, ForceNew: true, - ConflictsWith: []string{"port", "protocol"}, + ConflictsWith: []string{"container.0.port", "container.0.protocol"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "protocol": { @@ -187,7 +187,7 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ConflictsWith: []string{"ports"}, + ConflictsWith: []string{"container.0.ports"}, Deprecated: "Use `ports` instead.", DiffSuppressFunc: ignoreCaseDiffSuppressFunc, ValidateFunc: validation.StringInSlice([]string{ From 648e46a0e95f7e5367d530fd495dbcd7165e67d3 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Tue, 27 Nov 2018 13:23:48 -0600 Subject: [PATCH 06/13] removing unnecessary package --- azurerm/resource_arm_container_group_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/azurerm/resource_arm_container_group_test.go b/azurerm/resource_arm_container_group_test.go index 22cf27fea384..87bef391d6f6 100644 --- a/azurerm/resource_arm_container_group_test.go +++ b/azurerm/resource_arm_container_group_test.go @@ -9,8 +9,6 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" - - "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-04-01/containerinstance" ) func TestAccAzureRMContainerGroup_imageRegistryCredentials(t *testing.T) { @@ -616,7 +614,7 @@ resource "azurerm_container_group" "test" { `, ri, location, ri, ri, ri, ri) } -func testCheckAzureRMContainerGroupExists(name string, checkResp func(containerinstance.ContainerGroup) error) resource.TestCheckFunc { +func testCheckAzureRMContainerGroupExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] From 7a1debfcd2489d3d613c68c0771700d74e90e55b Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Wed, 28 Nov 2018 10:47:42 -0600 Subject: [PATCH 07/13] fix set list issue --- azurerm/resource_arm_container_group.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index e3d62a2dbbf9..71968af98d7e 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -455,9 +455,9 @@ func expandContainerGroupContainers(d *schema.ResourceData) (*[]containerinstanc } if v, ok := data["ports"]; ok { - p := v.([]interface{}) + s := v.(*schema.Set) var ports []containerinstance.ContainerPort - for _, v := range p { + for _, v := range s.List() { portObj := v.(map[string]interface{}) port := int32(portObj["port"].(int)) proto := portObj["protocol"].(string) From 1b22262ef8e56580696f13061285b24107ab75f8 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Wed, 28 Nov 2018 22:03:37 -0600 Subject: [PATCH 08/13] adding documentation, fixing tests --- azurerm/resource_arm_container_group.go | 42 ++++++++++++++------ website/docs/r/container_group.html.markdown | 17 ++++++-- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 71968af98d7e..332fa0daf548 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -465,6 +465,10 @@ func expandContainerGroupContainers(d *schema.ResourceData) (*[]containerinstanc Protocol: containerinstance.ContainerNetworkProtocol(strings.ToUpper(proto)), Port: &port, }) + containerGroupPorts = append(containerGroupPorts, containerinstance.Port{ + Protocol: containerinstance.ContainerGroupNetworkProtocol(strings.ToUpper(proto)), + Port: &port, + }) } container.Ports = &ports } @@ -650,10 +654,13 @@ func flattenContainerGroupContainers(d *schema.ResourceData, containers *[]conta //map old container names to index so we can look up things up nameIndexMap := map[string]int{} + var newPortsField bool for i, c := range d.Get("container").([]interface{}) { cfg := c.(map[string]interface{}) nameIndexMap[cfg["name"].(string)] = i - + if _, ok := cfg["ports"]; ok { + newPortsField = true + } } containerCfg := make([]interface{}, 0, len(*containers)) @@ -684,19 +691,30 @@ func flattenContainerGroupContainers(d *schema.ResourceData, containers *[]conta } if len(*container.Ports) > 0 { - containerPort := *(*container.Ports)[0].Port - containerConfig["port"] = containerPort - // protocol isn't returned in container config, have to search in container group ports - protocol := "" - if containerGroupPorts != nil { - for _, cgPort := range *containerGroupPorts { - if *cgPort.Port == containerPort { - protocol = string(cgPort.Protocol) + if newPortsField { + ports := make([]interface{}, 0) + for _, p := range *container.Ports { + port := make(map[string]interface{}) + port["port"] = int(*p.Port) + port["protocol"] = string(p.Protocol) + ports = append(ports, port) + } + containerConfig["ports"] = ports + } else { + containerPort := *(*container.Ports)[0].Port + containerConfig["port"] = containerPort + // protocol isn't returned in container config, have to search in container group ports + protocol := "" + if containerGroupPorts != nil { + for _, cgPort := range *containerGroupPorts { + if *cgPort.Port == containerPort { + protocol = string(cgPort.Protocol) + } } } - } - if protocol != "" { - containerConfig["protocol"] = protocol + if protocol != "" { + containerConfig["protocol"] = protocol + } } } diff --git a/website/docs/r/container_group.html.markdown b/website/docs/r/container_group.html.markdown index 7c37b036f2de..b984972b9ae3 100644 --- a/website/docs/r/container_group.html.markdown +++ b/website/docs/r/container_group.html.markdown @@ -49,7 +49,12 @@ resource "azurerm_container_group" "aci-helloworld" { image = "seanmckenna/aci-hellofiles" cpu = "0.5" memory = "1.5" - port = "80" + ports = { + port = 80 + } + ports = { + port = 443 + } environment_variables { "NODE_ENV" = "testing" @@ -119,9 +124,7 @@ The `container` block supports: * `memory` - (Required) The required memory of the containers in GB. Changing this forces a new resource to be created. -* `port` - (Optional) A public port for the container. Changing this forces a new resource to be created. - -* `protocol` - (Optional) The protocol associated with port for the container. Allowed values are `TCP` and `UDP`. +* `ports` - (Optional) A set of public ports for the container. Changing this forces a new resource to be created. Set as documented in the `ports` block below. * `environment_variables` - (Optional) A list of environment variables to be set on the container. Specified as a map of name/value pairs. Changing this forces a new resource to be created. @@ -157,6 +160,12 @@ The `image_registry_credential` block supports: * `server` - (Required) The address to use to connect to the registry without protocol ("https"/"http"). For example: "myacr.acr.io" +The `ports` block supports: + +* `port` - (Required) The port number the container will expose. + +* `protocol` - (Optional) The network protocol ("tcp"/"udp") the port will use. + ## Attributes Reference The following attributes are exported: From a0727c3bfd16a31ca266e53fd12494a78bc93020 Mon Sep 17 00:00:00 2001 From: kt Date: Sun, 6 Jan 2019 12:37:04 -0800 Subject: [PATCH 09/13] update default to use constant --- azurerm/resource_arm_container_group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 52cf4b16e9ad..40d034de421b 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -169,7 +169,7 @@ func resourceArmContainerGroup() *schema.Resource { Optional: true, ForceNew: true, DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - Default: string("TCP"), + Default: string(containerinstance.TCP), ValidateFunc: validation.StringInSlice([]string{ string(containerinstance.TCP), string(containerinstance.UDP), From 55b840b01964b7e3a2fbf940ef59f25d8f6426a7 Mon Sep 17 00:00:00 2001 From: Nate Sweet Date: Wed, 9 Jan 2019 15:00:54 -0600 Subject: [PATCH 10/13] ports are sets --- azurerm/resource_arm_container_group.go | 2 +- azurerm/resource_arm_container_group_test.go | 14 -------------- website/docs/r/container_group.html.markdown | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 332fa0daf548..74452555bf24 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -167,7 +167,7 @@ func resourceArmContainerGroup() *schema.Resource { Optional: true, ForceNew: true, DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - Default: string("TCP"), + Default: string(containerinstance.TCP), ValidateFunc: validation.StringInSlice([]string{ string(containerinstance.TCP), string(containerinstance.UDP), diff --git a/azurerm/resource_arm_container_group_test.go b/azurerm/resource_arm_container_group_test.go index 87bef391d6f6..8b424a962d7c 100644 --- a/azurerm/resource_arm_container_group_test.go +++ b/azurerm/resource_arm_container_group_test.go @@ -84,8 +84,6 @@ func TestAccAzureRMContainerGroup_imageRegistryCredentialsUpdate(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.username", "updatedusername"), resource.TestCheckResourceAttr(resourceName, "image_registry_credential.0.password", "updatedpassword"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), ), }, }, @@ -150,10 +148,6 @@ func TestAccAzureRMContainerGroup_linuxBasicUpdate(t *testing.T) { testCheckAzureRMContainerGroupExists(resourceName), resource.TestCheckResourceAttr(resourceName, "container.#", "2"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "2"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.1.port", "5443"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.1.protocol", "UDP"), ), }, }, @@ -177,8 +171,6 @@ func TestAccAzureRMContainerGroup_linuxComplete(t *testing.T) { testCheckAzureRMContainerGroupExists(resourceName), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), resource.TestCheckResourceAttr(resourceName, "container.0.command", "/bin/bash -c ls"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.#", "3"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.0", "/bin/bash"), @@ -231,10 +223,6 @@ func TestAccAzureRMContainerGroup_windowsBasic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "container.#", "1"), resource.TestCheckResourceAttr(resourceName, "os_type", "Windows"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "2"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "443"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), ), }, { @@ -263,8 +251,6 @@ func TestAccAzureRMContainerGroup_windowsComplete(t *testing.T) { testCheckAzureRMContainerGroupExists(resourceName), resource.TestCheckResourceAttr(resourceName, "container.#", "1"), resource.TestCheckResourceAttr(resourceName, "container.0.ports.#", "1"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.port", "80"), - resource.TestCheckResourceAttr(resourceName, "container.0.ports.0.protocol", "TCP"), resource.TestCheckResourceAttr(resourceName, "container.0.command", "cmd.exe echo hi"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.#", "3"), resource.TestCheckResourceAttr(resourceName, "container.0.commands.0", "cmd.exe"), diff --git a/website/docs/r/container_group.html.markdown b/website/docs/r/container_group.html.markdown index b984972b9ae3..b4fbcfa4ca30 100644 --- a/website/docs/r/container_group.html.markdown +++ b/website/docs/r/container_group.html.markdown @@ -164,7 +164,7 @@ The `ports` block supports: * `port` - (Required) The port number the container will expose. -* `protocol` - (Optional) The network protocol ("tcp"/"udp") the port will use. +* `protocol` - (Optional) The network protocol ("tcp"/"udp") associated with port. The default is `TCP`. ## Attributes Reference From 6997434589e7785d225e57285338b4bb9116aaca Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 10 Jan 2019 22:57:00 -0800 Subject: [PATCH 11/13] fixed container group ports --- azurerm/resource_arm_container_group.go | 190 ++++++++++--------- azurerm/resource_arm_container_group_test.go | 12 +- website/docs/r/container_group.html.markdown | 8 +- 3 files changed, 112 insertions(+), 98 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index 40d034de421b..b9a5881b5c6f 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -1,7 +1,10 @@ package azurerm import ( + "bytes" "fmt" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "log" "strings" @@ -149,55 +152,58 @@ func resourceArmContainerGroup() *schema.Resource { }, "port": { - Type: schema.TypeInt, - Optional: true, - ForceNew: true, - ConflictsWith: []string{"container.0.ports"}, - Deprecated: "Use `ports` instead.", - ValidateFunc: validate.PortNumber, + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Computed: true, + Deprecated: "Deprecated in favor of `ports`", + ValidateFunc: validate.PortNumber, + }, + + "protocol": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Deprecated: "Deprecated in favor of `ports`", + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: validation.StringInSlice([]string{ + string(containerinstance.TCP), + string(containerinstance.UDP), + }, true), }, "ports": { - Type: schema.TypeSet, - Optional: true, - ForceNew: true, - ConflictsWith: []string{"container.0.port", "container.0.protocol"}, + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Computed: true, + Set: resourceArmContainerGroupPortsHash, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "protocol": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - Default: string(containerinstance.TCP), - ValidateFunc: validation.StringInSlice([]string{ - string(containerinstance.TCP), - string(containerinstance.UDP), - }, true), - }, "port": { Type: schema.TypeInt, - Required: true, + Optional: true, ForceNew: true, + Computed: true, ValidateFunc: validate.PortNumber, }, + + "protocol": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + //Default: string(containerinstance.TCP), restore in 2.0 + ValidateFunc: validation.StringInSlice([]string{ + string(containerinstance.TCP), + string(containerinstance.UDP), + }, false), + }, }, }, }, - "protocol": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{"container.0.ports"}, - Deprecated: "Use `ports` instead.", - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - ValidateFunc: validation.StringInSlice([]string{ - string(containerinstance.TCP), - string(containerinstance.UDP), - }, true), - }, - "environment_variables": { Type: schema.TypeMap, ForceNew: true, @@ -446,46 +452,44 @@ func expandContainerGroupContainers(d *schema.ResourceData) (*[]containerinstanc }, } - if v := data["port"]; v != 0 { - port := int32(v.(int)) - - // container port (port number) - container.Ports = &[]containerinstance.ContainerPort{ - { - Port: &port, - }, - } - - // container group port (port number + protocol) - containerGroupPort := containerinstance.Port{ - Port: &port, - } - - if v, ok := data["protocol"]; ok { - protocol := v.(string) - containerGroupPort.Protocol = containerinstance.ContainerGroupNetworkProtocol(strings.ToUpper(protocol)) - } - - containerGroupPorts = append(containerGroupPorts, containerGroupPort) - } - - if v, ok := data["ports"]; ok { - s := v.(*schema.Set) + if v, ok := data["ports"].(*schema.Set); ok && len(v.List()) > 0 { var ports []containerinstance.ContainerPort - for _, v := range s.List() { + for _, v := range v.List() { portObj := v.(map[string]interface{}) + port := int32(portObj["port"].(int)) proto := portObj["protocol"].(string) + ports = append(ports, containerinstance.ContainerPort{ - Protocol: containerinstance.ContainerNetworkProtocol(strings.ToUpper(proto)), Port: &port, + Protocol: containerinstance.ContainerNetworkProtocol(proto), }) containerGroupPorts = append(containerGroupPorts, containerinstance.Port{ - Protocol: containerinstance.ContainerGroupNetworkProtocol(strings.ToUpper(proto)), Port: &port, + Protocol: containerinstance.ContainerGroupNetworkProtocol(proto), }) } container.Ports = &ports + } else { + if v := int32(data["port"].(int)); v != 0 { + ports := []containerinstance.ContainerPort{ + { + Port: &v, + }, + } + + port := containerinstance.Port{ + Port: &v, + } + + if v, ok := data["protocol"].(string); ok { + ports[0].Protocol = containerinstance.ContainerNetworkProtocol(v) + port.Protocol = containerinstance.ContainerGroupNetworkProtocol(v) + } + + container.Ports = &ports + containerGroupPorts = append(containerGroupPorts, port) + } } // Set both sensitive and non-secure environment variables @@ -669,13 +673,9 @@ func flattenContainerGroupContainers(d *schema.ResourceData, containers *[]conta //map old container names to index so we can look up things up nameIndexMap := map[string]int{} - var newPortsField bool for i, c := range d.Get("container").([]interface{}) { cfg := c.(map[string]interface{}) nameIndexMap[cfg["name"].(string)] = i - if _, ok := cfg["ports"]; ok { - newPortsField = true - } } containerCfg := make([]interface{}, 0, len(*containers)) @@ -705,31 +705,32 @@ func flattenContainerGroupContainers(d *schema.ResourceData, containers *[]conta } } - if len(*container.Ports) > 0 { - if newPortsField { - ports := make([]interface{}, 0) - for _, p := range *container.Ports { - port := make(map[string]interface{}) - port["port"] = int(*p.Port) - port["protocol"] = string(p.Protocol) - ports = append(ports, port) + if cPorts := container.Ports; cPorts != nil && len(*cPorts) > 0 { + ports := make([]interface{}, 0) + for _, p := range *cPorts { + port := make(map[string]interface{}) + if v := p.Port; v != nil { + port["port"] = int(*v) } - containerConfig["ports"] = ports - } else { - containerPort := *(*container.Ports)[0].Port - containerConfig["port"] = containerPort - // protocol isn't returned in container config, have to search in container group ports - protocol := "" - if containerGroupPorts != nil { - for _, cgPort := range *containerGroupPorts { - if *cgPort.Port == containerPort { - protocol = string(cgPort.Protocol) - } + port["protocol"] = string(p.Protocol) + ports = append(ports, port) + } + containerConfig["ports"] = schema.NewSet(resourceArmContainerGroupPortsHash, ports) + + //old deprecated code + containerPort := *(*cPorts)[0].Port + containerConfig["port"] = containerPort + // protocol isn't returned in container config, have to search in container group ports + protocol := "" + if containerGroupPorts != nil { + for _, cgPort := range *containerGroupPorts { + if *cgPort.Port == containerPort { + protocol = string(cgPort.Protocol) } } - if protocol != "" { - containerConfig["protocol"] = protocol - } + } + if protocol != "" { + containerConfig["protocol"] = protocol } } @@ -865,3 +866,14 @@ func flattenContainerVolumes(volumeMounts *[]containerinstance.VolumeMount, cont return volumeConfigs } + +func resourceArmContainerGroupPortsHash(v interface{}) int { + var buf bytes.Buffer + + if m, ok := v.(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", m["port"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string))) + } + + return hashcode.String(buf.String()) +} diff --git a/azurerm/resource_arm_container_group_test.go b/azurerm/resource_arm_container_group_test.go index 5fd76efd9961..6e3f3c34af8b 100644 --- a/azurerm/resource_arm_container_group_test.go +++ b/azurerm/resource_arm_container_group_test.go @@ -385,7 +385,7 @@ resource "azurerm_container_group" "test" { cpu = "0.5" memory = "0.5" port = 5443 - protocol = "udp" + protocol = "UDP" } image_registry_credential { @@ -482,7 +482,7 @@ resource "azurerm_container_group" "test" { } ports = { port = 5443 - protocol = "udp" + protocol = "UDP" } } @@ -521,11 +521,11 @@ resource "azurerm_container_group" "test" { memory = "3.5" ports = { port = 80 - protocol = "tcp" + protocol = "TCP" } ports = { port = 443 - protocol = "tcp" + protocol = "TCP" } } @@ -559,7 +559,7 @@ resource "azurerm_container_group" "test" { memory = "3.5" ports = { port = 80 - protocol = "tcp" + protocol = "TCP" } environment_variables { @@ -623,7 +623,7 @@ resource "azurerm_container_group" "test" { ports = { port = 80 - protocol = "tcp" + protocol = "TCP" } volume { diff --git a/website/docs/r/container_group.html.markdown b/website/docs/r/container_group.html.markdown index 1498de576a66..6ab0bf58e4c8 100644 --- a/website/docs/r/container_group.html.markdown +++ b/website/docs/r/container_group.html.markdown @@ -50,10 +50,12 @@ resource "azurerm_container_group" "aci-helloworld" { cpu = "0.5" memory = "1.5" ports = { - port = 80 + port = 80 + protocol = "TCP" } ports = { - port = 443 + port = 443 + protocol = "TCP" } environment_variables { @@ -166,7 +168,7 @@ The `ports` block supports: * `port` - (Required) The port number the container will expose. -* `protocol` - (Optional) The network protocol ("tcp"/"udp") associated with port. The default is `TCP`. +* `protocol` - (Required) The network protocol associated with port. Possible values are `TCP` & `UDP`. ## Attributes Reference From 04b5bf381c6678c91677cf6ea787bafe587477dd Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 10 Jan 2019 23:20:18 -0800 Subject: [PATCH 12/13] make fmt goimport --- azurerm/resource_arm_container_group.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index b9a5881b5c6f..a53c382ed135 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -3,11 +3,12 @@ package azurerm import ( "bytes" "fmt" - "github.com/hashicorp/terraform/helper/hashcode" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "log" "strings" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" + "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" From f80e9126ddadb25c82bd718b923839840a443c75 Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 10 Jan 2019 23:36:40 -0800 Subject: [PATCH 13/13] add some validation --- azurerm/resource_arm_container_group.go | 88 ++++++++++++++----------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/azurerm/resource_arm_container_group.go b/azurerm/resource_arm_container_group.go index a53c382ed135..0bdf5bd2dfaf 100644 --- a/azurerm/resource_arm_container_group.go +++ b/azurerm/resource_arm_container_group.go @@ -29,9 +29,10 @@ func resourceArmContainerGroup() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "location": locationSchema(), @@ -43,7 +44,7 @@ func resourceArmContainerGroup() *schema.Resource { Optional: true, Default: "Public", ForceNew: true, - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + DiffSuppressFunc: suppress.CaseDifference, ValidateFunc: validation.StringInSlice([]string{ string(containerinstance.Public), }, true), @@ -53,7 +54,7 @@ func resourceArmContainerGroup() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + DiffSuppressFunc: suppress.CaseDifference, ValidateFunc: validation.StringInSlice([]string{ string(containerinstance.Windows), string(containerinstance.Linux), @@ -69,23 +70,23 @@ func resourceArmContainerGroup() *schema.Resource { "server": { Type: schema.TypeString, Required: true, - ValidateFunc: validate.NoEmptyStrings, ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "username": { Type: schema.TypeString, Required: true, - ValidateFunc: validate.NoEmptyStrings, ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "password": { Type: schema.TypeString, Required: true, Sensitive: true, - ValidateFunc: validate.NoEmptyStrings, ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, }, }, @@ -98,7 +99,7 @@ func resourceArmContainerGroup() *schema.Resource { Optional: true, ForceNew: true, Default: string(containerinstance.Always), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + DiffSuppressFunc: suppress.CaseDifference, ValidateFunc: validation.StringInSlice([]string{ string(containerinstance.Always), string(containerinstance.Never), @@ -106,16 +107,6 @@ func resourceArmContainerGroup() *schema.Resource { }, true), }, - "ip_address": { - Type: schema.TypeString, - Computed: true, - }, - - "fqdn": { - Type: schema.TypeString, - Computed: true, - }, - "dns_name_label": { Type: schema.TypeString, Optional: true, @@ -129,15 +120,17 @@ func resourceArmContainerGroup() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "image": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "cpu": { @@ -239,15 +232,17 @@ func resourceArmContainerGroup() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "mount_path": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "read_only": { @@ -258,21 +253,24 @@ func resourceArmContainerGroup() *schema.Resource { }, "share_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "storage_account_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, "storage_account_key": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, }, }, @@ -280,6 +278,16 @@ func resourceArmContainerGroup() *schema.Resource { }, }, }, + + "ip_address": { + Type: schema.TypeString, + Computed: true, + }, + + "fqdn": { + Type: schema.TypeString, + Computed: true, + }, }, } }