Merge pull request #2530 from aznashwan/f-azure-database-firewall

provider/azure: Added SQL Database Server Firewall Rule resource.
This commit is contained in:
Paul Hinze 2015-06-29 13:43:38 -05:00
commit 9ef25fa022
8 changed files with 579 additions and 19 deletions

View File

@ -36,6 +36,7 @@ func Provider() terraform.ResourceProvider {
"azure_affinity_group": resourceAzureAffinityGroup(),
"azure_data_disk": resourceAzureDataDisk(),
"azure_sql_database_server": resourceAzureSqlDatabaseServer(),
"azure_sql_database_server_firewall_rule": resourceAzureSqlDatabaseServerFirewallRule(),
"azure_sql_database_service": resourceAzureSqlDatabaseService(),
"azure_hosted_service": resourceAzureHostedService(),
"azure_storage_service": resourceAzureStorageService(),

View File

@ -220,9 +220,9 @@ func resourceAzureSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface
// 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:
// note the fact that this rule still applies to this security group:
found = true
remaining.Add("secGroupName")
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)
@ -237,6 +237,8 @@ func resourceAzureSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface
if err != nil {
return fmt.Errorf("Error updating Azure network security group rule for security group %q: %s", secGroupName, err)
}
break
}
}
}
@ -267,7 +269,6 @@ func resourceAzureSecurityGroupRuleDelete(d *schema.ResourceData, meta interface
// 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) {

View File

@ -0,0 +1,222 @@
package azure
import (
"fmt"
"log"
"strings"
"github.com/Azure/azure-sdk-for-go/management/sql"
"github.com/hashicorp/terraform/helper/schema"
)
// resourceAzureSqlDatabaseServerFirewallRule returns the *schema.Resource
// associated to a firewall rule of a database server in Azure.
func resourceAzureSqlDatabaseServerFirewallRule() *schema.Resource {
return &schema.Resource{
Create: resourceAzureSqlDatabaseServerFirewallRuleCreate,
Read: resourceAzureSqlDatabaseServerFirewallRuleRead,
Update: resourceAzureSqlDatabaseServerFirewallRuleUpdate,
Delete: resourceAzureSqlDatabaseServerFirewallRuleDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"database_server_names": &schema.Schema{
Type: schema.TypeSet,
Required: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Set: schema.HashString,
},
"start_ip": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"end_ip": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
},
}
}
// resourceAzureSqlDatabaseServerFirewallRuleCreate does all the necessary API
// calls to create the SQL Database Server Firewall Rule on Azure.
func resourceAzureSqlDatabaseServerFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error {
sqlClient := meta.(*Client).sqlClient
name := d.Get("name").(string)
params := sql.FirewallRuleCreateParams{
Name: name,
StartIPAddress: d.Get("start_ip").(string),
EndIPAddress: d.Get("end_ip").(string),
}
// loop over all the database servers and apply the firewall rule to each:
serverNames := d.Get("database_server_names").(*schema.Set).List()
for _, srv := range serverNames {
serverName := srv.(string)
log.Printf("[INFO] Sending Azure Database Server Firewall Rule %q creation request for Server %q.", name, serverName)
if err := sqlClient.CreateFirewallRule(serverName, params); err != nil {
return fmt.Errorf("Error creating Azure Database Server Firewall Rule %q for Server %q: %s", name, serverName, err)
}
}
d.SetId(name)
return nil
}
// resourceAzureSqlDatabaseServerFirewallRuleRead does all the necessary API
// calls to read the state of the SQL Database Server Firewall Rule on Azure.
func resourceAzureSqlDatabaseServerFirewallRuleRead(d *schema.ResourceData, meta interface{}) error {
sqlClient := meta.(*Client).sqlClient
name := d.Get("name").(string)
remaining := schema.NewSet(schema.HashString, nil)
// for each of our servers; check to see if the rule is still present:
var found bool
for _, srv := range d.Get("database_server_names").(*schema.Set).List() {
serverName := srv.(string)
log.Printf("[INFO] Sending Azure Database Server Firewall Rule list query for server %q.", serverName)
rules, err := sqlClient.ListFirewallRules(serverName)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
// it means that the database server this rule belonged to has
// been deleted in the meantime.
continue
} else {
return fmt.Errorf("Error getting Azure Firewall Rules for Database Server %q: %s", serverName, err)
}
}
// look for our rule:
for _, rule := range rules.FirewallRules {
if rule.Name == name {
found = true
remaining.Add(serverName)
break
}
}
}
// check to see if there is still any Database Server still having this rule:
if !found {
d.SetId("")
return nil
}
// else; update the list of Database Servers still having this rule:
d.Set("database_server_names", remaining)
return nil
}
// resourceAzureSqlDatabaseServerFirewallRuleUpdate does all the necessary API
// calls to update the state of the SQL Database Server Firewall Rule on Azure.
func resourceAzureSqlDatabaseServerFirewallRuleUpdate(d *schema.ResourceData, meta interface{}) error {
sqlClient := meta.(*Client).sqlClient
var found bool
name := d.Get("name").(string)
updateParams := sql.FirewallRuleUpdateParams{
Name: name,
StartIPAddress: d.Get("start_ip").(string),
EndIPAddress: d.Get("end_ip").(string),
}
// for each of the Database Servers our rules concerns; issue the update:
remaining := schema.NewSet(schema.HashString, nil)
for _, srv := range d.Get("database_server_names").(*schema.Set).List() {
serverName := srv.(string)
log.Printf("[INFO] Issuing Azure Database Server Firewall Rule list for Database Server %q.", name, serverName)
rules, err := sqlClient.ListFirewallRules(serverName)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
// it means that the database server this rule belonged to has
// been deleted in the meantime.
continue
} else {
return fmt.Errorf("Error getting Azure Firewall Rules for Database Server %q: %s", serverName, err)
}
}
// look for our rule:
for _, rule := range rules.FirewallRules {
if rule.Name == name {
// take note of the fact that this Database Server still has
// this rule:
found = true
remaining.Add(serverName)
// go ahead and update the rule:
log.Printf("[INFO] Issuing update of Azure Database Server Firewall Rule %q in Server %q.", name, serverName)
if err := sqlClient.UpdateFirewallRule(serverName, name, updateParams); err != nil {
return fmt.Errorf("Error updating Azure Database Server Firewall Rule %q for Server %q: %s", name, serverName, err)
}
break
}
}
}
// check to see if the rule is still exists on any of the servers:
if !found {
d.SetId("")
return nil
}
// else; update the list with the remaining Servers:
d.Set("database_server_names", remaining)
return nil
}
// resourceAzureSqlDatabaseServerFirewallRuleDelete does all the necessary API
// calls to delete the SQL Database Server Firewall Rule on Azure.
func resourceAzureSqlDatabaseServerFirewallRuleDelete(d *schema.ResourceData, meta interface{}) error {
sqlClient := meta.(*Client).sqlClient
name := d.Get("name").(string)
for _, srv := range d.Get("database_server_names").(*schema.Set).List() {
serverName := srv.(string)
log.Printf("[INFO] Sending Azure Database Server Firewall Rule list query for Server %q.", serverName)
rules, err := sqlClient.ListFirewallRules(serverName)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
// it means that the database server this rule belonged to has
// been deleted in the meantime.
continue
} else {
return fmt.Errorf("Error getting Azure Firewall Rules for Database Server %q: %s", serverName, err)
}
}
// look for our rule:
for _, rule := range rules.FirewallRules {
if rule.Name == name {
// go ahead and delete the rule:
log.Printf("[INFO] Issuing deletion of Azure Database Server Firewall Rule %q in Server %q.", name, serverName)
if err := sqlClient.DeleteFirewallRule(serverName, name); err != nil {
return fmt.Errorf("Error deleting Azure Database Server Firewall Rule %q for Server %q: %s", name, serverName, err)
}
break
}
}
}
return nil
}

