diff --git a/azurerm/config.go b/azurerm/config.go index c1297a9c2a48..cf550c9b05ac 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -133,23 +133,24 @@ type ArmClient struct { monitorAlertRulesClient insights.AlertRulesClient // Networking - applicationGatewayClient network.ApplicationGatewaysClient - expressRouteCircuitClient network.ExpressRouteCircuitsClient - ifaceClient network.InterfacesClient - loadBalancerClient network.LoadBalancersClient - localNetConnClient network.LocalNetworkGatewaysClient - publicIPClient network.PublicIPAddressesClient - routesClient network.RoutesClient - routeTablesClient network.RouteTablesClient - secGroupClient network.SecurityGroupsClient - secRuleClient network.SecurityRulesClient - subnetClient network.SubnetsClient - netUsageClient network.UsagesClient - vnetGatewayConnectionsClient network.VirtualNetworkGatewayConnectionsClient - vnetGatewayClient network.VirtualNetworkGatewaysClient - vnetClient network.VirtualNetworksClient - vnetPeeringsClient network.VirtualNetworkPeeringsClient - watcherClient network.WatchersClient + applicationGatewayClient network.ApplicationGatewaysClient + applicationSecurityGroupsClient network.ApplicationSecurityGroupsClient + expressRouteCircuitClient network.ExpressRouteCircuitsClient + ifaceClient network.InterfacesClient + loadBalancerClient network.LoadBalancersClient + localNetConnClient network.LocalNetworkGatewaysClient + publicIPClient network.PublicIPAddressesClient + routesClient network.RoutesClient + routeTablesClient network.RouteTablesClient + secGroupClient network.SecurityGroupsClient + secRuleClient network.SecurityRulesClient + subnetClient network.SubnetsClient + netUsageClient network.UsagesClient + vnetGatewayConnectionsClient network.VirtualNetworkGatewayConnectionsClient + vnetGatewayClient network.VirtualNetworkGatewaysClient + vnetClient network.VirtualNetworksClient + vnetPeeringsClient network.VirtualNetworkPeeringsClient + watcherClient network.WatchersClient // Resources managementLocksClient locks.ManagementLocksClient @@ -323,22 +324,15 @@ func getArmClient(c *authentication.Config) (*ArmClient, error) { return keyVaultSpt, nil }) - csc := containerservice.NewContainerServicesClientWithBaseURI(endpoint, c.SubscriptionID) - setUserAgent(&csc.Client) - csc.Authorizer = auth - csc.Sender = sender - csc.SkipResourceProviderRegistration = c.SkipProviderRegistration - client.containerServicesClient = csc - client.registerAppInsightsClients(endpoint, c.SubscriptionID, auth, sender) client.registerAutomationClients(endpoint, c.SubscriptionID, auth, sender) client.registerAuthentication(endpoint, graphEndpoint, c.SubscriptionID, c.TenantID, auth, graphAuth, sender) client.registerCDNClients(endpoint, c.SubscriptionID, auth, sender) client.registerComputeClients(endpoint, c.SubscriptionID, auth, sender) - client.registerContainerServicesClients(endpoint, c.SubscriptionID, auth) - client.registerCosmosDBClients(endpoint, c.SubscriptionID, auth, sender) client.registerContainerInstanceClients(endpoint, c.SubscriptionID, auth, sender) client.registerContainerRegistryClients(endpoint, c.SubscriptionID, auth, sender) + client.registerContainerServicesClients(endpoint, c.SubscriptionID, auth) + client.registerCosmosDBClients(endpoint, c.SubscriptionID, auth, sender) client.registerDatabases(endpoint, c.SubscriptionID, auth, sender) client.registerDNSClients(endpoint, c.SubscriptionID, auth, sender) client.registerEventGridClients(endpoint, c.SubscriptionID, auth, sender) @@ -656,6 +650,10 @@ func (c *ArmClient) registerNetworkingClients(endpoint, subscriptionId string, a c.configureClient(&applicationGatewaysClient.Client, auth) c.applicationGatewayClient = applicationGatewaysClient + appSecurityGroupsClient := network.NewApplicationSecurityGroupsClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&appSecurityGroupsClient.Client, auth) + c.applicationSecurityGroupsClient = appSecurityGroupsClient + expressRouteCircuitsClient := network.NewExpressRouteCircuitsClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&expressRouteCircuitsClient.Client, auth) c.expressRouteCircuitClient = expressRouteCircuitsClient diff --git a/azurerm/provider.go b/azurerm/provider.go index ea3f8221bde8..db56caae4f7d 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -90,6 +90,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "azurerm_application_gateway": resourceArmApplicationGateway(), "azurerm_application_insights": resourceArmApplicationInsights(), + "azurerm_application_security_group": resourceArmApplicationSecurityGroup(), "azurerm_app_service": resourceArmAppService(), "azurerm_app_service_plan": resourceArmAppServicePlan(), "azurerm_app_service_active_slot": resourceArmAppServiceActiveSlot(), diff --git a/azurerm/resource_arm_application_security_group.go b/azurerm/resource_arm_application_security_group.go new file mode 100644 index 000000000000..ce3b8bf3352b --- /dev/null +++ b/azurerm/resource_arm_application_security_group.go @@ -0,0 +1,132 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network" + "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 resourceArmApplicationSecurityGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceArmApplicationSecurityGroupCreateUpdate, + Read: resourceArmApplicationSecurityGroupRead, + Update: resourceArmApplicationSecurityGroupCreateUpdate, + Delete: resourceArmApplicationSecurityGroupDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "location": locationSchema(), + + "resource_group_name": resourceGroupNameSchema(), + + "tags": tagsSchema(), + }, + } +} + +func resourceArmApplicationSecurityGroupCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).applicationSecurityGroupsClient + ctx := meta.(*ArmClient).StopContext + + resourceGroup := d.Get("resource_group_name").(string) + name := d.Get("name").(string) + location := d.Get("location").(string) + tags := d.Get("tags").(map[string]interface{}) + + securityGroup := network.ApplicationSecurityGroup{ + Location: utils.String(location), + Tags: expandTags(tags), + } + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, securityGroup) + if err != nil { + return fmt.Errorf("Error creating Application Security Group %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + err = future.WaitForCompletion(ctx, client.Client) + if err != nil { + return fmt.Errorf("Error waiting for the Application Security Group %q (Resource Group %q) to finish creating: %+v", name, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Cannot read Application Security Group %q (Resource Group %q) ID", name, resourceGroup) + } + + d.SetId(*read.ID) + + return resourceArmApplicationSecurityGroupRead(d, meta) +} + +func resourceArmApplicationSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).applicationSecurityGroupsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["applicationSecurityGroups"] + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + + return fmt.Errorf("Error making Read request on Application Security Group %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("location", azureRMNormalizeLocation(*resp.Location)) + d.Set("resource_group_name", resourceGroup) + flattenAndSetTags(d, resp.Tags) + + return nil +} + +func resourceArmApplicationSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).applicationSecurityGroupsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["applicationSecurityGroups"] + + log.Printf("[DEBUG] Deleting Application Security Group %q (resource group %q)", name, resourceGroup) + + future, err := client.Delete(ctx, resourceGroup, name) + if err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error issuing delete request for Application Security Group %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + + err = future.WaitForCompletion(ctx, client.Client) + if err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error waiting for deletion of Application Security Group %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + + return nil +} diff --git a/azurerm/resource_arm_application_security_group_test.go b/azurerm/resource_arm_application_security_group_test.go new file mode 100644 index 000000000000..a4387826f730 --- /dev/null +++ b/azurerm/resource_arm_application_security_group_test.go @@ -0,0 +1,174 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMApplicationSecurityGroup_basic(t *testing.T) { + ri := acctest.RandInt() + resourceName := "azurerm_application_security_group.test" + config := testAccAzureRMApplicationSecurityGroup_basic(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationSecurityGroupExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccAzureRMApplicationSecurityGroup_complete(t *testing.T) { + ri := acctest.RandInt() + resourceName := "azurerm_application_security_group.test" + config := testAccAzureRMApplicationSecurityGroup_complete(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationSecurityGroupExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Hello", "World"), + ), + }, + }, + }) +} + +func TestAccAzureRMApplicationSecurityGroup_update(t *testing.T) { + ri := acctest.RandInt() + location := testLocation() + resourceName := "azurerm_application_security_group.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationSecurityGroup_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationSecurityGroupExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAzureRMApplicationSecurityGroup_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationSecurityGroupExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Hello", "World"), + ), + }, + }, + }) +} + +func testCheckAzureRMApplicationSecurityGroupDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_application_security_group" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + client := testAccProvider.Meta().(*ArmClient).applicationSecurityGroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resourceGroup, name) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + + return fmt.Errorf("Applicaton Security Group still exists:\n%#v", resp) + } + + return nil +} + +func testCheckAzureRMApplicationSecurityGroupExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %q", name) + } + + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for Application Security Group: %q", name) + } + + client := testAccProvider.Meta().(*ArmClient).applicationSecurityGroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.Get(ctx, resourceGroup, name) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Application Security Group %q (resource group: %q) was not found: %+v", name, resourceGroup, err) + } + + return fmt.Errorf("Bad: Get on applicationSecurityGroupsClient: %+v", err) + } + + return nil + } +} + +func testAccAzureRMApplicationSecurityGroup_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_application_security_group" "test" { + name = "acctest-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, rInt, location, rInt) +} + +func testAccAzureRMApplicationSecurityGroup_complete(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_application_security_group" "test" { + name = "acctest-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tags { + "Hello" = "World" + } +} +`, rInt, location, rInt) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 07e6ce30082e..cdfcc5071d0f 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -484,6 +484,10 @@ azurerm_application_gateway + > + azurerm_application_security_group + + > azurerm_express_route_circuit diff --git a/website/docs/r/application_security_group.html.markdown b/website/docs/r/application_security_group.html.markdown new file mode 100644 index 000000000000..a078a52c38da --- /dev/null +++ b/website/docs/r/application_security_group.html.markdown @@ -0,0 +1,57 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_application_security_group" +sidebar_current: "docs-azurerm-resource-network-application-security-group" +description: |- + Create an Application Security Group. +--- + +# azurerm_application_security_group + +Create an Application Security Group. + +-> **Note:** Application Security Groups are currently in Public Preview on an opt-in basis. [More information, including how you can register for the Preview, and which regions Application Security Groups are available in are available here](https://docs.microsoft.com/en-us/azure/virtual-network/create-network-security-group-preview) + +## Example Usage + +```hcl +resource "azurerm_resource_group" "test" { + name = "tf-test" + location = "West Europe" +} + +resource "azurerm_application_security_group" "test" { + name = "tf-appsecuritygroup" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tags { + "Hello" = "World" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of the Application Security Group. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which to create the Application Security Group. + +* `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. + +* `tags` - (Optional) A mapping of tags to assign to the resource. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Application Security Group. + +## Import + +Application Security Groups can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_application_security_group.securitygroup1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/applicationSecurityGroups/securitygroup1 +```