mirror of https://github.com/hashicorp/terraform
- Add documentation for resources - Rename files to match standard patterns - Add acceptance tests for resource groups - Add acceptance tests for vnets - Remove ARM_CREDENTIALS file - as discussed this does not appear to be an Azure standard, and there is scope for confusion with the azureProfile.json file which the CLI generates. If a standard emerges we can reconsider this. - Validate credentials in the schema - Remove storage testing artefacts - Use ARM IDs as Terraform IDs - Use autorest hooks for loggingpull/4226/head
parent
63bc8e9852
commit
805c4896bd
@ -1 +0,0 @@
|
||||
package main
|
||||
@ -0,0 +1,82 @@
|
||||
package azurerm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/core/http"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureRMResourceGroup_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testCheckAzureRMResourceGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureRMResourceGroup_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testCheckAzureRMResourceGroupExists("azurerm_resource_group.test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testCheckAzureRMResourceGroupExists(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: %s", name)
|
||||
}
|
||||
|
||||
resourceGroup := rs.Primary.Attributes["name"]
|
||||
|
||||
// Ensure resource group exists in API
|
||||
conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient
|
||||
|
||||
resp, err := conn.Get(resourceGroup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Bad: Get on resourceGroupClient: %s", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return fmt.Errorf("Bad: Virtual Network %q (resource group: %q) does not exist", name, resourceGroup)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testCheckAzureRMResourceGroupDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "azurerm_resource_group" {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceGroup := rs.Primary.ID
|
||||
|
||||
resp, err := conn.Get(resourceGroup)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
return fmt.Errorf("Resource Group still exists:\n%#v", resp.Properties)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAzureRMResourceGroup_basic = `
|
||||
resource "azurerm_resource_group" "test" {
|
||||
name = "acceptanceTestResourceGroup1_basic"
|
||||
location = "West US"
|
||||
}
|
||||
`
|
||||
@ -0,0 +1,100 @@
|
||||
package azurerm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/core/http"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureRMVirtualNetwork_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testCheckAzureRMVirtualNetworkDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureRMVirtualNetwork_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testCheckAzureRMVirtualNetworkExists("azurerm_virtual_network.test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testCheckAzureRMVirtualNetworkExists(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: %s", name)
|
||||
}
|
||||
|
||||
virtualNetworkName := 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 virtual network: %s", virtualNetworkName)
|
||||
}
|
||||
|
||||
// Ensure resource group/virtual network combination exists in API
|
||||
conn := testAccProvider.Meta().(*ArmClient).vnetClient
|
||||
|
||||
resp, err := conn.Get(resourceGroup, virtualNetworkName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Bad: Get on vnetClient: %s", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return fmt.Errorf("Bad: Virtual Network %q (resource group: %q) does not exist", name, resourceGroup)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testCheckAzureRMVirtualNetworkDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*ArmClient).vnetClient
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "azurerm_virtual_network" {
|
||||
continue
|
||||
}
|
||||
|
||||
name := rs.Primary.Attributes["name"]
|
||||
resourceGroup := rs.Primary.Attributes["resource_group_name"]
|
||||
|
||||
resp, err := conn.Get(resourceGroup, name)
|
||||
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
return fmt.Errorf("Virtual Network sitll exists:\n%#v", resp.Properties)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAzureRMVirtualNetwork_basic = `
|
||||
resource "azurerm_resource_group" "test" {
|
||||
name = "acceptanceTestResourceGroup1"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
resource "azurerm_virtual_network" "test" {
|
||||
name = "acceptanceTestVirtualNetwork1"
|
||||
address_space = ["10.0.0.0/16"]
|
||||
location = "West US"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
|
||||
subnet {
|
||||
name = "subnet1"
|
||||
address_prefix = "10.0.1.0/24"
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -0,0 +1,82 @@
|
||||
package azurerm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ResourceID represents a parsed long-form Azure Resource Manager ID
|
||||
// with the Subscription ID, Resource Group and the Provider as top-
|
||||
// level fields, and other key-value pairs available via a map in the
|
||||
// Path field.
|
||||
type ResourceID struct {
|
||||
SubscriptionID string
|
||||
ResourceGroup string
|
||||
Provider string
|
||||
Path map[string]string
|
||||
}
|
||||
|
||||
// parseAzureResourceID converts a long-form Azure Resource Manager ID
|
||||
// into a ResourceID. We make assumptions about the structure of URLs,
|
||||
// which is obviously not good, but the best thing available given the
|
||||
// SDK.
|
||||
func parseAzureResourceID(id string) (*ResourceID, error) {
|
||||
idURL, err := url.ParseRequestURI(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse Azure Id: %s", err)
|
||||
}
|
||||
|
||||
path := idURL.Path
|
||||
|
||||
path = strings.TrimSpace(path)
|
||||
if strings.HasPrefix(path, "/") {
|
||||
path = path[1:]
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, "/") {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
|
||||
components := strings.Split(path, "/")
|
||||
|
||||
// We should have an even number of key-value pairs.
|
||||
if len(components)%2 != 0 {
|
||||
return nil, fmt.Errorf("The number of path segments is not divisible by 2 in %q", path)
|
||||
}
|
||||
|
||||
// Put the constituent key-value pairs into a map
|
||||
componentMap := make(map[string]string, len(components)/2)
|
||||
for current := 0; current < len(components); current += 2 {
|
||||
key := components[current]
|
||||
value := components[current+1]
|
||||
|
||||
componentMap[key] = value
|
||||
}
|
||||
|
||||
// Build up a ResourceID from the map
|
||||
idObj := &ResourceID{}
|
||||
idObj.Path = componentMap
|
||||
|
||||
if subscription, ok := componentMap["subscriptions"]; ok {
|
||||
idObj.SubscriptionID = subscription
|
||||
delete(componentMap, "subscriptions")
|
||||
} else {
|
||||
return nil, fmt.Errorf("No subscription ID found in: %q", path)
|
||||
}
|
||||
|
||||
if resourceGroup, ok := componentMap["resourceGroups"]; ok {
|
||||
idObj.ResourceGroup = resourceGroup
|
||||
delete(componentMap, "resourceGroups")
|
||||
} else {
|
||||
return nil, fmt.Errorf("No resource group name found in: %q", path)
|
||||
}
|
||||
|
||||
// It is OK not to have a provider in the case of a resource group
|
||||
if provider, ok := componentMap["providers"]; ok {
|
||||
idObj.Provider = provider
|
||||
delete(componentMap, "providers")
|
||||
}
|
||||
|
||||
return idObj, nil
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
package azurerm
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseAzureResourceID(t *testing.T) {
|
||||
testCases := []struct {
|
||||
id string
|
||||
expectedResourceID *ResourceID
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
"random",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"/subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"/subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038/resourceGroups/testGroup1",
|
||||
&ResourceID{
|
||||
SubscriptionID: "6d74bdd2-9f84-11e5-9bd9-7831c1c4c038",
|
||||
ResourceGroup: "testGroup1",
|
||||
Provider: "",
|
||||
Path: map[string]string{},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"/subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038/resourceGroups/testGroup1/providers/Microsoft.Network",
|
||||
&ResourceID{
|
||||
SubscriptionID: "6d74bdd2-9f84-11e5-9bd9-7831c1c4c038",
|
||||
ResourceGroup: "testGroup1",
|
||||
Provider: "Microsoft.Network",
|
||||
Path: map[string]string{},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Missing leading /
|
||||
"subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038/resourceGroups/testGroup1/providers/Microsoft.Network/virtualNetworks/virtualNetwork1/",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"/subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038/resourceGroups/testGroup1/providers/Microsoft.Network/virtualNetworks/virtualNetwork1",
|
||||
&ResourceID{
|
||||
SubscriptionID: "6d74bdd2-9f84-11e5-9bd9-7831c1c4c038",
|
||||
ResourceGroup: "testGroup1",
|
||||
Provider: "Microsoft.Network",
|
||||
Path: map[string]string{
|
||||
"virtualNetworks": "virtualNetwork1",
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"/subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038/resourceGroups/testGroup1/providers/Microsoft.Network/virtualNetworks/virtualNetwork1?api-version=2006-01-02-preview",
|
||||
&ResourceID{
|
||||
SubscriptionID: "6d74bdd2-9f84-11e5-9bd9-7831c1c4c038",
|
||||
ResourceGroup: "testGroup1",
|
||||
Provider: "Microsoft.Network",
|
||||
Path: map[string]string{
|
||||
"virtualNetworks": "virtualNetwork1",
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"/subscriptions/6d74bdd2-9f84-11e5-9bd9-7831c1c4c038/resourceGroups/testGroup1/providers/Microsoft.Network/virtualNetworks/virtualNetwork1/subnets/publicInstances1?api-version=2006-01-02-preview",
|
||||
&ResourceID{
|
||||
SubscriptionID: "6d74bdd2-9f84-11e5-9bd9-7831c1c4c038",
|
||||
ResourceGroup: "testGroup1",
|
||||
Provider: "Microsoft.Network",
|
||||
Path: map[string]string{
|
||||
"virtualNetworks": "virtualNetwork1",
|
||||
"subnets": "publicInstances1",
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
parsed, err := parseAzureResourceID(test.id)
|
||||
if test.expectError && err != nil {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(test.expectedResourceID, parsed) {
|
||||
t.Fatalf("Unexpected resource ID:\nExpected: %+v\nGot: %+v\n", test.expectedResourceID, parsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
---
|
||||
layout: "azurerm"
|
||||
page_title: "Provider: Azure Resource Manager"
|
||||
sidebar_current: "docs-azurerm-index"
|
||||
description: |-
|
||||
The Azure Resource Manager provider is used to interact with the many resources supported by Azure, via the ARM API. This supercedes the Azure provider, which interacts with Azure using the Service Management API. The provider needs to be configured with a credentials file, or credentials needed to generate OAuth tokens for the ARM API.
|
||||
---
|
||||
|
||||
# Azure Resource Manager Provider
|
||||
|
||||
The Azure Resource Manager provider is used to interact with the many resources
|
||||
supported by Azure, via the ARM API. This supercedes the Azure provider, which
|
||||
interacts with Azure using the Service Management API. The provider needs to be
|
||||
configured with the credentials needed to generate OAuth tokens for the ARM API.
|
||||
|
||||
Use the navigation to the left to read about the available resources.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
# Configure the Azure Resource Manager Provider
|
||||
provider "azurerm" {
|
||||
subscription_id = "..."
|
||||
client_id = "..."
|
||||
client_secret = "..."
|
||||
tenant_id = "..."
|
||||
}
|
||||
|
||||
# Create a resource group
|
||||
resource "azurerm_resource_group" "production" {
|
||||
name = "production"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
# Create a virtual network in the web_servers resource group
|
||||
resource "azurerm_virtual_network" "network" {
|
||||
name = "productionNetwork"
|
||||
address_space = ["10.0.0.0/16"]
|
||||
location = "West US"
|
||||
resource_group_name = "${azurerm_resource_group.production.name}"
|
||||
|
||||
subnet {
|
||||
name = "subnet1"
|
||||
address_prefix = "10.0.1.0/24"
|
||||
}
|
||||
|
||||
subnet {
|
||||
name = "subnet2"
|
||||
address_prefix = "10.0.2.0/24"
|
||||
}
|
||||
|
||||
subnet {
|
||||
name = "subnet3"
|
||||
address_prefix = "10.0.3.0/24"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `subscription_id` - (Optional) The subscription ID to use. It can also
|
||||
be sourced from the `ARM_SUBSCRIPTION_ID` environment variable.
|
||||
|
||||
* `client_id` - (Optional) The client ID to use. It can also be sourced from
|
||||
the `ARM_CLIENT_ID` environment variable.
|
||||
|
||||
* `client_secret` - (Optional) The client secret to use. It can also be sourced from
|
||||
the `ARM_CLIENT_SECRET` environment variable.
|
||||
|
||||
* `tenant_id` - (Optional) The tenant ID to use. It can also be sourced from the
|
||||
`ARM_TENANT_ID` environment variable.
|
||||
|
||||
## Testing:
|
||||
|
||||
Credentials must be provided via the `ARM_SUBSCRIPTION_ID`, `ARM_CLIENT_ID`,
|
||||
`ARM_CLIENT_SECRET` and `ARM_TENANT_ID` environment variables in order to run
|
||||
acceptance tests.
|
||||
@ -0,0 +1,36 @@
|
||||
---
|
||||
layout: "azurerm"
|
||||
page_title: "Azure Resource Manager: azurerm_resource_group"
|
||||
sidebar_current: "docs-azurerm-resource-resource-group"
|
||||
description: |-
|
||||
Creates a new resource group on Azure.
|
||||
---
|
||||
|
||||
# azurerm\_resource\_group
|
||||
|
||||
Creates a new resource group on Azure.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azurerm_resource_group" "test" {
|
||||
name = "testResourceGroup1"
|
||||
location = "West US"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the resource group. Must be unique on your
|
||||
Azure subscription.
|
||||
|
||||
* `location` - (Required) The location where the resource group should be created.
|
||||
For a list of all Azure locations, please consult [this link](http://azure.microsoft.com/en-us/regions/).
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The resource group ID.
|
||||
@ -0,0 +1,76 @@
|
||||
---
|
||||
layout: "azurerm"
|
||||
page_title: "Azure Resource Manager: azure_virtual_network"
|
||||
sidebar_current: "docs-azurerm-resource-virtual-network"
|
||||
description: |-
|
||||
Creates a new virtual network including any configured subnets. Each subnet can optionally be configured with a security group to be associated with the subnet.
|
||||
---
|
||||
|
||||
# azurerm\_virtual\_network
|
||||
|
||||
Creates a new virtual network including any configured subnets. Each subnet can
|
||||
optionally be configured with a security group to be associated with the subnet.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azurerm_virtual_network" "test" {
|
||||
name = "virtualNetwork1"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
address_space = ["10.0.0.0/16"]
|
||||
location = "West US"
|
||||
|
||||
subnet {
|
||||
name = "subnet1"
|
||||
address_prefix = "10.0.1.0/24"
|
||||
}
|
||||
|
||||
subnet {
|
||||
name = "subnet2"
|
||||
address_prefix = "10.0.2.0/24"
|
||||
}
|
||||
|
||||
subnet {
|
||||
name = "subnet3"
|
||||
address_prefix = "10.0.3.0/24"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the virtual network. Changing this forces a
|
||||
new resource to be created.
|
||||
|
||||
* `resource_group_name` - (Required) The name of the resource group in which to
|
||||
create the virtual network.
|
||||
|
||||
* `address_space` - (Required) The address space that is used the virtual
|
||||
network. You can supply more than one address space. Changing this forces
|
||||
a new resource to be created.
|
||||
|
||||
* `location` - (Required) The location/region where the virtual network is
|
||||
created. Changing this forces a new resource to be created.
|
||||
|
||||
* `dns_servers` - (Optional) List of names of DNS servers previously registered
|
||||
on Azure.
|
||||
|
||||
* `subnet` - (Required) Can be specified multiple times to define multiple
|
||||
subnets. Each `subnet` block supports fields documented below.
|
||||
|
||||
The `subnet` block supports:
|
||||
|
||||
* `name` - (Required) The name of the subnet.
|
||||
|
||||
* `address_prefix` - (Required) The address prefix to use for the subnet.
|
||||
|
||||
* `security_group` - (Optional) The Network Security Group to associate with
|
||||
the subnet.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The virtual NetworkConfiguration ID.
|
||||
@ -0,0 +1,30 @@
|
||||
<% wrap_layout :inner do %>
|
||||
<% content_for :sidebar do %>
|
||||
<div class="docs-sidebar hidden-print affix-top" role="complementary">
|
||||
<ul class="nav docs-sidenav">
|
||||
<li<%= sidebar_current("docs-home") %>>
|
||||
<a href="/docs/providers/index.html">« Documentation Home</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azurerm-index") %>>
|
||||
<a href="/docs/providers/azurerm/index.html">Azure Resource Manager Provider</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current(/^docs-azurerm-resource/) %>>
|
||||
<a href="#">Resources</a>
|
||||
<ul class="nav nav-visible">
|
||||
<li<%= sidebar_current("docs-azure-resource-resource-group") %>>
|
||||
<a href="/docs/providers/azurerm/r/resource_group.html">azurerm_resource_group</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-virtual-network") %>>
|
||||
<a href="/docs/providers/azurerm/r/virtual_network.html">azurerm_virtual_network</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= yield %>
|
||||
<% end %>
|
||||
Loading…
Reference in new issue