View File

@ -0,0 +1,235 @@
package azure
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAzureSqlDatabaseServerFirewallRuleBasic(t *testing.T) {
name := "azure_sql_database_server_firewall_rule.foo"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccAzureDatabaseServerFirewallRuleDeleted(testAccAzureSqlServerNames),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAzureDatabaseServerFirewallRuleBasicConfig,
Check: resource.ComposeTestCheckFunc(
testAccAzureSqlDatabaseServerGetNames,
testAccAzureSqlDatabaseServersNumber(1),
testAccAzureDatabaseServerFirewallRuleExists(name, testAccAzureSqlServerNames),
resource.TestCheckResourceAttr(name, "name", "terraform-testing-rule"),
resource.TestCheckResourceAttr(name, "start_ip", "10.0.0.0"),
resource.TestCheckResourceAttr(name, "end_ip", "10.0.0.255"),
),
},
},
})
}
func TestAccAzureSqlDatabaseServerFirewallRuleAdvanced(t *testing.T) {
name1 := "azure_sql_database_server_firewall_rule.foo"
name2 := "azure_sql_database_server_firewall_rule.bar"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccAzureDatabaseServerFirewallRuleDeleted(testAccAzureSqlServerNames),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAzureDatabaseServerFirewallRuleAdvancedConfig,
Check: resource.ComposeTestCheckFunc(
testAccAzureSqlDatabaseServerGetNames,
testAccAzureSqlDatabaseServersNumber(2),
testAccAzureDatabaseServerFirewallRuleExists(name1, testAccAzureSqlServerNames),
resource.TestCheckResourceAttr(name1, "name", "terraform-testing-rule1"),
resource.TestCheckResourceAttr(name1, "start_ip", "10.0.0.0"),
resource.TestCheckResourceAttr(name1, "end_ip", "10.0.0.255"),
testAccAzureDatabaseServerFirewallRuleExists(name2, testAccAzureSqlServerNames),
resource.TestCheckResourceAttr(name2, "name", "terraform-testing-rule2"),
resource.TestCheckResourceAttr(name2, "start_ip", "200.0.0.0"),
resource.TestCheckResourceAttr(name2, "end_ip", "200.255.255.255"),
),
},
},
})
}
func TestAccAzureSqlDatabaseServerFirewallRuleUpdate(t *testing.T) {
name1 := "azure_sql_database_server_firewall_rule.foo"
name2 := "azure_sql_database_server_firewall_rule.bar"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccAzureDatabaseServerFirewallRuleDeleted(testAccAzureSqlServerNames),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAzureDatabaseServerFirewallRuleAdvancedConfig,
Check: resource.ComposeTestCheckFunc(
testAccAzureSqlDatabaseServerGetNames,
testAccAzureSqlDatabaseServersNumber(2),
testAccAzureDatabaseServerFirewallRuleExists(name1, testAccAzureSqlServerNames),
resource.TestCheckResourceAttr(name1, "name", "terraform-testing-rule1"),
resource.TestCheckResourceAttr(name1, "start_ip", "10.0.0.0"),
resource.TestCheckResourceAttr(name1, "end_ip", "10.0.0.255"),
testAccAzureDatabaseServerFirewallRuleExists(name2, testAccAzureSqlServerNames),
resource.TestCheckResourceAttr(name2, "name", "terraform-testing-rule2"),
resource.TestCheckResourceAttr(name2, "start_ip", "200.0.0.0"),
resource.TestCheckResourceAttr(name2, "end_ip", "200.255.255.255"),
),
},
resource.TestStep{
Config: testAccAzureDatabaseServerFirewallRuleUpdateConfig,
Check: resource.ComposeTestCheckFunc(
testAccAzureSqlDatabaseServerGetNames,
testAccAzureSqlDatabaseServersNumber(2),
testAccAzureDatabaseServerFirewallRuleExists(name1, testAccAzureSqlServerNames),
resource.TestCheckResourceAttr(name1, "name", "terraform-testing-rule1"),
resource.TestCheckResourceAttr(name1, "start_ip", "11.0.0.0"),
resource.TestCheckResourceAttr(name1, "end_ip", "11.0.0.255"),
),
},
},
})
}
func testAccAzureDatabaseServerFirewallRuleExists(name string, servers []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
resource, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Azure Database Server Firewall Rule %q doesn't exist.", name)
}
if resource.Primary.ID == "" {
return fmt.Errorf("Azure Database Server Firewall Rule %q resource ID not set.", name)
}
sqlClient := testAccProvider.Meta().(*Client).sqlClient
for _, server := range servers {
rules, err := sqlClient.ListFirewallRules(server)
if err != nil {
return fmt.Errorf("Error listing Azure Database Server Firewall Rules for Server %q: %s", server, err)
}
var found bool
for _, rule := range rules.FirewallRules {
if rule.Name == resource.Primary.ID {
found = true
break
}
}
if !found {
return fmt.Errorf("Azure Database Server Firewall Rule %q doesn't exists on server %q.", resource.Primary.ID, server)
}
}
return nil
}
}
func testAccAzureDatabaseServerFirewallRuleDeleted(servers []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, resource := range s.RootModule().Resources {
if resource.Type != "azure_sql_database_server_firewall_rule" {
continue
}
if resource.Primary.ID == "" {
return fmt.Errorf("Azure Database Server Firewall Rule resource ID not set.")
}
sqlClient := testAccProvider.Meta().(*Client).sqlClient
for _, server := range servers {
rules, err := sqlClient.ListFirewallRules(server)
if err != nil {
return fmt.Errorf("Error listing Azure Database Server Firewall Rules for Server %q: %s", server, err)
}
for _, rule := range rules.FirewallRules {
if rule.Name == resource.Primary.ID {
return fmt.Errorf("Azure Database Server Firewall Rule %q still exists on Server %q.", resource.Primary.ID, err)
}
}
}
}
return nil
}
}
var testAccAzureDatabaseServerFirewallRuleBasicConfig = `
resource "azure_sql_database_server" "foo" {
location = "West US"
username = "SuperUser"
password = "SuperSEKR3T"
version = "2.0"
}
resource "azure_sql_database_server_firewall_rule" "foo" {
name = "terraform-testing-rule"
depends_on = ["azure_sql_database_server.foo"]
start_ip = "10.0.0.0"
end_ip = "10.0.0.255"
database_server_names = ["${azure_sql_database_server.foo.name}"]
}
`
var testAccAzureDatabaseServerFirewallRuleAdvancedConfig = `
resource "azure_sql_database_server" "foo" {
location = "West US"
username = "SuperUser"
password = "SuperSEKR3T"
version = "2.0"
}
resource "azure_sql_database_server" "bar" {
location = "West US"
username = "SuperUser"
password = "SuperSEKR3T"
version = "2.0"
}
resource "azure_sql_database_server_firewall_rule" "foo" {
name = "terraform-testing-rule1"
start_ip = "10.0.0.0"
end_ip = "10.0.0.255"
database_server_names = ["${azure_sql_database_server.foo.name}", "${azure_sql_database_server.bar.name}"]
}
resource "azure_sql_database_server_firewall_rule" "bar" {
name = "terraform-testing-rule2"
start_ip = "200.0.0.0"
end_ip = "200.255.255.255"
database_server_names = ["${azure_sql_database_server.foo.name}", "${azure_sql_database_server.bar.name}"]
}
`
var testAccAzureDatabaseServerFirewallRuleUpdateConfig = `
resource "azure_sql_database_server" "foo" {
location = "West US"
username = "SuperUser"
password = "SuperSEKR3T"
version = "2.0"
}
resource "azure_sql_database_server" "bar" {
location = "West US"
username = "SuperUser"
password = "SuperSEKR3T"
version = "2.0"
}
resource "azure_sql_database_server_firewall_rule" "foo" {
name = "terraform-testing-rule1"
start_ip = "11.0.0.0"
end_ip = "11.0.0.255"
database_server_names = ["${azure_sql_database_server.foo.name}"]
}
`

