diff --git a/builtin/providers/azure/resource_azure_instance_test.go b/builtin/providers/azure/resource_azure_instance_test.go index 1125fc9f3..755bed308 100644 --- a/builtin/providers/azure/resource_azure_instance_test.go +++ b/builtin/providers/azure/resource_azure_instance_test.go @@ -348,7 +348,7 @@ resource "azure_security_group" "foo" { resource "azure_security_group_rule" "foo" { name = "rdp" - security_group_name = "${azure_security_group.foo.name}" + security_group_names = ["${azure_security_group.foo.name}"] priority = 101 source_address_prefix = "*" source_port_range = "*" @@ -404,7 +404,7 @@ resource "azure_security_group" "foo" { resource "azure_security_group_rule" "foo" { name = "rdp" - security_group_name = "${azure_security_group.foo.name}" + security_group_names = ["${azure_security_group.foo.name}"] priority = 101 source_address_prefix = "*" source_port_range = "*" @@ -422,7 +422,7 @@ resource "azure_security_group" "bar" { resource "azure_security_group_rule" "bar" { name = "rdp" - security_group_name = "${azure_security_group.bar.name}" + security_group_names = ["${azure_security_group.bar.name}"] priority = 101 source_address_prefix = "192.168.0.0/24" source_port_range = "*" diff --git a/builtin/providers/azure/resource_azure_security_group_rule.go b/builtin/providers/azure/resource_azure_security_group_rule.go index 9adf7451d..f4f946db5 100644 --- a/builtin/providers/azure/resource_azure_security_group_rule.go +++ b/builtin/providers/azure/resource_azure_security_group_rule.go @@ -16,7 +16,6 @@ func resourceAzureSecurityGroupRule() *schema.Resource { Create: resourceAzureSecurityGroupRuleCreate, Read: resourceAzureSecurityGroupRuleRead, Update: resourceAzureSecurityGroupRuleUpdate, - Exists: resourceAzureSecurityGroupRuleExists, Delete: resourceAzureSecurityGroupRuleDelete, Schema: map[string]*schema.Schema{ @@ -26,11 +25,15 @@ func resourceAzureSecurityGroupRule() *schema.Resource { ForceNew: true, Description: parameterDescriptions["name"], }, - "security_group_name": &schema.Schema{ - Type: schema.TypeString, + "security_group_names": &schema.Schema{ + Type: schema.TypeSet, Required: true, ForceNew: true, - Description: parameterDescriptions["netsecgroup_secgroup_name"], + Description: parameterDescriptions["netsecgroup_secgroup_names"], + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, }, "type": &schema.Schema{ Type: schema.TypeString, @@ -97,18 +100,24 @@ func resourceAzureSecurityGroupRuleCreate(d *schema.ResourceData, meta interface Protocol: netsecgroup.RuleProtocol(d.Get("protocol").(string)), } - // send the create request to Azure: - log.Println("[INFO] Sending network security group rule creation request to Azure.") - reqID, err := secGroupClient.SetNetworkSecurityGroupRule( - d.Get("security_group_name").(string), - rule, - ) - if err != nil { - return fmt.Errorf("Error sending network security group rule creation request to Azure: %s", err) - } - err = mgmtClient.WaitForOperation(reqID, nil) - if err != nil { - return fmt.Errorf("Error creating network security group rule on Azure: %s", err) + // apply the rule to all the necessary network security groups: + secGroups := d.Get("security_group_names").(*schema.Set).List() + for _, sg := range secGroups { + secGroup := sg.(string) + + // send the create request to Azure: + log.Printf("[INFO] Sending Azure security group rule addition request for security group %q.", secGroup) + reqID, err := secGroupClient.SetNetworkSecurityGroupRule( + secGroup, + rule, + ) + if err != nil { + return fmt.Errorf("Error sending Azure network security group rule creation request for security group %q: %s", secGroup, err) + } + err = mgmtClient.WaitForOperation(reqID, nil) + if err != nil { + return fmt.Errorf("Error creating Azure network security group rule for security group %q: %s", secGroup, err) + } } d.SetId(name) @@ -121,89 +130,61 @@ func resourceAzureSecurityGroupRuleRead(d *schema.ResourceData, meta interface{} azureClient := meta.(*Client) secGroupClient := azureClient.secGroupClient - secGroupName := d.Get("security_group_name").(string) - - // get info on the network security group and check its rules for this one: - log.Println("[INFO] Sending network security group rule query to Azure.") - secgroup, err := secGroupClient.GetNetworkSecurityGroup(secGroupName) - if err != nil { - if !management.IsResourceNotFoundError(err) { - return fmt.Errorf("Error issuing network security group rules query: %s", err) - } else { - // it meants that the network security group this rule belonged to has - // been deleted; so we must remove this resource from the schema: - d.SetId("") - return nil - } - } - - // find our security rule: var found bool name := d.Get("name").(string) - for _, rule := range secgroup.Rules { - if rule.Name == name { - found = true - log.Println("[DEBUG] Reading state of Azure network security group rule.") - d.Set("type", rule.Type) - d.Set("priority", rule.Priority) - d.Set("action", rule.Action) - d.Set("source_address_prefix", rule.SourceAddressPrefix) - d.Set("source_port_range", rule.SourcePortRange) - d.Set("destination_address_prefix", rule.DestinationAddressPrefix) - d.Set("destination_port_range", rule.DestinationPortRange) - d.Set("protocol", rule.Protocol) + secGroups := d.Get("security_group_names").(*schema.Set).List() + remaining := schema.NewSet(schema.HashString, nil) - break + // for each of our security groups; check for our rule: + for _, sg := range secGroups { + secGroupName := sg.(string) + + // get info on the network security group and check its rules for this one: + log.Printf("[INFO] Sending Azure network security group rule query for security group %s.", secGroupName) + secgroup, err := secGroupClient.GetNetworkSecurityGroup(secGroupName) + if err != nil { + if !management.IsResourceNotFoundError(err) { + return fmt.Errorf("Error issuing network security group rules query for security group %q: %s", secGroupName, err) + } else { + // it meants that the network security group this rule belonged to has + // been deleted; so we skip this iteration: + continue + } + } + + // find our security rule: + for _, rule := range secgroup.Rules { + if rule.Name == name { + // note the fact that this rule still apllies to this security group: + found = true + remaining.Add(secGroupName) + + break + } } } - // check if the rule still exists, and is not, remove the resource: + // check to see if there is any security group still having this rule: if !found { d.SetId("") + return nil } + + // now; we must update the set of security groups still having this rule: + d.Set("security_group_names", remaining) return nil } // resourceAzureSecurityGroupRuleUpdate does all the necessary API calls to -// update the state of a network security group ruke off Azure. +// update the state of a network security group rule off Azure. func resourceAzureSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface{}) error { azureClient := meta.(*Client) mgmtClient := azureClient.mgmtClient secGroupClient := azureClient.secGroupClient - secGroupName := d.Get("security_group_name").(string) - - // get info on the network security group and check its rules for this one: - log.Println("[INFO] Sending network security group rule query for update to Azure.") - secgroup, err := secGroupClient.GetNetworkSecurityGroup(secGroupName) - if err != nil { - if !management.IsResourceNotFoundError(err) { - return fmt.Errorf("Error issuing network security group rules query: %s", err) - } else { - // it meants that the network security group this rule belonged to has - // been deleted; so we must remove this resource from the schema: - d.SetId("") - return nil - } - } - - // try and find our security group rule: var found bool name := d.Get("name").(string) - for _, rule := range secgroup.Rules { - if rule.Name == name { - found = true - } - } - // check is the resource has not been deleted in the meantime: - if !found { - // if not; remove the resource: - d.SetId("") - return nil - } - - // else, start building up the rule request struct: newRule := netsecgroup.RuleRequest{ Name: d.Get("name").(string), Type: netsecgroup.RuleType(d.Get("type").(string)), @@ -216,59 +197,62 @@ func resourceAzureSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface Protocol: netsecgroup.RuleProtocol(d.Get("protocol").(string)), } - // send the create request to Azure: - log.Println("[INFO] Sending network security group rule update request to Azure.") - reqID, err := secGroupClient.SetNetworkSecurityGroupRule( - secGroupName, - newRule, - ) - if err != nil { - return fmt.Errorf("Error sending network security group rule update request to Azure: %s", err) + // iterate over all the security groups that should have this rule and + // update it per security group: + remaining := schema.NewSet(schema.HashString, nil) + secGroupNames := d.Get("security_group_names").(*schema.Set).List() + for _, sg := range secGroupNames { + secGroupName := sg.(string) + + // get info on the network security group and check its rules for this one: + log.Printf("[INFO] Sending Azure network security group rule query for security group %q.", secGroupName) + secgroup, err := secGroupClient.GetNetworkSecurityGroup(secGroupName) + if err != nil { + if !management.IsResourceNotFoundError(err) { + return fmt.Errorf("Error issuing network security group rules query: %s", err) + } else { + // it meants that the network security group this rule belonged to has + // been deleted; so we skip this iteration: + continue + } + } + + // try and find our security group rule: + for _, rule := range secgroup.Rules { + if rule.Name == name { + // note the fact that this rule still apllies to this security group: + found = true + remaining.Add("secGroupName") + + // and go ahead and update it: + log.Printf("[INFO] Sending Azure network security group rule update request for security group %q.", secGroupName) + reqID, err := secGroupClient.SetNetworkSecurityGroupRule( + secGroupName, + newRule, + ) + if err != nil { + return fmt.Errorf("Error sending Azure network security group rule update request for security group %q: %s", secGroupName, err) + } + err = mgmtClient.WaitForOperation(reqID, nil) + if err != nil { + return fmt.Errorf("Error updating Azure network security group rule for security group %q: %s", secGroupName, err) + } + } + } } - err = mgmtClient.WaitForOperation(reqID, nil) - if err != nil { - return fmt.Errorf("Error updating network security group rule on Azure: %s", err) + + // check to see if there is any security group still having this rule: + if !found { + d.SetId("") + return nil } + // here; we must update the set of security groups still having this rule: + d.Set("security_group_names", remaining) + return nil } -// resourceAzureSecurityGroupRuleExists does all the necessary API calls to -// check for the existence of the network security group rule on Azure. -func resourceAzureSecurityGroupRuleExists(d *schema.ResourceData, meta interface{}) (bool, error) { - secGroupClient := meta.(*Client).secGroupClient - - secGroupName := d.Get("security_group_name").(string) - - // get info on the network security group and search for our rule: - log.Println("[INFO] Sending network security group rule query for existence check to Azure.") - secgroup, err := secGroupClient.GetNetworkSecurityGroup(secGroupName) - if err != nil { - if !management.IsResourceNotFoundError(err) { - return false, fmt.Errorf("Error issuing network security group rules query: %s", err) - } else { - // it meants that the network security group this rule belonged to has - // been deleted; so we must remove this resource from the schema: - d.SetId("") - return false, nil - } - } - - // try and find our security group rule: - name := d.Get("name").(string) - for _, rule := range secgroup.Rules { - if rule.Name == name { - return true, nil - } - } - - // if here; it means the resource has been deleted in the - // meantime and must be removed from the schema: - d.SetId("") - - return false, nil -} - // resourceAzureSecurityGroupRuleDelete does all the necessary API calls to // delete a network security group rule off Azure. func resourceAzureSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { @@ -276,35 +260,39 @@ func resourceAzureSecurityGroupRuleDelete(d *schema.ResourceData, meta interface mgmtClient := azureClient.mgmtClient secGroupClient := azureClient.secGroupClient - secGroupName := d.Get("security_group_name").(string) - - // get info on the network security group and search for our rule: - log.Println("[INFO] Sending network security group rule query for deletion to Azure.") - secgroup, err := secGroupClient.GetNetworkSecurityGroup(secGroupName) - if err != nil { - if management.IsResourceNotFoundError(err) { - // it meants that the network security group this rule belonged to has - // been deleted; so we need do nothing more but stop tracking the resource: - d.SetId("") - return nil - } else { - return fmt.Errorf("Error issuing network security group rules query: %s", err) - } - } - - // check is the resource has not been deleted in the meantime: name := d.Get("name").(string) - for _, rule := range secgroup.Rules { - if rule.Name == name { - // if not; we shall issue the delete: - reqID, err := secGroupClient.DeleteNetworkSecurityGroupRule(secGroupName, name) - if err != nil { - return fmt.Errorf("Error sending network security group rule delete request to Azure: %s", err) + secGroupNames := d.Get("security_group_names").(*schema.Set).List() + for _, sg := range secGroupNames { + secGroupName := sg.(string) + + // get info on the network security group and search for our rule: + log.Printf("[INFO] Sending network security group rule query for security group %q.", secGroupName) + + secgroup, err := secGroupClient.GetNetworkSecurityGroup(secGroupName) + if err != nil { + if management.IsResourceNotFoundError(err) { + // it means that this network security group this rule belonged to has + // been deleted; so we need not do anything more here: + continue + } else { + return fmt.Errorf("Error issuing Azure network security group rules query for security group %q: %s", secGroupName, err) } - err = mgmtClient.WaitForOperation(reqID, nil) - if err != nil { - return fmt.Errorf("Error deleting network security group rule off Azure: %s", err) + } + + // check if the rule has been deleted in the meantime: + for _, rule := range secgroup.Rules { + if rule.Name == name { + // if not; we shall issue the delete: + reqID, err := secGroupClient.DeleteNetworkSecurityGroupRule(secGroupName, name) + if err != nil { + return fmt.Errorf("Error sending network security group rule delete request to Azure: %s", err) + } + err = mgmtClient.WaitForOperation(reqID, nil) + if err != nil { + return fmt.Errorf("Error deleting network security group rule off Azure: %s", err) + } } + break } } diff --git a/builtin/providers/azure/resource_azure_security_group_rule_test.go b/builtin/providers/azure/resource_azure_security_group_rule_test.go index 29b6e90ca..ec430f098 100644 --- a/builtin/providers/azure/resource_azure_security_group_rule_test.go +++ b/builtin/providers/azure/resource_azure_security_group_rule_test.go @@ -4,30 +4,44 @@ import ( "fmt" "testing" + "github.com/Azure/azure-sdk-for-go/management" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" ) -func TestAccAzureSecurityGroupRule(t *testing.T) { +var ( + testAcctestingSecurityGroup1 = fmt.Sprintf("%s-%d", testAccSecurityGroupName, 1) + testAccTestingSecurityGroupHash1 = fmt.Sprintf("%d", schema.HashString(testAcctestingSecurityGroup1)) + + testAcctestingSecurityGroup2 = fmt.Sprintf("%s-%d", testAccSecurityGroupName, 2) + testAccTestingSecurityGroupHash2 = fmt.Sprintf("%d", schema.HashString(testAcctestingSecurityGroup2)) +) + +func TestAccAzureSecurityGroupRuleBasic(t *testing.T) { name := "azure_security_group_rule.foo" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAzureSecurityGroupRuleDeleted, + CheckDestroy: testAccCheckAzureSecurityGroupRuleDeleted([]string{testAccSecurityGroupName}), Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccAzureSecurityGroupRule, + Config: testAccAzureSecurityGroupRuleBasicConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckAzureSecurityGroupRuleExists(name), + testAccCheckAzureSecurityGroupRuleExists(name, testAccSecurityGroupName), resource.TestCheckResourceAttr(name, "name", "terraform-secgroup-rule"), - resource.TestCheckResourceAttr(name, "security_group_name", testAccSecurityGroupName), + resource.TestCheckResourceAttr(name, + fmt.Sprintf("security_group_names.%d", schema.HashString(testAccSecurityGroupName)), + testAccSecurityGroupName), resource.TestCheckResourceAttr(name, "type", "Inbound"), resource.TestCheckResourceAttr(name, "action", "Deny"), resource.TestCheckResourceAttr(name, "priority", "200"), resource.TestCheckResourceAttr(name, "source_address_prefix", "100.0.0.0/32"), resource.TestCheckResourceAttr(name, "source_port_range", "1000"), resource.TestCheckResourceAttr(name, "destination_address_prefix", "10.0.0.0/32"), + resource.TestCheckResourceAttr(name, "destination_port_range", "1000"), resource.TestCheckResourceAttr(name, "protocol", "TCP"), ), }, @@ -35,7 +49,99 @@ func TestAccAzureSecurityGroupRule(t *testing.T) { }) } -func testAccCheckAzureSecurityGroupRuleExists(name string) resource.TestCheckFunc { +func TestAccAzureSecurityGroupRuleAdvanced(t *testing.T) { + name := "azure_security_group_rule.foo" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAzureSecurityGroupRuleDeleted( + []string{ + testAcctestingSecurityGroup1, + testAcctestingSecurityGroup2, + }, + ), + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAzureSecurityGroupRuleAdvancedConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAzureSecurityGroupRuleExists(name, testAcctestingSecurityGroup1), + testAccCheckAzureSecurityGroupRuleExists(name, testAcctestingSecurityGroup2), + resource.TestCheckResourceAttr(name, "name", "terraform-secgroup-rule"), + resource.TestCheckResourceAttr(name, fmt.Sprintf("security_group_names.%s", + testAccTestingSecurityGroupHash1), testAcctestingSecurityGroup1), + resource.TestCheckResourceAttr(name, fmt.Sprintf("security_group_names.%s", + testAccTestingSecurityGroupHash2), testAcctestingSecurityGroup2), + resource.TestCheckResourceAttr(name, "type", "Inbound"), + resource.TestCheckResourceAttr(name, "action", "Deny"), + resource.TestCheckResourceAttr(name, "priority", "200"), + resource.TestCheckResourceAttr(name, "source_address_prefix", "100.0.0.0/32"), + resource.TestCheckResourceAttr(name, "source_port_range", "1000"), + resource.TestCheckResourceAttr(name, "destination_address_prefix", "10.0.0.0/32"), + resource.TestCheckResourceAttr(name, "destination_port_range", "1000"), + resource.TestCheckResourceAttr(name, "protocol", "TCP"), + ), + }, + }, + }) +} + +func TestAccAzureSecurityGroupRuleUpdate(t *testing.T) { + name := "azure_security_group_rule.foo" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAzureSecurityGroupRuleDeleted( + []string{ + testAcctestingSecurityGroup1, + testAcctestingSecurityGroup2, + }, + ), + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAzureSecurityGroupRuleAdvancedConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAzureSecurityGroupRuleExists(name, testAcctestingSecurityGroup1), + testAccCheckAzureSecurityGroupRuleExists(name, testAcctestingSecurityGroup2), + resource.TestCheckResourceAttr(name, "name", "terraform-secgroup-rule"), + resource.TestCheckResourceAttr(name, fmt.Sprintf("security_group_names.%s", + testAccTestingSecurityGroupHash1), testAcctestingSecurityGroup1), + resource.TestCheckResourceAttr(name, fmt.Sprintf("security_group_names.%s", + testAccTestingSecurityGroupHash2), testAcctestingSecurityGroup2), + resource.TestCheckResourceAttr(name, "type", "Inbound"), + resource.TestCheckResourceAttr(name, "action", "Deny"), + resource.TestCheckResourceAttr(name, "priority", "200"), + resource.TestCheckResourceAttr(name, "source_address_prefix", "100.0.0.0/32"), + resource.TestCheckResourceAttr(name, "source_port_range", "1000"), + resource.TestCheckResourceAttr(name, "destination_address_prefix", "10.0.0.0/32"), + resource.TestCheckResourceAttr(name, "destination_port_range", "1000"), + resource.TestCheckResourceAttr(name, "protocol", "TCP"), + ), + }, + + resource.TestStep{ + Config: testAccAzureSecurityGroupRuleUpdateConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAzureSecurityGroupRuleExists(name, testAcctestingSecurityGroup2), + resource.TestCheckResourceAttr(name, "name", "terraform-secgroup-rule"), + resource.TestCheckResourceAttr(name, fmt.Sprintf("security_group_names.%s", + testAccTestingSecurityGroupHash2), testAcctestingSecurityGroup2), + resource.TestCheckResourceAttr(name, "type", "Outbound"), + resource.TestCheckResourceAttr(name, "action", "Allow"), + resource.TestCheckResourceAttr(name, "priority", "100"), + resource.TestCheckResourceAttr(name, "source_address_prefix", "101.0.0.0/32"), + resource.TestCheckResourceAttr(name, "source_port_range", "1000"), + resource.TestCheckResourceAttr(name, "destination_address_prefix", "10.0.0.0/32"), + resource.TestCheckResourceAttr(name, "destination_port_range", "1001"), + resource.TestCheckResourceAttr(name, "protocol", "UDP"), + ), + }, + }, + }) +} + +func testAccCheckAzureSecurityGroupRuleExists(name, groupName string) resource.TestCheckFunc { return func(s *terraform.State) error { resource, ok := s.RootModule().Resources[name] if !ok { @@ -48,9 +154,9 @@ func testAccCheckAzureSecurityGroupRuleExists(name string) resource.TestCheckFun secGroupClient := testAccProvider.Meta().(*Client).secGroupClient - secGroup, err := secGroupClient.GetNetworkSecurityGroup(testAccSecurityGroupName) + secGroup, err := secGroupClient.GetNetworkSecurityGroup(groupName) if err != nil { - return fmt.Errorf("Failed getting network security group details: %s", err) + return fmt.Errorf("Failed getting network security group details for %q: %s", groupName, err) } for _, rule := range secGroup.Rules { @@ -63,37 +169,43 @@ func testAccCheckAzureSecurityGroupRuleExists(name string) resource.TestCheckFun } } -func testAccCheckAzureSecurityGroupRuleDeleted(s *terraform.State) error { - for _, resource := range s.RootModule().Resources { - if resource.Type != "azure_security_group_rule" { - continue - } +func testAccCheckAzureSecurityGroupRuleDeleted(groups []string) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, resource := range s.RootModule().Resources { + if resource.Type != "azure_security_group_rule" { + continue + } - if resource.Primary.ID == "" { - return fmt.Errorf("Azure network security group ID not set.") - } + if resource.Primary.ID == "" { + return fmt.Errorf("Azure network security group ID not set.") + } - secGroupClient := testAccProvider.Meta().(*Client).secGroupClient + secGroupClient := testAccProvider.Meta().(*Client).secGroupClient - secGroup, err := secGroupClient.GetNetworkSecurityGroup(testAccSecurityGroupName) - if err != nil { - return fmt.Errorf("Failed getting network security group details: %s", err) - } + for _, groupName := range groups { + secGroup, err := secGroupClient.GetNetworkSecurityGroup(groupName) + if err != nil { + if !management.IsResourceNotFoundError(err) { + return fmt.Errorf("Failed getting network security group details for %q: %s", groupName, err) + } + } - for _, rule := range secGroup.Rules { - if rule.Name == resource.Primary.ID { - return fmt.Errorf("Azure network security group rule still exists!") + for _, rule := range secGroup.Rules { + if rule.Name == resource.Primary.ID { + return fmt.Errorf("Azure network security group rule still exists!") + } + } } } - } - return nil + return nil + } } -var testAccAzureSecurityGroupRule = testAccAzureSecurityGroupConfig + ` +var testAccAzureSecurityGroupRuleBasicConfig = testAccAzureSecurityGroupConfig + ` resource "azure_security_group_rule" "foo" { name = "terraform-secgroup-rule" - security_group_name = "${azure_security_group.foo.name}" + security_group_names = ["${azure_security_group.foo.name}"] type = "Inbound" action = "Deny" priority = 200 @@ -104,3 +216,34 @@ resource "azure_security_group_rule" "foo" { protocol = "TCP" } ` +var testAccAzureSecurityGroupRuleAdvancedConfig = fmt.Sprintf(testAccAzureSecurityGroupConfigTemplate, "foo", testAcctestingSecurityGroup1) + + fmt.Sprintf(testAccAzureSecurityGroupConfigTemplate, "bar", testAcctestingSecurityGroup2) + ` +resource "azure_security_group_rule" "foo" { + name = "terraform-secgroup-rule" + security_group_names = ["${azure_security_group.foo.name}", "${azure_security_group.bar.name}"] + type = "Inbound" + action = "Deny" + priority = 200 + source_address_prefix = "100.0.0.0/32" + source_port_range = "1000" + destination_address_prefix = "10.0.0.0/32" + destination_port_range = "1000" + protocol = "TCP" +} +` + +var testAccAzureSecurityGroupRuleUpdateConfig = fmt.Sprintf(testAccAzureSecurityGroupConfigTemplate, "foo", testAcctestingSecurityGroup1) + + fmt.Sprintf(testAccAzureSecurityGroupConfigTemplate, "bar", testAcctestingSecurityGroup2) + ` +resource "azure_security_group_rule" "foo" { + name = "terraform-secgroup-rule" + security_group_names = ["${azure_security_group.bar.name}"] + type = "Outbound" + action = "Allow" + priority = 100 + source_address_prefix = "101.0.0.0/32" + source_port_range = "1000" + destination_address_prefix = "10.0.0.0/32" + destination_port_range = "1001" + protocol = "UDP" +} +` diff --git a/builtin/providers/azure/resource_azure_security_group_test.go b/builtin/providers/azure/resource_azure_security_group_test.go index 3b35d8731..3d86d0873 100644 --- a/builtin/providers/azure/resource_azure_security_group_test.go +++ b/builtin/providers/azure/resource_azure_security_group_test.go @@ -89,9 +89,14 @@ func testAccCheckAzureSecurityGroupDestroy(s *terraform.State) error { return nil } -var testAccAzureSecurityGroupConfig = fmt.Sprintf(` -resource "azure_security_group" "foo" { +const testAccAzureSecurityGroupConfigTemplate = ` +resource "azure_security_group" "%s" { name = "%s" location = "West US" label = "terraform testing security group" -}`, testAccSecurityGroupName) +}` + +var testAccAzureSecurityGroupConfig = fmt.Sprintf( + testAccAzureSecurityGroupConfigTemplate, + "foo", "terraform-security-group", +) diff --git a/builtin/providers/azure/resource_azure_virtual_network_test.go b/builtin/providers/azure/resource_azure_virtual_network_test.go index bb6b6c563..f6d637f16 100644 --- a/builtin/providers/azure/resource_azure_virtual_network_test.go +++ b/builtin/providers/azure/resource_azure_virtual_network_test.go @@ -218,7 +218,7 @@ resource "azure_security_group" "foo" { resource "azure_security_group_rule" "foo" { name = "terraform-secgroup-rule" - security_group_name = "${azure_security_group.foo.name}" + security_group_names = ["${azure_security_group.foo.name}"] type = "Inbound" action = "Deny" priority = 200 @@ -249,7 +249,7 @@ resource "azure_security_group" "foo" { resource "azure_security_group_rule" "foo" { name = "terraform-secgroup-rule" - security_group_name = "${azure_security_group.foo.name}" + security_group_names = ["${azure_security_group.foo.name}"] type = "Inbound" action = "Deny" priority = 200 diff --git a/website/source/docs/providers/azure/r/security_group_rule.html.markdown b/website/source/docs/providers/azure/r/security_group_rule.html.markdown index 004d73eb5..02df5408c 100644 --- a/website/source/docs/providers/azure/r/security_group_rule.html.markdown +++ b/website/source/docs/providers/azure/r/security_group_rule.html.markdown @@ -17,9 +17,13 @@ resource "azure_security_group" "web" { ... } +resource "azure_security_group" "apps" { + ... +} + resource "azure_security_group_rule" "ssh_access" { name = "ssh-access-rule" - security_group_name = "${azure_security_group.web.name}" + security_group_names = ["${azure_security_group.web.name}", "${azure_security_group.apps.name}"] type = "Inbound" action = "Allow" priority = 200 @@ -34,10 +38,11 @@ resource "azure_security_group_rule" "ssh_access" { ## Argument Reference The following arguments are supported: -* `name` - (Required) The name of the security group the rule should be - applied to. +* `name` - (Required) The name of the security group rule. -* `security_group_name` - (Required) The name of the security group m +* `security_group_names` - (Required) A list of the names of the security groups + the rule should be applied to. + Changing this list forces the creation of a new resource. * `type` - (Required) The type of the security rule. Valid options are: `Inbound` and `Outbound`.