-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Resource: azurerm_postgresql_virtual_network_rule
#1774
Merged
tombuildsstuff
merged 20 commits into
hashicorp:master
from
arnoldclark:add_postgresql_vnet_rule
Sep 4, 2018
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
1657d1b
Add the basics of postgresql vnet rule.
ac-astuartkregor 5e640de
Bring across postgresql_server resource from postgresql_server_test.
ac-astuartkregor b0205eb
Add doc page for postgresql_virtual_network_rule.
ac-astuartkregor 2f13ae8
Add import test for postgresql_virtual_network_rule.
ac-astuartkregor 3db91e6
Make postgresql_virtual_network_rule example similar to postgresql_se…
ac-astuartkregor f356130
Fix resource ID for postgresql_virtual_network_rule import docs.
ac-astuartkregor 0ad24c4
Add postgresql_virtual_network_rule to docs sidebar.
ac-astuartkregor a85e3a2
Add a client for postgresqlVirtualNetworkRules.
ac-astuartkregor 692306f
Fix text in anchor for azurerm_postgresql_virtual_network_rule.
ac-astuartkregor 0f333d5
Add non-zero value validation for server_name and subnet_id.
ac-astuartkregor be87178
(postgresql_virtual_network_rule) Adjust positioning of advice around…
ac-astuartkregor 19d52a9
Remove currently unused import for postgresql_virtual_network_rule.
ac-astuartkregor 2eb65c1
Fix validator function names for postgresql_virtual_network_rule.
ac-astuartkregor 81aeb01
postgresql_virtual_network_rule Use Azure resource ID validator for s…
ac-astuartkregor f0ebf93
postgresql_vnet_rule Acceptance tests mostly working, ignore missing …
ac-astuartkregor 7c91f83
postgresql vnet rule - skip failing test because of API issue.
ac-astuartkregor f830ec8
postgresql vnet rule remove ignore_missing_vnet_service_endpoint test.
ac-astuartkregor e32e5c5
Postgresql vnet rule - remove `ignore_missing_vnet_service_endpoint` …
ac-astuartkregor caf3cdb
postgresql vnet rule - default `IgnoreMissingVnetServiceEndpoint` to …
ac-astuartkregor 0b0b3dd
Checking to ensure the Subnet's configured correctly so the Virtual N…
tombuildsstuff File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
31 changes: 31 additions & 0 deletions
31
azurerm/import_arm_postgresql_virtual_network_rule_test.go
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 TestAccAzureRMPostgreSQLVirtualNetworkRule_importBasic(t *testing.T) { | ||
resourceName := "azurerm_postgresql_virtual_network_rule.test" | ||
|
||
ri := acctest.RandInt() | ||
config := testAccAzureRMPostgreSQLVirtualNetworkRule_basic(ri, testLocation()) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testCheckAzureRMPostgreSQLVirtualNetworkRuleDestroy, | ||
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
284 changes: 284 additions & 0 deletions
284
azurerm/resource_arm_postgresql_virtual_network_rule.go
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,284 @@ | ||
package azurerm | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"regexp" | ||
"strings" | ||
"time" | ||
|
||
"github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/helper/validation" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" | ||
) | ||
|
||
func resourceArmPostgreSQLVirtualNetworkRule() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceArmPostgreSQLVirtualNetworkRuleCreateUpdate, | ||
Read: resourceArmPostgreSQLVirtualNetworkRuleRead, | ||
Update: resourceArmPostgreSQLVirtualNetworkRuleCreateUpdate, | ||
Delete: resourceArmPostgreSQLVirtualNetworkRuleDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validatePostgreSQLVirtualNetworkRuleName, | ||
}, | ||
|
||
"resource_group_name": resourceGroupNameSchema(), | ||
|
||
"server_name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validation.NoZeroValues, | ||
}, | ||
|
||
"subnet_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ValidateFunc: azure.ValidateResourceID, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceArmPostgreSQLVirtualNetworkRuleCreateUpdate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).postgresqlVirtualNetworkRulesClient | ||
ctx := meta.(*ArmClient).StopContext | ||
|
||
name := d.Get("name").(string) | ||
serverName := d.Get("server_name").(string) | ||
resourceGroup := d.Get("resource_group_name").(string) | ||
subnetId := d.Get("subnet_id").(string) | ||
|
||
// due to a bug in the API we have to ensure the Subnet's configured correctly or the API call will timeout | ||
// BUG: https://github.com/Azure/azure-rest-api-specs/issues/3719 | ||
subnetsClient := meta.(*ArmClient).subnetClient | ||
subnetParsedId, err := parseAzureResourceID(subnetId) | ||
|
||
subnetResourceGroup := subnetParsedId.ResourceGroup | ||
virtualNetwork := subnetParsedId.Path["virtualNetworks"] | ||
subnetName := subnetParsedId.Path["subnets"] | ||
subnet, err := subnetsClient.Get(ctx, subnetResourceGroup, virtualNetwork, subnetName, "") | ||
if err != nil { | ||
if utils.ResponseWasNotFound(subnet.Response) { | ||
return fmt.Errorf("Subnet with ID %q was not found: %+v", subnetId, err) | ||
} | ||
|
||
return fmt.Errorf("Error obtaining Subnet %q (Virtual Network %q / Resource Group %q: %+v", subnetName, virtualNetwork, subnetResourceGroup, err) | ||
} | ||
|
||
containsEndpoint := false | ||
if props := subnet.SubnetPropertiesFormat; props != nil { | ||
if endpoints := props.ServiceEndpoints; endpoints != nil { | ||
for _, e := range *endpoints { | ||
if e.Service == nil { | ||
continue | ||
} | ||
|
||
if strings.EqualFold(*e.Service, "Microsoft.Sql") { | ||
containsEndpoint = true | ||
break | ||
} | ||
} | ||
} | ||
} | ||
|
||
if !containsEndpoint { | ||
return fmt.Errorf("Error creating PostgreSQL Virtual Network Rule: Subnet %q (Virtual Network %q / Resource Group %q) must contain a Service Endpoint for `Microsoft.Sql`", subnetName, virtualNetwork, subnetResourceGroup) | ||
} | ||
|
||
parameters := postgresql.VirtualNetworkRule{ | ||
VirtualNetworkRuleProperties: &postgresql.VirtualNetworkRuleProperties{ | ||
VirtualNetworkSubnetID: utils.String(subnetId), | ||
IgnoreMissingVnetServiceEndpoint: utils.Bool(false), | ||
}, | ||
} | ||
|
||
_, err = client.CreateOrUpdate(ctx, resourceGroup, serverName, name, parameters) | ||
if err != nil { | ||
return fmt.Errorf("Error creating PostgreSQL Virtual Network Rule %q (PostgreSQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
//Wait for the provisioning state to become ready | ||
log.Printf("[DEBUG] Waiting for PostgreSQL Virtual Network Rule %q (PostgreSQL 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: postgreSQLVirtualNetworkStateStatusCodeRefreshFunc(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 PostgreSQL Virtual Network Rule %q (PostgreSQL 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 PostgreSQL Virtual Network Rule %q (PostgreSQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
d.SetId(*resp.ID) | ||
|
||
return resourceArmPostgreSQLVirtualNetworkRuleRead(d, meta) | ||
} | ||
|
||
func resourceArmPostgreSQLVirtualNetworkRuleRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).postgresqlVirtualNetworkRulesClient | ||
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 PostgreSQL Virtual Network Rule %q - removing from state", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("Error reading PostgreSQL Virtual Network Rule: %q (PostgreSQL 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) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceArmPostgreSQLVirtualNetworkRuleDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).postgresqlVirtualNetworkRulesClient | ||
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 PostgreSQL Virtual Network Rule %q (PostgreSQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
err = future.WaitForCompletionRef(ctx, client.Client) | ||
if err != nil { | ||
if response.WasNotFound(future.Response()) { | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("Error deleting PostgreSQL Virtual Network Rule %q (PostgreSQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
/* | ||
This function checks the format of the PostgreSQL Virtual Network Rule Name to make sure that | ||
it does not contain any potentially invalid values. | ||
*/ | ||
func validatePostgreSQLVirtualNetworkRuleName(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 PostgreSQL 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 postgreSQLVirtualNetworkStateStatusCodeRefreshFunc(ctx context.Context, client postgresql.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 PostgreSQL Virtual Network Rule %q (PostgreSQL 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 PostgreSQL Virtual Network Rule %q (PostgreSQL Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) | ||
} | ||
|
||
if props := resp.VirtualNetworkRuleProperties; props != nil { | ||
log.Printf("[DEBUG] Retrieving PostgreSQL Virtual Network Rule %q (PostgreSQL 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 PostgreSQL Virtual Network Rule %q (PostgreSQL Server: %q, Resource Group: %q) returned empty VirtualNetworkRuleProperties", resourceGroup, serverName, name) | ||
return resp, "Unknown", nil | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where did you find the definition for these constraints? Because according to the general naming rules and restrictions it states:
<descriptive context>
sql-allow
In general, avoid having any special characters (
-
or_
) as the first or last character in any name. These characters will cause most validation rules to fail. I am also wondering if we could abstract this out to a general validation method in the azure package and use it on other resources as well?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These rules are present in the
resource_arm_sql_virtual_network_rule
which this resource has been copied from. They overall seem to be quite sensible, although I would be happy to adjust them to be a bit more stringent, especially around length or beginning/ending characters.In terms of abstracting out this validation, this might be worth doing although it'd be worth looking at the existing resources where the validation might apply to assess how valuable that would be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually fine for now, In the near future I will implement the validation functions in the azure helper package based on Microsoft's Naming conventions best practices. Once I have completed that work I will update this resource to use the new validation rules.