View File

@ -12,6 +12,7 @@ import (
// the randomly-generated name of the SQL Server after it is created.
// The anonymous function is there because go is too good to &"" directly.
var testAccAzureSqlServerName *string = func(s string) *string { return &s }("")
var testAccAzureSqlServerNames []string = []string{}
func TestAccAzureSqlDatabaseServer(t *testing.T) {
name := "azure_sql_database_server.foo"
@ -109,6 +110,44 @@ func testAccAzureSqlDatabaseServerGetName(s *terraform.State) error {
return fmt.Errorf("No Azure SQL Servers found.")
}
// testAccAzureSqlDatabaseServerGetNames is the same as the above; only it gets
// all the servers' names.
func testAccAzureSqlDatabaseServerGetNames(s *terraform.State) error {
testAccAzureSqlServerNames = []string{}
for _, resource := range s.RootModule().Resources {
if resource.Type != "azure_sql_database_server" {
continue
}
if resource.Primary.ID == "" {
return fmt.Errorf("Azure SQL Server resource ID not set.")
}
testAccAzureSqlServerNames = append(testAccAzureSqlServerNames, resource.Primary.ID)
}
if len(testAccAzureSqlServerNames) == 0 {
return fmt.Errorf("No Azure SQL Servers found.")
}
return nil
}
// testAccAzureSqlDatabaseServersNumber checks if the numbers of servers is
// exactly equal to the given number. It is modeled as a resource.TestCheckFunc
// to be easily embeddable in test checks.
func testAccAzureSqlDatabaseServersNumber(n int) resource.TestCheckFunc {
return func(_ *terraform.State) error {
if len(testAccAzureSqlServerNames) != n {
return fmt.Errorf("Erroneous number of Azure Sql Database Servers. Expected %d; have %d.", n,
len(testAccAzureSqlServerNames))
}
return nil
}
}
const testAccAzureSqlDatabaseServerConfig = `
resource "azure_sql_database_server" "foo" {
location = "West US"

View File

@ -135,7 +135,7 @@ func testAccCheckAzureSqlDatabaseServiceExists(name string) resource.TestCheckFu
func testAccCheckAzureSqlDatabaseServiceDeleted(s *terraform.State) error {
for _, resource := range s.RootModule().Resources {
if resource.Type != "azure_sql_database_server" {
if resource.Type != "azure_sql_database_service" {
continue
}
@ -155,6 +155,7 @@ func testAccCheckAzureSqlDatabaseServiceDeleted(s *terraform.State) error {
}
}
}
return nil
}

View File

@ -0,0 +1,57 @@
---
layout: "azure"
page_title: "Azure: azure_sql_database_server_firewall_rule"
sidebar_current: "docs-azure-sql-database-server-firewall-rule"
description: |-
Defines a new Firewall Rule to be applied across the given Database Servers.
---
# azure\_sql\_database\_server
Defines a new Firewall Rule to be applied across the given Database Servers.
## Example Usage
```
resource "azure_sql_database_server" "sql-serv1" {
...
}
resource "azure_sql_database_server" "sql-serv2" {
...
}
resource "azure_sql_database_server_firewall_rule" "constraint" {
name = "terraform-testing-rule"
start_ip = "154.0.0.0"
end_ip = "154.0.0.255"
database_server_names = [
"${azure_sql_database_server.sql-serv1.name}",
"${azure_sql_database_server.sql-serv2.name}",
]
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) The name of the rule. Changing forces the creation of a
new resource.
* `start_ip` - (Required) The IPv4 which will represent the lower bound of the
rule's application IP's. Traffic to/from IP's greater than or equal to this
one up to the `end_ip` will be permitted.
* `end_ip` - (Required) The IPv4 which will represent the upper bound of the
rule's application IP's. Traffic to/from IP's lesser that or equal to this
one all the way down to the `start_ip` will be permitted.
* `database_server_names` - (Required) The set of names of the Azure SQL
Database servers the rule should be enforced on.
## Attributes Reference
The following attributes are exported:
* `id` - The database server ID. Coincides with the given `name`.

View File

@ -49,6 +49,10 @@
<a href="/docs/providers/azure/r/sql_database_server.html">azure_sql_database_server</a>
</li>
<li<%= sidebar_current("docs-azure-resource-sql-database-server-firewall-rule") %>>
<a href="/docs/providers/azure/r/sql_database_server_firewall_rule.html">azure_sql_database_server_firewall_rule</a>
</li>
<li<%= sidebar_current("docs-azure-resource-sql-database-service") %>>
<a href="/docs/providers/azure/r/sql_database_service.html">azure_sql_database_service</a>
</li>