Skip to content

Commit

Permalink
mssql: add resources azurerm_mssql_firewall_rule and azurerm_mssql_vi…
Browse files Browse the repository at this point in the history
…rtual_network_rule (#10954)

Co-authored-by: jackofallops <[email protected]>
  • Loading branch information
manicminer and jackofallops authored Mar 18, 2021
1 parent fef9a42 commit d304731
Show file tree
Hide file tree
Showing 20 changed files with 1,761 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .teamcity/components/generated/services.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var services = mapOf(
"maps" to "Maps",
"mariadb" to "MariaDB",
"media" to "Media",
"mssql" to "Microsoft SQL Server / SQL Azure",
"mssql" to "Microsoft SQL Server / Azure SQL",
"mixedreality" to "Mixed Reality",
"monitor" to "Monitor",
"mysql" to "MySQL",
Expand Down
19 changes: 15 additions & 4 deletions azurerm/internal/services/mssql/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@ package client
import (
"github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v3.0/sql"
"github.com/Azure/azure-sdk-for-go/services/preview/sqlvirtualmachine/mgmt/2017-03-01-preview/sqlvirtualmachine"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common"
)

type Client struct {
BackupLongTermRetentionPoliciesClient *sql.BackupLongTermRetentionPoliciesClient
BackupShortTermRetentionPoliciesClient *sql.BackupShortTermRetentionPoliciesClient
DatabasesClient *sql.DatabasesClient
DatabaseExtendedBlobAuditingPoliciesClient *sql.ExtendedDatabaseBlobAuditingPoliciesClient
DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient
ElasticPoolsClient *sql.ElasticPoolsClient
DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient
DatabasesClient *sql.DatabasesClient
ElasticPoolsClient *sql.ElasticPoolsClient
FirewallRulesClient *sql.FirewallRulesClient
RestorableDroppedDatabasesClient *sql.RestorableDroppedDatabasesClient
ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient
ServersClient *sql.ServersClient
ServerExtendedBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient
ServerConnectionPoliciesClient *sql.ServerConnectionPoliciesClient
ServerExtendedBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient
ServerSecurityAlertPoliciesClient *sql.ServerSecurityAlertPoliciesClient
ServerVulnerabilityAssessmentsClient *sql.ServerVulnerabilityAssessmentsClient
ServersClient *sql.ServersClient
VirtualMachinesClient *sqlvirtualmachine.SQLVirtualMachinesClient
VirtualNetworkRulesClient *sql.VirtualNetworkRulesClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand All @@ -46,6 +49,9 @@ func NewClient(o *common.ClientOptions) *Client {
elasticPoolsClient := sql.NewElasticPoolsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&elasticPoolsClient.Client, o.ResourceManagerAuthorizer)

firewallRulesClient := sql.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&firewallRulesClient.Client, o.ResourceManagerAuthorizer)

restorableDroppedDatabasesClient := sql.NewRestorableDroppedDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&restorableDroppedDatabasesClient.Client, o.ResourceManagerAuthorizer)

Expand All @@ -70,6 +76,9 @@ func NewClient(o *common.ClientOptions) *Client {
sqlVirtualMachinesClient := sqlvirtualmachine.NewSQLVirtualMachinesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&sqlVirtualMachinesClient.Client, o.ResourceManagerAuthorizer)

sqlVirtualNetworkRulesClient := sql.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&sqlVirtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer)

return &Client{
BackupLongTermRetentionPoliciesClient: &BackupLongTermRetentionPoliciesClient,
BackupShortTermRetentionPoliciesClient: &BackupShortTermRetentionPoliciesClient,
Expand All @@ -78,6 +87,7 @@ func NewClient(o *common.ClientOptions) *Client {
DatabaseThreatDetectionPoliciesClient: &databaseThreatDetectionPoliciesClient,
DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient,
ElasticPoolsClient: &elasticPoolsClient,
FirewallRulesClient: &firewallRulesClient,
RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient,
ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient,
ServersClient: &serversClient,
Expand All @@ -86,5 +96,6 @@ func NewClient(o *common.ClientOptions) *Client {
ServerSecurityAlertPoliciesClient: &serverSecurityAlertPoliciesClient,
ServerVulnerabilityAssessmentsClient: &serverVulnerabilityAssessmentsClient,
VirtualMachinesClient: &sqlVirtualMachinesClient,
VirtualNetworkRulesClient: &sqlVirtualNetworkRulesClient,
}
}
165 changes: 165 additions & 0 deletions azurerm/internal/services/mssql/mssql_firewall_rule_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package mssql

import (
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v3.0/sql"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/sql/parse"
azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceMsSqlFirewallRule() *schema.Resource {
return &schema.Resource{
Create: resourceMsSqlFirewallRuleCreateUpdate,
Read: resourceMsSqlFirewallRuleRead,
Update: resourceMsSqlFirewallRuleCreateUpdate,
Delete: resourceMsSqlFirewallRuleDelete,

Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error {
_, err := parse.FirewallRuleID(id)
return err
}),

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Minute),
Read: schema.DefaultTimeout(5 * time.Minute),
Update: schema.DefaultTimeout(30 * time.Minute),
Delete: schema.DefaultTimeout(30 * time.Minute),
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"server_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.ServerID,
},

"start_ip_address": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.All(
validation.IsIPAddress,
validation.StringIsNotEmpty,
),
},

