diff --git a/azurerm/internal/services/network/nat_gateway_public_ip_association_resource.go b/azurerm/internal/services/network/nat_gateway_public_ip_association_resource.go new file mode 100644 index 000000000000..e1a5e229ce27 --- /dev/null +++ b/azurerm/internal/services/network/nat_gateway_public_ip_association_resource.go @@ -0,0 +1,195 @@ +package network + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-03-01/network" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "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/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" + 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 resourceArmNatGatewayPublicIpAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceArmNatGatewayPublicIpAssociationCreate, + Read: resourceArmNatGatewayPublicIpAssociationRead, + Delete: resourceArmNatGatewayPublicIpAssociationDelete, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.NatGatewayID(id) + return err + }), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "nat_gateway_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NatGatewayID, + }, + + "public_ip_address_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: azure.ValidateResourceID, + }, + }, + } +} + +func resourceArmNatGatewayPublicIpAssociationCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.NatGatewayClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for Nat Gateway <-> Public Ip Association creation.") + natGatewayId := d.Get("nat_gateway_id").(string) + publicIpAddressId := d.Get("public_ip_address_id").(string) + parsedNatGatewayId, err := parse.NatGatewayID(natGatewayId) + if err != nil { + return err + } + + locks.ByName(parsedNatGatewayId.Name, natGatewayResourceName) + defer locks.UnlockByName(parsedNatGatewayId.Name, natGatewayResourceName) + + natGateway, err := client.Get(ctx, parsedNatGatewayId.ResourceGroup, parsedNatGatewayId.Name, "") + if err != nil { + if utils.ResponseWasNotFound(natGateway.Response) { + return fmt.Errorf("Nat Gateway %q (Resource Group %q) was not found.", parsedNatGatewayId.Name, parsedNatGatewayId.ResourceGroup) + } + return fmt.Errorf("failed to retrieve Nat Gateway %q (Resource Group %q): %+v", parsedNatGatewayId.Name, parsedNatGatewayId.ResourceGroup, err) + } + + publicIpAddresses := make([]network.SubResource, 0) + if natGateway.PublicIPAddresses != nil { + for _, existingPublicIPAddress := range *natGateway.PublicIPAddresses { + if existingPublicIPAddress.ID != nil { + if *existingPublicIPAddress.ID == publicIpAddressId { + return tf.ImportAsExistsError("azurerm_nat_gateway_public_ip_association", *natGateway.ID) + } + + publicIpAddresses = append(publicIpAddresses, existingPublicIPAddress) + } + } + } + + publicIpAddresses = append(publicIpAddresses, network.SubResource{ + ID: utils.String(publicIpAddressId), + }) + natGateway.PublicIPAddresses = &publicIpAddresses + + future, err := client.CreateOrUpdate(ctx, parsedNatGatewayId.ResourceGroup, parsedNatGatewayId.Name, natGateway) + if err != nil { + return fmt.Errorf("failed to update Public IP Association for Nat Gateway %q (Resource Group %q): %+v", parsedNatGatewayId.Name, parsedNatGatewayId.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("failed to wait for completion of Public IP Association for Nat Gateway %q (Resource Group %q): %+v", parsedNatGatewayId.Name, parsedNatGatewayId.ResourceGroup, err) + } + + resp, err := client.Get(ctx, parsedNatGatewayId.ResourceGroup, parsedNatGatewayId.Name, "") + if err != nil { + return fmt.Errorf("failed to retrieve Nat Gateway %q (Resource Group %q): %+v", parsedNatGatewayId.Name, parsedNatGatewayId.ResourceGroup, err) + } + d.SetId(*resp.ID) + + return resourceArmNatGatewayPublicIpAssociationRead(d, meta) +} + +func resourceArmNatGatewayPublicIpAssociationRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.NatGatewayClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.NatGatewayID(d.Id()) + if err != nil { + return err + } + + natGateway, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + if err != nil { + if utils.ResponseWasNotFound(natGateway.Response) { + log.Printf("[DEBUG] Nat Gateway %q (Resource Group %q) could not be found - removing from state!", id.Name, id.ResourceGroup) + d.SetId("") + return nil + } + return fmt.Errorf("failed to retrieve Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + if natGateway.PublicIPAddresses == nil { + log.Printf("[DEBUG] Nat Gateway %q (Resource Group %q) doesn't have a Public IP - removing from state!", id.Name, id.ResourceGroup) + d.SetId("") + return nil + } + + d.Set("nat_gateway_id", natGateway.ID) + + return nil +} + +func resourceArmNatGatewayPublicIpAssociationDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.NatGatewayClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.NatGatewayID(d.Id()) + if err != nil { + return err + } + + publicIpAddressId := d.Get("public_ip_address_id").(string) + + locks.ByName(id.Name, natGatewayResourceName) + defer locks.UnlockByName(id.Name, natGatewayResourceName) + + natGateway, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + if err != nil { + if utils.ResponseWasNotFound(natGateway.Response) { + return fmt.Errorf("Nat Gateway %q (Resource Group %q) was not found.", id.Name, id.ResourceGroup) + } + + return fmt.Errorf("failed to retrieve Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + publicIpAddresses := make([]network.SubResource, 0) + if publicIPAddresses := natGateway.PublicIPAddresses; publicIPAddresses != nil { + for _, publicIPAddress := range *publicIPAddresses { + if publicIPAddress.ID == nil { + continue + } + + if *publicIPAddress.ID != publicIpAddressId { + publicIpAddresses = append(publicIpAddresses, publicIPAddress) + } + } + } + natGateway.PublicIPAddresses = &publicIpAddresses + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, natGateway) + if err != nil { + return fmt.Errorf("failed to remove Public Ip Association for Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("failed to wait for removal of Public Ip Association for Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + return nil +} diff --git a/azurerm/internal/services/network/nat_gateway_resource.go b/azurerm/internal/services/network/nat_gateway_resource.go index 46b7f7a0dd27..cc9783747c88 100644 --- a/azurerm/internal/services/network/nat_gateway_resource.go +++ b/azurerm/internal/services/network/nat_gateway_resource.go @@ -60,10 +60,12 @@ func resourceArmNatGateway() *schema.Resource { "public_ip_address_ids": { Type: schema.TypeSet, Optional: true, + Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: azure.ValidateResourceID, }, + Deprecated: "Deprecated in favor of `azurerm_nat_gateway_public_ip_association`. The dependency relation between `azurerm_nat_gateway` and `azurerm_public_ip` isn't detected by implicit dependency. So `azurerm_nat_gateway_public_ip_association` is added to resolve this issue.", }, "public_ip_prefix_ids": { diff --git a/azurerm/internal/services/network/parse/nat_gateway.go b/azurerm/internal/services/network/parse/nat_gateway.go new file mode 100644 index 000000000000..c730d001f34d --- /dev/null +++ b/azurerm/internal/services/network/parse/nat_gateway.go @@ -0,0 +1,31 @@ +package parse + +import ( + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type NatGatewayId struct { + Name string + ResourceGroup string +} + +func NatGatewayID(input string) (*NatGatewayId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + natGateway := NatGatewayId{ + ResourceGroup: id.ResourceGroup, + } + + if natGateway.Name, err = id.PopSegment("natGateways"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &natGateway, nil +} diff --git a/azurerm/internal/services/network/parse/nat_gateway_test.go b/azurerm/internal/services/network/parse/nat_gateway_test.go new file mode 100644 index 000000000000..d93cb021cf27 --- /dev/null +++ b/azurerm/internal/services/network/parse/nat_gateway_test.go @@ -0,0 +1,70 @@ +package parse + +import ( + "testing" +) + +func TestNatGatewayID(t *testing.T) { + testData := []struct { + Name string + Input string + Error bool + Expect *NatGatewayId + }{ + { + Name: "Empty", + Input: "", + Error: true, + }, + { + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Error: true, + }, + { + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups", + Error: true, + }, + { + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1", + Error: true, + }, + { + Name: "Missing Nat Gateway Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/natGateways", + Error: true, + }, + { + Name: "Nat Gateway ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/natGateways/gateway1", + Error: false, + Expect: &NatGatewayId{ + Name: "gateway1", + ResourceGroup: "group1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := NatGatewayID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.Name != v.Expect.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expect.Name, actual.Name) + } + + if actual.ResourceGroup != v.Expect.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.Expect.ResourceGroup, actual.ResourceGroup) + } + } +} diff --git a/azurerm/internal/services/network/registration.go b/azurerm/internal/services/network/registration.go index 1bd4e2ba5bc4..c6bdf4c1e225 100644 --- a/azurerm/internal/services/network/registration.go +++ b/azurerm/internal/services/network/registration.go @@ -86,6 +86,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_private_endpoint": resourceArmPrivateEndpoint(), "azurerm_private_link_service": resourceArmPrivateLinkService(), "azurerm_public_ip": resourceArmPublicIp(), + "azurerm_nat_gateway_public_ip_association": resourceArmNatGatewayPublicIpAssociation(), "azurerm_public_ip_prefix": resourceArmPublicIpPrefix(), "azurerm_network_security_group": resourceArmNetworkSecurityGroup(), "azurerm_network_security_rule": resourceArmNetworkSecurityRule(), diff --git a/azurerm/internal/services/network/tests/nat_gateway_public_ip_association_resource_test.go b/azurerm/internal/services/network/tests/nat_gateway_public_ip_association_resource_test.go new file mode 100644 index 000000000000..39aa699e72ce --- /dev/null +++ b/azurerm/internal/services/network/tests/nat_gateway_public_ip_association_resource_test.go @@ -0,0 +1,293 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-03-01/network" + "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/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +func TestAccAzureRMNatGatewayPublicIpAssociation_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNatGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNatGatewayPublicIpAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNatGatewayPublicIpAssociationExists(data.ResourceName), + ), + }, + // `public_ip_address_id` cannot be retrieved in read function while importing. + data.ImportStep("public_ip_address_id"), + }, + }) +} + +func TestAccAzureRMNatGatewayPublicIpAssociation_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNatGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNatGatewayPublicIpAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNatGatewayPublicIpAssociationExists(data.ResourceName), + ), + }, + data.RequiresImportErrorStep(testAccAzureRMNatGatewayPublicIpAssociation_requiresImport), + }, + }) +} + +func TestAccAzureRMNatGatewayPublicIpAssociation_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNatGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNatGatewayPublicIpAssociation_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNatGatewayPublicIpAssociationExists(data.ResourceName), + ), + }, + data.ImportStep("public_ip_address_id"), + }, + }) +} + +func TestAccAzureRMNatGatewayPublicIpAssociation_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNatGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNatGatewayPublicIpAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNatGatewayPublicIpAssociationExists(data.ResourceName), + ), + }, + data.ImportStep("public_ip_address_id"), + { + Config: testAccAzureRMNatGatewayPublicIpAssociation_update(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNatGatewayPublicIpAssociationExists(data.ResourceName), + ), + }, + data.ImportStep("public_ip_address_id"), + }, + }) +} + +func TestAccAzureRMNatGatewayPublicIpAssociation_deleted(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_association", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNatGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNatGatewayPublicIpAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNatGatewayPublicIpAssociationExists(data.ResourceName), + testCheckAzureRMNatGatewayPublicIpAssociationDisappears(data.ResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccAzureRMNatGatewayPublicIpAssociation_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMNatGatewayPublicIpAssociation_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway_public_ip_association" "import" { + nat_gateway_id = azurerm_nat_gateway_public_ip_association.test.nat_gateway_id + public_ip_address_id = azurerm_nat_gateway_public_ip_association.test.public_ip_address_id +} +`, template) +} + +func testCheckAzureRMNatGatewayPublicIpAssociationExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Network.NatGatewayClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + id, err := parse.NatGatewayID(rs.Primary.ID) + if err != nil { + return err + } + publicIpAddressId := rs.Primary.Attributes["public_ip_address_id"] + + resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + if err != nil { + return fmt.Errorf("failed to retrieve Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + if publicIpAddresses := resp.PublicIPAddresses; publicIpAddresses != nil { + for _, publicIpAddress := range *publicIpAddresses { + if *publicIpAddress.ID == publicIpAddressId { + return nil + } + } + } + + return fmt.Errorf("Association between Nat Gateway %q and Public Ip %q was not found.", id.Name, publicIpAddressId) + } +} + +func testCheckAzureRMNatGatewayPublicIpAssociationDisappears(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Network.NatGatewayClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + id, err := parse.NatGatewayID(rs.Primary.ID) + if err != nil { + return err + } + publicIpAddressId := rs.Primary.Attributes["public_ip_address_id"] + + resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + if err != nil { + return fmt.Errorf("failed to retrieve Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + updatedAddresses := make([]network.SubResource, 0) + if publicIpAddresses := resp.PublicIPAddresses; publicIpAddresses != nil { + for _, publicIpAddress := range *publicIpAddresses { + if *publicIpAddress.ID != publicIpAddressId { + updatedAddresses = append(updatedAddresses, publicIpAddress) + } + } + } + resp.PublicIPAddresses = &updatedAddresses + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, resp) + if err != nil { + return fmt.Errorf("failed to remove Nat Gateway Public Ip Association for Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("failed to wait for removal of Nat Gateway Public Ip Association for Nat Gateway %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + return nil + } +} + +func testAccAzureRMNatGatewayPublicIpAssociation_basic(data acceptance.TestData) string { + template := testAccAzureRMNatGatewayPublicIpAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway_public_ip_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_address_id = azurerm_public_ip.test.id +} +`, template) +} + +func testAccAzureRMNatGatewayPublicIpAssociation_complete(data acceptance.TestData) string { + template := testAccAzureRMNatGatewayPublicIpAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway_public_ip_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_address_id = azurerm_public_ip.test.id +} + +resource "azurerm_public_ip" "test2" { + name = "acctest-PIP2-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_nat_gateway_public_ip_association" "test2" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_address_id = azurerm_public_ip.test2.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNatGatewayPublicIpAssociation_update(data acceptance.TestData) string { + template := testAccAzureRMNatGatewayPublicIpAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway" "test2" { + name = "acctest-NatGateway2-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Standard" +} + +resource "azurerm_nat_gateway_public_ip_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test2.id + public_ip_address_id = azurerm_public_ip.test.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNatGatewayPublicIpAssociation_template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-ngpi-%d" + location = "%s" +} + +resource "azurerm_public_ip" "test" { + name = "acctest-PIP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_nat_gateway" "test" { + name = "acctest-NatGateway-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Standard" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/network/validate/nat_gateway.go b/azurerm/internal/services/network/validate/nat_gateway.go new file mode 100644 index 000000000000..7ec9cdd42e6f --- /dev/null +++ b/azurerm/internal/services/network/validate/nat_gateway.go @@ -0,0 +1,22 @@ +package validate + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +func NatGatewayID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := parse.NatGatewayID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 25d10b1ed772..972c812fe1e3 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -2016,6 +2016,10 @@ azurerm_nat_gateway +