-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Resource:
azurerm_sql_virtual_network_rule
(#978)
* Added SQL Vnet Rule * Initial working implemtation of arm_sql_virtual_network_rule * Added initial virtual network rule test. * Fixed SQL test cases for SQL Vnet rule. * Fixed SQL Virtual Network Rule tests to run correctly. * Added additional test cases and expected output for SQL Vnet rule endpoint cases * Added Import Test for SQL Vnet Rule. * Added additional test case for provisioning multiple SQL vnet rules * Fixed formatting and comments in vnet sql rule tests. * Updated config entry to new registration syntax * Updated subnet variable name to match other resources * Added SQL vnet rule name validation and tests * Added additional error handling to the SQL vnet rule delete functions. * Added nil check for response properties to SQL vnet rule. * Reordered SQL vnet rule name validation for error message clarity * Added SQL vnet rule test for switching subnets * Added additional validation function acceptance test for SQL vnet rule * Fixed SQL Vnet Rule test case and validation logic. Added more consistency with comments. * Added initial rough draft of documentation * Added SQL vnet rule endpoint_state as a computed field * Revised part of the SQL vnet rule documentation. * Added check/wait status on create or update of a SQL virtual network rule. Added consistency to error messages. * Increased SQL Vnet Rule Create method's ContinuousTargetOccurence property to 5. * Removing the `endpoint_state` field
- Loading branch information
1 parent
4cda1c3
commit 8446bb3
Showing
7 changed files
with
1,136 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package azurerm | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestAccAzureRMSqlVirtualNetworkRule_importBasic(t *testing.T) { | ||
resourceName := "azurerm_sql_virtual_network_rule.test" | ||
|
||
ri := acctest.RandInt() | ||
config := testAccAzureRMSqlVirtualNetworkRule_basic(ri, testLocation()) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testCheckAzureRMSqlVirtualNetworkRuleDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: config, | ||
}, | ||
{ | ||
ResourceName: resourceName, | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
package azurerm | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"regexp" | ||
"time" | ||
|
||
"github.com/Azure/azure-sdk-for-go/services/sql/mgmt/2015-05-01-preview/sql" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" | ||
) | ||
|
||
func resourceArmSqlVirtualNetworkRule() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceArmSqlVirtualNetworkRuleCreateUpdate, | ||
Read: resourceArmSqlVirtualNetworkRuleRead, | ||
Update: resourceArmSqlVirtualNetworkRuleCreateUpdate, | ||
Delete: resourceArmSqlVirtualNetworkRuleDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validateSqlVirtualNetworkRuleName, | ||
}, | ||
|
||
"resource_group_name": resourceGroupNameSchema(), | ||
|
||
"server_name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"subnet_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
|
||
"ignore_missing_vnet_service_endpoint": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Default: false, //When not provided, Azure defaults to false | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceArmSqlVirtualNetworkRuleCreateUpdate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).sqlVirtualNetworkRulesClient | ||
ctx := meta.(*ArmClient).StopContext | ||
|
||
name := d.Get("name").(string) | ||
serverName := d.Get("server_name").(string) | ||
resourceGroup := d.Get("resource_group_name").(string) | ||
virtualNetworkSubnetId := d.Get("subnet_id").(string) | ||
ignoreMissingVnetServiceEndpoint := d.Get("ignore_missing_vnet_service_endpoint").(bool) | ||
|
||
parameters := sql.VirtualNetworkRule{ | ||
VirtualNetworkRuleProperties: &sql.VirtualNetworkRuleProperties{ | ||
VirtualNetworkSubnetID: utils.String(virtualNetworkSubnetId), | ||
IgnoreMissingVnetServiceEndpoint: utils.Bool(ignoreMissingVnetServiceEndpoint), | ||
}, | ||
} | ||
|
||
_, err := client.CreateOrUpdate(ctx, resourceGroup, serverName, name, parameters) | ||
if err != nil { | ||
return fmt.Errorf("Error creating SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
//Wait for the provisioning state to become ready | ||
log.Printf("[DEBUG] Waiting for SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q) to become ready: %+v", name, serverName, resourceGroup, err) | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{"Initializing", "InProgress", "Unknown", "ResponseNotFound"}, | ||
Target: []string{"Ready"}, | ||
Refresh: sqlVirtualNetworkStateStatusCodeRefreshFunc(ctx, client, resourceGroup, serverName, name), | ||
Timeout: 10 * time.Minute, | ||
MinTimeout: 1 * time.Minute, | ||
ContinuousTargetOccurence: 5, | ||
} | ||
|
||
if _, err := stateConf.WaitForState(); err != nil { | ||
return fmt.Errorf("Error waiting for SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q) to be created or updated: %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
resp, err := client.Get(ctx, resourceGroup, serverName, name) | ||
if err != nil { | ||
return fmt.Errorf("Error retrieving SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
d.SetId(*resp.ID) | ||
|
||
return resourceArmSqlVirtualNetworkRuleRead(d, meta) | ||
} | ||
|
||
func resourceArmSqlVirtualNetworkRuleRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).sqlVirtualNetworkRulesClient | ||
ctx := meta.(*ArmClient).StopContext | ||
|
||
id, err := parseAzureResourceID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resourceGroup := id.ResourceGroup | ||
serverName := id.Path["servers"] | ||
name := id.Path["virtualNetworkRules"] | ||
|
||
resp, err := client.Get(ctx, resourceGroup, serverName, name) | ||
if err != nil { | ||
if utils.ResponseWasNotFound(resp.Response) { | ||
log.Printf("[INFO] Error reading SQL Virtual Network Rule %q - removing from state", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("Error reading SQL Virtual Network Rule: %q (SQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
d.Set("name", resp.Name) | ||
d.Set("resource_group_name", resourceGroup) | ||
d.Set("server_name", serverName) | ||
|
||
if props := resp.VirtualNetworkRuleProperties; props != nil { | ||
d.Set("subnet_id", props.VirtualNetworkSubnetID) | ||
d.Set("ignore_missing_vnet_service_endpoint", props.IgnoreMissingVnetServiceEndpoint) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceArmSqlVirtualNetworkRuleDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).sqlVirtualNetworkRulesClient | ||
ctx := meta.(*ArmClient).StopContext | ||
|
||
id, err := parseAzureResourceID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resourceGroup := id.ResourceGroup | ||
serverName := id.Path["servers"] | ||
name := id.Path["virtualNetworkRules"] | ||
|
||
future, err := client.Delete(ctx, resourceGroup, serverName, name) | ||
if err != nil { | ||
if response.WasNotFound(future.Response()) { | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("Error deleting SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
err = future.WaitForCompletion(ctx, client.Client) | ||
if err != nil { | ||
if response.WasNotFound(future.Response()) { | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("Error deleting SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
/* | ||
This function checks the format of the SQL Virtual Network Rule Name to make sure that | ||
it does not contain any potentially invalid values. | ||
*/ | ||
func validateSqlVirtualNetworkRuleName(v interface{}, k string) (ws []string, errors []error) { | ||
value := v.(string) | ||
|
||
// Cannot be empty | ||
if len(value) == 0 { | ||
errors = append(errors, fmt.Errorf( | ||
"%q cannot be an empty string: %q", k, value)) | ||
} | ||
|
||
// Cannot be more than 128 characters | ||
if len(value) > 128 { | ||
errors = append(errors, fmt.Errorf( | ||
"%q cannot be longer than 128 characters: %q", k, value)) | ||
} | ||
|
||
// Must only contain alphanumeric characters or hyphens | ||
if !regexp.MustCompile(`^[A-Za-z0-9-]*$`).MatchString(value) { | ||
errors = append(errors, fmt.Errorf( | ||
"%q can only contain alphanumeric characters and hyphens: %q", | ||
k, value)) | ||
} | ||
|
||
// Cannot end in a hyphen | ||
if regexp.MustCompile(`-$`).MatchString(value) { | ||
errors = append(errors, fmt.Errorf( | ||
"%q cannot end with a hyphen: %q", k, value)) | ||
} | ||
|
||
// Cannot start with a number or hyphen | ||
if regexp.MustCompile(`^[0-9-]`).MatchString(value) { | ||
errors = append(errors, fmt.Errorf( | ||
"%q cannot start with a number or hyphen: %q", k, value)) | ||
} | ||
|
||
// There are multiple returns in the case that there is more than one invalid | ||
// case applied to the name. | ||
return | ||
} | ||
|
||
/* | ||
This function refreshes and checks the state of the SQL Virtual Network Rule. | ||
Response will contain a VirtualNetworkRuleProperties struct with a State property. The state property contain one of the following states (except ResponseNotFound). | ||
* Deleting | ||
* Initializing | ||
* InProgress | ||
* Unknown | ||
* Ready | ||
* ResponseNotFound (Custom state in case of 404) | ||
*/ | ||
func sqlVirtualNetworkStateStatusCodeRefreshFunc(ctx context.Context, client sql.VirtualNetworkRulesClient, resourceGroup string, serverName string, name string) resource.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
resp, err := client.Get(ctx, resourceGroup, serverName, name) | ||
|
||
if err != nil { | ||
if utils.ResponseWasNotFound(resp.Response) { | ||
log.Printf("[DEBUG] Retrieving SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q) returned 404.", resourceGroup, serverName, name) | ||
return nil, "ResponseNotFound", nil | ||
} | ||
|
||
return nil, "", fmt.Errorf("Error polling for the state of the SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
if props := resp.VirtualNetworkRuleProperties; props != nil { | ||
log.Printf("[DEBUG] Retrieving SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q) returned Status %s", resourceGroup, serverName, name, props.State) | ||
return resp, fmt.Sprintf("%s", props.State), nil | ||
} | ||
|
||
//Valid response was returned but VirtualNetworkRuleProperties was nil. Basically the rule exists, but with no properties for some reason. Assume Unknown instead of returning error. | ||
log.Printf("[DEBUG] Retrieving SQL Virtual Network Rule %q (SQL Server: %q, Resource Group: %q) returned empty VirtualNetworkRuleProperties", resourceGroup, serverName, name) | ||
return resp, "Unknown", nil | ||
} | ||
} |
Oops, something went wrong.