"end_ip_address": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.All(
validation.IsIPAddress,
validation.StringIsNotEmpty,
),
},
},
}
}

func resourceMsSqlFirewallRuleCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).MSSQL.FirewallRulesClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

serverId, err := parse.ServerID(d.Get("server_id").(string))
if err != nil {
return fmt.Errorf("parsing server ID %q: %+v", d.Get("server_id"), err)
}

id := parse.NewFirewallRuleID(serverId.SubscriptionId, serverId.ResourceGroup, serverId.Name, d.Get("name").(string))

if d.IsNewResource() {
existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("checking for presence of existing MSSQL %s: %+v", id.String(), err)
}
}

if existing.ID != nil && *existing.ID != "" {
return tf.ImportAsExistsError("azurerm_mssql_firewall_rule", id.ID())
}
}

parameters := sql.FirewallRule{
FirewallRuleProperties: &sql.FirewallRuleProperties{
StartIPAddress: utils.String(d.Get("start_ip_address").(string)),
EndIPAddress: utils.String(d.Get("end_ip_address").(string)),
},
}

if _, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, parameters); err != nil {
return fmt.Errorf("creating MSSQL %s: %+v", id.String(), err)
}

d.SetId(id.ID())

return resourceMsSqlFirewallRuleRead(d, meta)
}

func resourceMsSqlFirewallRuleRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).MSSQL.FirewallRulesClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.FirewallRuleID(d.Id())
if err != nil {
return fmt.Errorf("parsing ID %q: %+v", d.Id(), err)
}

resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[INFO] MSSQL %s was not found - removing from state", id.String())
d.SetId("")
return nil
}

return fmt.Errorf("retrieving MSSQL %s: %+v", id.String(), err)
}

d.Set("name", id.Name)

d.Set("start_ip_address", resp.StartIPAddress)
d.Set("end_ip_address", resp.EndIPAddress)

serverId := parse.NewServerID(id.SubscriptionId, id.ResourceGroup, id.ServerName)
d.Set("server_id", serverId.ID())

return nil
}

func resourceMsSqlFirewallRuleDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).MSSQL.FirewallRulesClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.FirewallRuleID(d.Id())
if err != nil {
return fmt.Errorf("parsing ID %q: %+v", d.Id(), err)
}

resp, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name)
if err != nil {
if !utils.ResponseWasNotFound(resp) {
return fmt.Errorf("deleting MSSQL %s: %+v", id.String(), err)
}
}

return nil
}
147 changes: 147 additions & 0 deletions azurerm/internal/services/mssql/mssql_firewall_rule_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package mssql_test

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

type MsSqlFirewallRuleResource struct{}

func TestAccMsSqlFirewallRule_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_mssql_firewall_rule", "test")
r := MsSqlFirewallRuleResource{}

data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.basic(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccMsSqlFirewallRule_update(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_mssql_firewall_rule", "test")
r := MsSqlFirewallRuleResource{}

data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.basic(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.updated(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccMsSqlFirewallRule_requiresImport(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_mssql_firewall_rule", "test")
r := MsSqlFirewallRuleResource{}

data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.basic(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.RequiresImportErrorStep(r.requiresImport),
})
}

func (r MsSqlFirewallRuleResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) {
id, err := parse.FirewallRuleID(state.ID)
if err != nil {
return nil, err
}

resp, err := client.MSSQL.FirewallRulesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return utils.Bool(false), nil
}
return nil, fmt.Errorf("retrieving MSSQL %s: %+v", id.String(), err)
}

return utils.Bool(true), nil
}

func (MsSqlFirewallRuleResource) template(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-%[1]d"
location = "%[2]s"
}
resource "azurerm_mssql_server" "test" {
name = "acctestsqlserver%[1]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
version = "12.0"
administrator_login = "msincredible"
administrator_login_password = "P@55W0rD!!%[3]s"
}
`, data.RandomInteger, data.Locations.Primary, data.RandomString)
}

func (r MsSqlFirewallRuleResource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
resource "azurerm_mssql_firewall_rule" "test" {
name = "acctestsqlserver%[2]d"
server_id = azurerm_mssql_server.test.id
start_ip_address = "0.0.0.0"
end_ip_address = "255.255.255.255"
}
`, r.template(data), data.RandomInteger)
}

func (r MsSqlFirewallRuleResource) updated(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
resource "azurerm_mssql_firewall_rule" "test" {
name = "acctestsqlserver%[2]d"
server_id = azurerm_mssql_server.test.id
start_ip_address = "10.0.17.62"
end_ip_address = "10.0.17.64"
}
`, r.template(data), data.RandomInteger)
}

func (r MsSqlFirewallRuleResource) requiresImport(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
resource "azurerm_mssql_firewall_rule" "import" {
name = azurerm_mssql_firewall_rule.test.name
server_id = azurerm_mssql_firewall_rule.test.server_id
start_ip_address = azurerm_mssql_firewall_rule.test.start_ip_address
end_ip_address = azurerm_mssql_firewall_rule.test.end_ip_address
}
`, r.basic(data))
}
Loading

0 comments on commit d304731

Please sign in to comment.