Merge pull request #2052 from aznashwan/azure
provider/azure: added a number of storage and networking resources.
This commit is contained in:
commit
1ebe117085
|
@ -5,7 +5,7 @@ import (
|
|||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// Config is the configuration structure used to instantiate a
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package azure
|
||||
|
||||
const (
|
||||
// terraformAzureLabel is used as the label for the hosted service created
|
||||
// by Terraform on Azure.
|
||||
terraformAzureLabel = "terraform-on-azure"
|
||||
|
||||
// terraformAzureDescription is the description used for the hosted service
|
||||
// created by Terraform on Azure.
|
||||
terraformAzureDescription = "Hosted service automatically created by terraform."
|
||||
)
|
||||
|
||||
// parameterDescriptions holds a list of descriptions for all the available
|
||||
// parameters of an Azure configuration.
|
||||
var parameterDescriptions = map[string]string{
|
||||
// provider descriptions:
|
||||
"management_url": "The URL of the management API all requests should be sent to.\n" +
|
||||
"Defaults to 'https://management.core.windows.net/', which is the default Azure API URL.\n" +
|
||||
"This should be filled in only if you have your own datacenter with its own hosted management API.",
|
||||
"management_certificate": "The certificate for connecting to the management API specified with 'management_url'",
|
||||
"subscription_id": "The subscription ID to be used when connecting to the management API.",
|
||||
"publish_settings_file": "The publish settings file, either created by you or downloaded from 'https://manage.windowsazure.com/publishsettings'",
|
||||
// general resource descriptions:
|
||||
"name": "Name of the resource to be created as it will appear in the Azure dashboard.",
|
||||
"service_name": "Name of the hosted service within Azure. Will have a DNS entry as dns-name.cloudapp.net",
|
||||
"location": "The Azure location where the resource will be located.\n" +
|
||||
"A list of Azure locations can be found here: http://azure.microsoft.com/en-us/regions/",
|
||||
"reverse_dns_fqdn": "The reverse of the fully qualified domain name. Optional.",
|
||||
"label": "Label by which the resource will be identified by. Optional.",
|
||||
"description": "Brief description of the resource. Optional.",
|
||||
// hosted service descriptions:
|
||||
"ephemeral_contents": "Sets whether the associated contents of this resource should also be\n" +
|
||||
"deleted upon this resource's deletion. Default is false.",
|
||||
// instance descriptions:
|
||||
"image": "The image the new VM will be booted from. Mandatory.",
|
||||
"size": "The size in GB of the disk to be created. Mandatory.",
|
||||
"os_type": "The OS type of the VM. Either Windows or Linux. Mandatory.",
|
||||
"storage_account": "The storage account (pool) name. Mandatory.",
|
||||
"storage_container": "The storage container name from the storage pool given with 'storage_pool'.",
|
||||
"user_name": "The user name to be configured on the new VM.",
|
||||
"user_password": "The user password to be configured on the new VM.",
|
||||
"default_certificate_thumbprint": "The thumbprint of the WinRM Certificate to be used as a default.",
|
||||
// local network descriptions:
|
||||
"vpn_gateway_address": "The IP address of the VPN gateway bridged through this virtual network.",
|
||||
"address_space_prefixes": "List of address space prefixes in the format '<IP>/netmask'",
|
||||
// dns descriptions:
|
||||
"dns_address": "Address of the DNS server. Required.",
|
||||
}
|
|
@ -32,10 +32,18 @@ func Provider() terraform.ResourceProvider {
|
|||
},
|
||||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"azure_data_disk": resourceAzureDataDisk(),
|
||||
"azure_instance": resourceAzureInstance(),
|
||||
"azure_security_group": resourceAzureSecurityGroup(),
|
||||
"azure_virtual_network": resourceAzureVirtualNetwork(),
|
||||
"azure_instance": resourceAzureInstance(),
|
||||
"azure_data_disk": resourceAzureDataDisk(),
|
||||
"azure_hosted_service": resourceAzureHostedService(),
|
||||
"azure_storage_service": resourceAzureStorageService(),
|
||||
"azure_storage_container": resourceAzureStorageContainer(),
|
||||
"azure_storage_blob": resourceAzureStorageBlob(),
|
||||
"azure_storage_queue": resourceAzureStorageQueue(),
|
||||
"azure_virtual_network": resourceAzureVirtualNetwork(),
|
||||
"azure_dns_server": resourceAzureDnsServer(),
|
||||
"azure_local_network_connection": resourceAzureLocalNetworkConnection(),
|
||||
"azure_security_group": resourceAzureSecurityGroup(),
|
||||
"azure_security_group_rule": resourceAzureSecurityGroupRule(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
|
|
|
@ -11,6 +11,18 @@ import (
|
|||
var testAccProviders map[string]terraform.ResourceProvider
|
||||
var testAccProvider *schema.Provider
|
||||
|
||||
const testAccSecurityGroupName = "terraform-security-group"
|
||||
|
||||
// testAccStorageServiceName is used as the name for the Storage Service
|
||||
// created in all storage-related tests.
|
||||
// It is much more convenient to provide a Storage Service which
|
||||
// has been created beforehand as the creation of one takes a lot
|
||||
// and would greatly impede the multitude of tests which rely on one.
|
||||
// NOTE: the storage container should be located in `West US`.
|
||||
var testAccStorageServiceName = os.Getenv("AZURE_STORAGE")
|
||||
|
||||
const testAccStorageContainerName = "terraform-testing-container"
|
||||
|
||||
func init() {
|
||||
testAccProvider = Provider().(*schema.Provider)
|
||||
testAccProviders = map[string]terraform.ResourceProvider{
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
)
|
||||
|
||||
const dataDiskBlobStorageURL = "http://%s.blob.core.windows.net/disks/%s.vhd"
|
||||
|
@ -50,7 +50,7 @@ func resourceAzureDataDisk() *schema.Resource {
|
|||
Default: "None",
|
||||
},
|
||||
|
||||
"storage": &schema.Schema{
|
||||
"storage_service_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
|
@ -321,7 +321,7 @@ func mediaLink(d *schema.ResourceData) string {
|
|||
name = fmt.Sprintf("%s-%d", d.Get("virtual_machine").(string), d.Get("lun").(int))
|
||||
}
|
||||
|
||||
return fmt.Sprintf(dataDiskBlobStorageURL, d.Get("storage").(string), name.(string))
|
||||
return fmt.Sprintf(dataDiskBlobStorageURL, d.Get("storage_service_name").(string), name.(string))
|
||||
}
|
||||
|
||||
func verifyDataDiskParameters(d *schema.ResourceData) error {
|
||||
|
@ -332,7 +332,7 @@ func verifyDataDiskParameters(d *schema.ResourceData) error {
|
|||
}
|
||||
|
||||
if _, ok := d.GetOk("media_link"); !ok {
|
||||
if _, ok := d.GetOk("storage"); !ok {
|
||||
if _, ok := d.GetOk("storage_service_name"); !ok {
|
||||
return fmt.Errorf("If not supplying 'media_link', you must supply 'storage'.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,13 @@ package azure
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/virtualmachinedisk"
|
||||
)
|
||||
|
||||
func TestAccAzureDataDisk_basic(t *testing.T) {
|
||||
|
@ -174,7 +173,7 @@ resource "azure_instance" "foo" {
|
|||
name = "terraform-test"
|
||||
image = "Ubuntu Server 14.04 LTS"
|
||||
size = "Basic_A1"
|
||||
storage = "%s"
|
||||
storage_service_name = "%s"
|
||||
location = "West US"
|
||||
username = "terraform"
|
||||
password = "Pass!admin123"
|
||||
|
@ -183,16 +182,16 @@ resource "azure_instance" "foo" {
|
|||
resource "azure_data_disk" "foo" {
|
||||
lun = 0
|
||||
size = 10
|
||||
storage = "${azure_instance.foo.storage}"
|
||||
storage_service_name = "${azure_instance.foo.storage_service_name}"
|
||||
virtual_machine = "${azure_instance.foo.id}"
|
||||
}`, os.Getenv("AZURE_STORAGE"))
|
||||
}`, testAccStorageServiceName)
|
||||
|
||||
var testAccAzureDataDisk_advanced = fmt.Sprintf(`
|
||||
resource "azure_instance" "foo" {
|
||||
name = "terraform-test1"
|
||||
image = "Ubuntu Server 14.04 LTS"
|
||||
size = "Basic_A1"
|
||||
storage = "%s"
|
||||
storage_service_name = "%s"
|
||||
location = "West US"
|
||||
username = "terraform"
|
||||
password = "Pass!admin123"
|
||||
|
@ -202,16 +201,16 @@ resource "azure_data_disk" "foo" {
|
|||
lun = 1
|
||||
size = 10
|
||||
caching = "ReadOnly"
|
||||
storage = "${azure_instance.foo.storage}"
|
||||
storage_service_name = "${azure_instance.foo.storage_service_name}"
|
||||
virtual_machine = "${azure_instance.foo.id}"
|
||||
}`, os.Getenv("AZURE_STORAGE"))
|
||||
}`, testAccStorageServiceName)
|
||||
|
||||
var testAccAzureDataDisk_update = fmt.Sprintf(`
|
||||
resource "azure_instance" "foo" {
|
||||
name = "terraform-test1"
|
||||
image = "Ubuntu Server 14.04 LTS"
|
||||
size = "Basic_A1"
|
||||
storage = "%s"
|
||||
storage_service_name = "%s"
|
||||
location = "West US"
|
||||
username = "terraform"
|
||||
password = "Pass!admin123"
|
||||
|
@ -221,7 +220,7 @@ resource "azure_instance" "bar" {
|
|||
name = "terraform-test2"
|
||||
image = "Ubuntu Server 14.04 LTS"
|
||||
size = "Basic_A1"
|
||||
storage = "${azure_instance.foo.storage}"
|
||||
storage_service_name = "${azure_instance.foo.storage_service_name}"
|
||||
location = "West US"
|
||||
username = "terraform"
|
||||
password = "Pass!admin123"
|
||||
|
@ -231,6 +230,6 @@ resource "azure_data_disk" "foo" {
|
|||
lun = 2
|
||||
size = 20
|
||||
caching = "ReadWrite"
|
||||
storage = "${azure_instance.bar.storage}"
|
||||
storage_service_name = "${azure_instance.bar.storage_service_name}"
|
||||
virtual_machine = "${azure_instance.bar.id}"
|
||||
}`, os.Getenv("AZURE_STORAGE"))
|
||||
}`, testAccStorageServiceName)
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualnetwork"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureDnsServer returns the *schema.Resource associated
|
||||
// to an Azure hosted service.
|
||||
func resourceAzureDnsServer() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureDnsServerCreate,
|
||||
Read: resourceAzureDnsServerRead,
|
||||
Update: resourceAzureDnsServerUpdate,
|
||||
Exists: resourceAzureDnsServerExists,
|
||||
Delete: resourceAzureDnsServerDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"dns_address": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["dns_address"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureDnsServerCreate does all the necessary API calls
|
||||
// to create a new DNS server definition on Azure.
|
||||
func resourceAzureDnsServerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
// first; check for the existence of the resource:
|
||||
exists, err := resourceAzureDnsServerExists(d, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("Azure DNS server definition already exists.")
|
||||
}
|
||||
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
azureClient.mutex.Lock()
|
||||
defer azureClient.mutex.Unlock()
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
log.Println("[DEBUG] Adding new DNS server definition to Azure.")
|
||||
name := d.Get("name").(string)
|
||||
address := d.Get("dns_address").(string)
|
||||
netConf.Configuration.DNS.DNSServers = append(
|
||||
netConf.Configuration.DNS.DNSServers,
|
||||
virtualnetwork.DNSServer{
|
||||
Name: name,
|
||||
IPAddress: address,
|
||||
})
|
||||
|
||||
// send the configuration back to Azure:
|
||||
log.Println("[INFO] Sending updated network configuration back to Azure.")
|
||||
reqID, err := networkClient.SetVirtualNetworkConfiguration(netConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed issuing update to network configuration: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error setting network configuration: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureDnsServerRead does all the necessary API calls to read
|
||||
// the state of the DNS server off Azure.
|
||||
func resourceAzureDnsServerRead(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
var found bool
|
||||
name := d.Get("name").(string)
|
||||
|
||||
// search for our DNS and update it if the IP has been changed:
|
||||
for _, dns := range netConf.Configuration.DNS.DNSServers {
|
||||
if dns.Name == name {
|
||||
found = true
|
||||
d.Set("dns_address", dns.IPAddress)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// remove the resource from the state if it has been deleted in the meantime:
|
||||
if !found {
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureDnsServerUpdate does all the necessary API calls
|
||||
// to update the DNS definition on Azure.
|
||||
func resourceAzureDnsServerUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
var found bool
|
||||
name := d.Get("name").(string)
|
||||
|
||||
if d.HasChange("dns_address") {
|
||||
log.Println("[DEBUG] DNS server address has changes; updating it on Azure.")
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
azureClient.mutex.Lock()
|
||||
defer azureClient.mutex.Unlock()
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
// search for our DNS and update its address value:
|
||||
for i, dns := range netConf.Configuration.DNS.DNSServers {
|
||||
if dns.Name == name {
|
||||
found = true
|
||||
netConf.Configuration.DNS.DNSServers[i].IPAddress = d.Get("dns_address").(string)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// if the config has changes, send the configuration back to Azure:
|
||||
if found {
|
||||
log.Println("[INFO] Sending updated network configuration back to Azure.")
|
||||
reqID, err := networkClient.SetVirtualNetworkConfiguration(netConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed issuing update to network configuration: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error setting network configuration: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// remove the resource from the state if it has been deleted in the meantime:
|
||||
if !found {
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureDnsServerExists does all the necessary API calls to
|
||||
// check if the DNS server definition alredy exists on Azure.
|
||||
func resourceAzureDnsServerExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
// search for the DNS server's definition:
|
||||
for _, dns := range netConf.Configuration.DNS.DNSServers {
|
||||
if dns.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// if we reached this point; the resource must have been deleted; and we must untrack it:
|
||||
d.SetId("")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// resourceAzureDnsServerDelete does all the necessary API calls
|
||||
// to delete the DNS server definition from Azure.
|
||||
func resourceAzureDnsServerDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
azureClient.mutex.Lock()
|
||||
defer azureClient.mutex.Unlock()
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
// search for the DNS server's definition and remove it:
|
||||
var found bool
|
||||
for i, dns := range netConf.Configuration.DNS.DNSServers {
|
||||
if dns.Name == name {
|
||||
found = true
|
||||
netConf.Configuration.DNS.DNSServers = append(
|
||||
netConf.Configuration.DNS.DNSServers[:i],
|
||||
netConf.Configuration.DNS.DNSServers[i+1:]...,
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// if not found; don't bother re-sending the natwork config:
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
// send the configuration back to Azure:
|
||||
log.Println("[INFO] Sending updated network configuration back to Azure.")
|
||||
reqID, err := networkClient.SetVirtualNetworkConfiguration(netConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed issuing update to network configuration: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error setting network configuration: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualnetwork"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureDnsServerBasic(t *testing.T) {
|
||||
name := "azure_dns_server.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureDnsServerDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureDnsServerBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureDnsServerExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-dns-server"),
|
||||
resource.TestCheckResourceAttr(name, "dns_address", "8.8.8.8"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAzureDnsServerUpdate(t *testing.T) {
|
||||
name := "azure_dns_server.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureDnsServerDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureDnsServerBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureDnsServerExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-dns-server"),
|
||||
resource.TestCheckResourceAttr(name, "dns_address", "8.8.8.8"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAzureDnsServerUpdate,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureDnsServerExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-dns-server"),
|
||||
resource.TestCheckResourceAttr(name, "dns_address", "8.8.4.4"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAzureDnsServerExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Resource not found: %s", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("No DNS Server ID set.")
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
netConf, err := virtualnetwork.NewClient(mgmtClient).GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed fetching networking configuration: %s", err)
|
||||
}
|
||||
|
||||
for _, dns := range netConf.Configuration.DNS.DNSServers {
|
||||
if dns.Name == resource.Primary.ID {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Azure DNS Server not found.")
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureDnsServerDestroy(s *terraform.State) error {
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_dns_server" {
|
||||
continue
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("No DNS Server ID is set.")
|
||||
}
|
||||
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving networking configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
for _, dns := range netConf.Configuration.DNS.DNSServers {
|
||||
if dns.Name == resource.Primary.ID {
|
||||
return fmt.Errorf("Azure DNS Server still exists.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const testAccAzureDnsServerBasic = `
|
||||
resource "azure_dns_server" "foo" {
|
||||
name = "terraform-dns-server"
|
||||
dns_address = "8.8.8.8"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAzureDnsServerUpdate = `
|
||||
resource "azure_dns_server" "foo" {
|
||||
name = "terraform-dns-server"
|
||||
dns_address = "8.8.4.4"
|
||||
}
|
||||
`
|
|
@ -0,0 +1,171 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureHostedService returns the schema.Resource associated to an
|
||||
// Azure hosted service.
|
||||
func resourceAzureHostedService() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureHostedServiceCreate,
|
||||
Read: resourceAzureHostedServiceRead,
|
||||
Update: resourceAzureHostedServiceUpdate,
|
||||
Delete: resourceAzureHostedServiceDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"location": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["location"],
|
||||
},
|
||||
"ephemeral_contents": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["ephemeral_contents"],
|
||||
},
|
||||
"url": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"status": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"reverse_dns_fqdn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: parameterDescriptions["reverse_dns_fqdn"],
|
||||
},
|
||||
"label": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
Default: "Made by Terraform.",
|
||||
Description: parameterDescriptions["label"],
|
||||
},
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
Description: parameterDescriptions["description"],
|
||||
},
|
||||
"default_certificate_thumbprint": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
Description: parameterDescriptions["default_certificate_thumbprint"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureHostedServiceCreate does all the necessary API calls
|
||||
// to create a hosted service on Azure.
|
||||
func resourceAzureHostedServiceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
hostedServiceClient := hostedservice.NewClient(mgmtClient)
|
||||
|
||||
serviceName := d.Get("name").(string)
|
||||
location := d.Get("location").(string)
|
||||
reverseDNS := d.Get("reverse_dns_fqdn").(string)
|
||||
description := d.Get("description").(string)
|
||||
label := base64.StdEncoding.EncodeToString([]byte(d.Get("label").(string)))
|
||||
|
||||
err := hostedServiceClient.CreateHostedService(
|
||||
hostedservice.CreateHostedServiceParameters{
|
||||
ServiceName: serviceName,
|
||||
Location: location,
|
||||
Label: label,
|
||||
Description: description,
|
||||
ReverseDNSFqdn: reverseDNS,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed defining new Azure hosted service: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(serviceName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureHostedServiceRead does all the necessary API calls
|
||||
// to read the state of a hosted service from Azure.
|
||||
func resourceAzureHostedServiceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
hostedServiceClient := hostedservice.NewClient(azureClient.mgmtClient)
|
||||
|
||||
log.Println("[INFO] Querying for hosted service info.")
|
||||
serviceName := d.Get("name").(string)
|
||||
hostedService, err := hostedServiceClient.GetHostedService(serviceName)
|
||||
if err != nil {
|
||||
if management.IsResourceNotFoundError(err) {
|
||||
// it means the hosted service was deleted in the meantime,
|
||||
// so we must remove it here:
|
||||
d.SetId("")
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Failed to get hosted service: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("[DEBUG] Reading hosted service query result data.")
|
||||
d.Set("name", hostedService.ServiceName)
|
||||
d.Set("url", hostedService.URL)
|
||||
d.Set("location", hostedService.Location)
|
||||
d.Set("description", hostedService.Description)
|
||||
d.Set("label", hostedService.Label)
|
||||
d.Set("status", hostedService.Status)
|
||||
d.Set("reverse_dns_fqdn", hostedService.ReverseDNSFqdn)
|
||||
d.Set("default_certificate_thumbprint", hostedService.DefaultWinRmCertificateThumbprint)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureHostedServiceUpdate does all the necessary API calls to
|
||||
// update some settings of a hosted service on Azure.
|
||||
func resourceAzureHostedServiceUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
// NOTE: although no-op; this is still required in order for updates to
|
||||
// ephemeral_contents to be possible.
|
||||
|
||||
// check if the service still exists:
|
||||
return resourceAzureHostedServiceRead(d, meta)
|
||||
}
|
||||
|
||||
// resourceAzureHostedServiceDelete does all the necessary API calls to
|
||||
// delete a hosted service from Azure.
|
||||
func resourceAzureHostedServiceDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
hostedServiceClient := hostedservice.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Issuing hosted service deletion.")
|
||||
serviceName := d.Get("name").(string)
|
||||
ephemeral := d.Get("ephemeral_contents").(bool)
|
||||
reqID, err := hostedServiceClient.DeleteHostedService(serviceName, ephemeral)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed issuing hosted service deletion request: %s", err)
|
||||
}
|
||||
|
||||
log.Println("[DEBUG] Awaiting confirmation on hosted service deletion.")
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error on hosted service deletion: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureHostedServiceBasic(t *testing.T) {
|
||||
name := "azure_hosted_service.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureHostedServiceDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureHostedServiceBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureHostedServiceExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-testing-service"),
|
||||
resource.TestCheckResourceAttr(name, "location", "North Europe"),
|
||||
resource.TestCheckResourceAttr(name, "ephemeral_contents", "false"),
|
||||
resource.TestCheckResourceAttr(name, "description", "very discriptive"),
|
||||
resource.TestCheckResourceAttr(name, "label", "very identifiable"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAzureHostedServiceUpdate(t *testing.T) {
|
||||
name := "azure_hosted_service.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureHostedServiceDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureHostedServiceBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureHostedServiceExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-testing-service"),
|
||||
resource.TestCheckResourceAttr(name, "location", "North Europe"),
|
||||
resource.TestCheckResourceAttr(name, "ephemeral_contents", "false"),
|
||||
resource.TestCheckResourceAttr(name, "description", "very discriptive"),
|
||||
resource.TestCheckResourceAttr(name, "label", "very identifiable"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAzureHostedServiceUpdate,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureHostedServiceExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-testing-service"),
|
||||
resource.TestCheckResourceAttr(name, "location", "North Europe"),
|
||||
resource.TestCheckResourceAttr(name, "ephemeral_contents", "true"),
|
||||
resource.TestCheckResourceAttr(name, "description", "very discriptive"),
|
||||
resource.TestCheckResourceAttr(name, "label", "very identifiable"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAzureHostedServiceExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Hosted Service resource not found.")
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Resource's ID is not set.")
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
_, err := hostedservice.NewClient(mgmtClient).GetHostedService(resource.Primary.ID)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureHostedServiceDestroyed(s *terraform.State) error {
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_hosted_service" {
|
||||
continue
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("No Azure Hosted Service Resource found.")
|
||||
}
|
||||
|
||||
_, err := hostedservice.NewClient(mgmtClient).GetHostedService(resource.Primary.ID)
|
||||
|
||||
return testAccResourceDestroyedErrorFilter("Hosted Service", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const testAccAzureHostedServiceBasic = `
|
||||
resource "azure_hosted_service" "foo" {
|
||||
name = "terraform-testing-service"
|
||||
location = "North Europe"
|
||||
ephemeral_contents = false
|
||||
description = "very discriptive"
|
||||
label = "very identifiable"
|
||||
}
|
||||
`
|
||||
const testAccAzureHostedServiceUpdate = `
|
||||
resource "azure_hosted_service" "foo" {
|
||||
name = "terraform-testing-service"
|
||||
location = "North Europe"
|
||||
ephemeral_contents = true
|
||||
description = "very discriptive"
|
||||
label = "very identifiable"
|
||||
}
|
||||
`
|
|
@ -7,14 +7,14 @@ import (
|
|||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/Azure/azure-sdk-for-go/management/osimage"
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualmachineimage"
|
||||
"github.com/Azure/azure-sdk-for-go/management/vmutils"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/osimage"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/virtualmachine"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/virtualmachineimage"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/vmutils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -68,7 +68,7 @@ func resourceAzureInstance() *schema.Resource {
|
|||
ForceNew: true,
|
||||
},
|
||||
|
||||
"storage": &schema.Schema{
|
||||
"storage_service_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
|
@ -183,7 +183,7 @@ func resourceAzureInstanceCreate(d *schema.ResourceData, meta interface{}) (err
|
|||
mc,
|
||||
d.Get("image").(string),
|
||||
name,
|
||||
d.Get("storage").(string),
|
||||
d.Get("storage_service_name").(string),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -2,14 +2,13 @@ package azure
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualmachine"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/virtualmachine"
|
||||
)
|
||||
|
||||
func TestAccAzureInstance_basic(t *testing.T) {
|
||||
|
@ -313,7 +312,7 @@ resource "azure_instance" "foo" {
|
|||
name = "terraform-test"
|
||||
image = "Ubuntu Server 14.04 LTS"
|
||||
size = "Basic_A1"
|
||||
storage = "%s"
|
||||
storage_service_name = "%s"
|
||||
location = "West US"
|
||||
username = "terraform"
|
||||
password = "Pass!admin123"
|
||||
|
@ -324,7 +323,7 @@ resource "azure_instance" "foo" {
|
|||
public_port = 22
|
||||
private_port = 22
|
||||
}
|
||||
}`, os.Getenv("AZURE_STORAGE"))
|
||||
}`, testAccStorageServiceName)
|
||||
|
||||
var testAccAzureInstance_advanced = fmt.Sprintf(`
|
||||
resource "azure_virtual_network" "foo" {
|
||||
|
@ -346,23 +345,26 @@ resource "azure_virtual_network" "foo" {
|
|||
resource "azure_security_group" "foo" {
|
||||
name = "terraform-security-group1"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
rule {
|
||||
name = "rdp"
|
||||
priority = 101
|
||||
source_cidr = "*"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = 3389
|
||||
protocol = "TCP"
|
||||
}
|
||||
resource "azure_security_group_rule" "foo" {
|
||||
name = "rdp"
|
||||
security_group_name = "${azure_security_group.foo.name}"
|
||||
priority = 101
|
||||
source_address_prefix = "*"
|
||||
source_port_range = "*"
|
||||
destination_address_prefix = "*"
|
||||
destination_port_range = "3389"
|
||||
action = "Deny"
|
||||
type = "Inbound"
|
||||
protocol = "TCP"
|
||||
}
|
||||
|
||||
resource "azure_instance" "foo" {
|
||||
name = "terraform-test1"
|
||||
image = "Windows Server 2012 R2 Datacenter, April 2015"
|
||||
size = "Basic_A1"
|
||||
storage = "%s"
|
||||
storage_service_name = "%s"
|
||||
location = "West US"
|
||||
time_zone = "America/Los_Angeles"
|
||||
subnet = "subnet1"
|
||||
|
@ -377,7 +379,7 @@ resource "azure_instance" "foo" {
|
|||
public_port = 3389
|
||||
private_port = 3389
|
||||
}
|
||||
}`, os.Getenv("AZURE_STORAGE"))
|
||||
}`, testAccStorageServiceName)
|
||||
|
||||
var testAccAzureInstance_update = fmt.Sprintf(`
|
||||
resource "azure_virtual_network" "foo" {
|
||||
|
@ -385,52 +387,58 @@ resource "azure_virtual_network" "foo" {
|
|||
address_space = ["10.1.2.0/24"]
|
||||
location = "West US"
|
||||
|
||||
subnet {
|
||||
subnet {
|
||||
name = "subnet1"
|
||||
address_prefix = "10.1.2.0/25"
|
||||
}
|
||||
address_prefix = "10.1.2.0/25"
|
||||
}
|
||||
|
||||
subnet {
|
||||
subnet {
|
||||
name = "subnet2"
|
||||
address_prefix = "10.1.2.128/25"
|
||||
address_prefix = "10.1.2.128/25"
|
||||
}
|
||||
}
|
||||
|
||||
resource "azure_security_group" "foo" {
|
||||
name = "terraform-security-group1"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
rule {
|
||||
name = "rdp"
|
||||
priority = 101
|
||||
source_cidr = "*"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = 3389
|
||||
protocol = "TCP"
|
||||
}
|
||||
resource "azure_security_group_rule" "foo" {
|
||||
name = "rdp"
|
||||
security_group_name = "${azure_security_group.foo.name}"
|
||||
priority = 101
|
||||
source_address_prefix = "*"
|
||||
source_port_range = "*"
|
||||
destination_address_prefix = "*"
|
||||
destination_port_range = "3389"
|
||||
type = "Inbound"
|
||||
action = "Deny"
|
||||
protocol = "TCP"
|
||||
}
|
||||
|
||||
resource "azure_security_group" "bar" {
|
||||
name = "terraform-security-group2"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
rule {
|
||||
name = "rdp"
|
||||
priority = 101
|
||||
source_cidr = "192.168.0.0/24"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = 3389
|
||||
protocol = "TCP"
|
||||
}
|
||||
resource "azure_security_group_rule" "bar" {
|
||||
name = "rdp"
|
||||
security_group_name = "${azure_security_group.bar.name}"
|
||||
priority = 101
|
||||
source_address_prefix = "192.168.0.0/24"
|
||||
source_port_range = "*"
|
||||
destination_address_prefix = "*"
|
||||
destination_port_range = "3389"
|
||||
type = "Inbound"
|
||||
action = "Deny"
|
||||
protocol = "TCP"
|
||||
}
|
||||
|
||||
resource "azure_instance" "foo" {
|
||||
name = "terraform-test1"
|
||||
image = "Windows Server 2012 R2 Datacenter, April 2015"
|
||||
size = "Basic_A2"
|
||||
storage = "%s"
|
||||
storage_service_name = "%s"
|
||||
location = "West US"
|
||||
time_zone = "America/Los_Angeles"
|
||||
subnet = "subnet1"
|
||||
|
@ -452,4 +460,4 @@ resource "azure_instance" "foo" {
|
|||
public_port = 5985
|
||||
private_port = 5985
|
||||
}
|
||||
}`, os.Getenv("AZURE_STORAGE"))
|
||||
}`, testAccStorageServiceName)
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualnetwork"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureLocalNetworkConnetion returns the schema.Resource associated to an
|
||||
// Azure hosted service.
|
||||
func resourceAzureLocalNetworkConnection() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureLocalNetworkConnectionCreate,
|
||||
Read: resourceAzureLocalNetworkConnectionRead,
|
||||
Update: resourceAzureLocalNetworkConnectionUpdate,
|
||||
Exists: resourceAzureLocalNetworkConnectionExists,
|
||||
Delete: resourceAzureLocalNetworkConnectionDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"vpn_gateway_address": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["vpn_gateway_address"],
|
||||
},
|
||||
"address_space_prefixes": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Required: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
Description: parameterDescriptions["address_space_prefixes"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// sourceAzureLocalNetworkConnectionCreate issues all the necessary API calls
|
||||
// to create a virtual network on Azure.
|
||||
func resourceAzureLocalNetworkConnectionCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
azureClient.mutex.Lock()
|
||||
defer azureClient.mutex.Unlock()
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
// get provided configuration:
|
||||
name := d.Get("name").(string)
|
||||
vpnGateway := d.Get("vpn_gateway_address").(string)
|
||||
var prefixes []string
|
||||
for _, prefix := range d.Get("address_space_prefixes").([]interface{}) {
|
||||
prefixes = append(prefixes, prefix.(string))
|
||||
}
|
||||
|
||||
// add configuration to network config:
|
||||
netConf.Configuration.LocalNetworkSites = append(netConf.Configuration.LocalNetworkSites,
|
||||
virtualnetwork.LocalNetworkSite{
|
||||
Name: name,
|
||||
VPNGatewayAddress: vpnGateway,
|
||||
AddressSpace: virtualnetwork.AddressSpace{
|
||||
AddressPrefix: prefixes,
|
||||
},
|
||||
})
|
||||
|
||||
// send the configuration back to Azure:
|
||||
log.Println("[INFO] Sending updated network configuration back to Azure.")
|
||||
reqID, err := networkClient.SetVirtualNetworkConfiguration(netConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed setting updated network configuration: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed updating the network configuration: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureLocalNetworkConnectionRead does all the necessary API calls to
|
||||
// read the state of our local natwork from Azure.
|
||||
func resourceAzureLocalNetworkConnectionRead(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
var found bool
|
||||
name := d.Get("name").(string)
|
||||
|
||||
// browsing for our network config:
|
||||
for _, lnet := range netConf.Configuration.LocalNetworkSites {
|
||||
if lnet.Name == name {
|
||||
found = true
|
||||
d.Set("vpn_gateway_address", lnet.VPNGatewayAddress)
|
||||
d.Set("address_space_prefixes", lnet.AddressSpace.AddressPrefix)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// remove the resource from the state of it has been deleted in the meantime:
|
||||
if !found {
|
||||
log.Println(fmt.Printf("[INFO] Azure local network '%s' has been deleted remotely. Removimg from Terraform.", name))
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureLocalNetworkConnectionUpdate does all the necessary API calls
|
||||
// update the settings of our Local Network on Azure.
|
||||
func resourceAzureLocalNetworkConnectionUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
azureClient.mutex.Lock()
|
||||
defer azureClient.mutex.Unlock()
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
cvpn := d.HasChange("vpn_gateway_address")
|
||||
cprefixes := d.HasChange("address_space_prefixes")
|
||||
|
||||
var found bool
|
||||
for i, lnet := range netConf.Configuration.LocalNetworkSites {
|
||||
if lnet.Name == name {
|
||||
found = true
|
||||
if cvpn {
|
||||
netConf.Configuration.LocalNetworkSites[i].VPNGatewayAddress = d.Get("vpn_gateway_address").(string)
|
||||
}
|
||||
if cprefixes {
|
||||
var prefixes []string
|
||||
for _, prefix := range d.Get("address_space_prefixes").([]interface{}) {
|
||||
prefixes = append(prefixes, prefix.(string))
|
||||
}
|
||||
netConf.Configuration.LocalNetworkSites[i].AddressSpace.AddressPrefix = prefixes
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// remove the resource from the state of it has been deleted in the meantime:
|
||||
if !found {
|
||||
log.Println(fmt.Printf("[INFO] Azure local network '%s' has been deleted remotely. Removimg from Terraform.", name))
|
||||
d.SetId("")
|
||||
} else if cvpn || cprefixes {
|
||||
// else, send the configuration back to Azure:
|
||||
log.Println("[INFO] Sending updated network configuration back to Azure.")
|
||||
reqID, err := networkClient.SetVirtualNetworkConfiguration(netConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed setting updated network configuration: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed updating the network configuration: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureLocalNetworkConnectionExists does all the necessary API calls
|
||||
// to check if the local network already exists on Azure.
|
||||
func resourceAzureLocalNetworkConnectionExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
name := d.Get("name")
|
||||
|
||||
for _, lnet := range netConf.Configuration.LocalNetworkSites {
|
||||
if lnet.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// resourceAzureLocalNetworkConnectionDelete does all the necessary API calls
|
||||
// to delete a local network off Azure.
|
||||
func resourceAzureLocalNetworkConnectionDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
networkClient := virtualnetwork.NewClient(mgmtClient)
|
||||
|
||||
log.Println("[INFO] Fetching current network configuration from Azure.")
|
||||
azureClient.mutex.Lock()
|
||||
defer azureClient.mutex.Unlock()
|
||||
netConf, err := networkClient.GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get the current network configuration from Azure: %s", err)
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
// search for our local network and remove it if found:
|
||||
for i, lnet := range netConf.Configuration.LocalNetworkSites {
|
||||
if lnet.Name == name {
|
||||
netConf.Configuration.LocalNetworkSites = append(
|
||||
netConf.Configuration.LocalNetworkSites[:i],
|
||||
netConf.Configuration.LocalNetworkSites[i+1:]...,
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// send the configuration back to Azure:
|
||||
log.Println("[INFO] Sending updated network configuration back to Azure.")
|
||||
reqID, err := networkClient.SetVirtualNetworkConfiguration(netConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed setting updated network configuration: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed updating the network configuration: %s", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualnetwork"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureLocalNetworkConnectionBasic(t *testing.T) {
|
||||
name := "azure_local_network_connection.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccAzureLocalNetworkConnectionDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureLocalNetworkConnectionBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccAzureLocalNetworkConnectionExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-local-network-connection"),
|
||||
resource.TestCheckResourceAttr(name, "vpn_gateway_address", "10.11.12.13"),
|
||||
resource.TestCheckResourceAttr(name, "address_space_prefixes.0", "10.10.10.0/31"),
|
||||
resource.TestCheckResourceAttr(name, "address_space_prefixes.1", "10.10.10.1/31"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAzureLocalNetworkConnectionUpdate(t *testing.T) {
|
||||
name := "azure_local_network_connection.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccAzureLocalNetworkConnectionDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureLocalNetworkConnectionBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccAzureLocalNetworkConnectionExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-local-network-connection"),
|
||||
resource.TestCheckResourceAttr(name, "vpn_gateway_address", "10.11.12.13"),
|
||||
resource.TestCheckResourceAttr(name, "address_space_prefixes.0", "10.10.10.0/31"),
|
||||
resource.TestCheckResourceAttr(name, "address_space_prefixes.1", "10.10.10.1/31"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAzureLocalNetworkConnectionUpdate,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccAzureLocalNetworkConnectionExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-local-network-connection"),
|
||||
resource.TestCheckResourceAttr(name, "vpn_gateway_address", "10.11.12.14"),
|
||||
resource.TestCheckResourceAttr(name, "address_space_prefixes.0", "10.10.10.2/30"),
|
||||
resource.TestCheckResourceAttr(name, "address_space_prefixes.1", "10.10.10.3/30"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// testAccAzureLocalNetworkConnectionExists checks whether the given local network
|
||||
// connection exists on Azure.
|
||||
func testAccAzureLocalNetworkConnectionExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Azure Local Network Connection not found: %s", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Local Network Connection ID not set.")
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
netConf, err := virtualnetwork.NewClient(mgmtClient).GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, lnet := range netConf.Configuration.LocalNetworkSites {
|
||||
if lnet.Name == resource.Primary.ID {
|
||||
return nil
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return fmt.Errorf("Local Network Connection not found: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
// testAccAzureLocalNetworkConnectionDestroyed checks whether the local network
|
||||
// connection has been destroyed on Azure or not.
|
||||
func testAccAzureLocalNetworkConnectionDestroyed(s *terraform.State) error {
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_local_network_connection" {
|
||||
continue
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Local Network Connection ID not set.")
|
||||
}
|
||||
|
||||
netConf, err := virtualnetwork.NewClient(mgmtClient).GetVirtualNetworkConfiguration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, lnet := range netConf.Configuration.LocalNetworkSites {
|
||||
if lnet.Name == resource.Primary.ID {
|
||||
return fmt.Errorf("Azure Local Network Connection still exists.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const testAccAzureLocalNetworkConnectionBasic = `
|
||||
resource "azure_local_network_connection" "foo" {
|
||||
name = "terraform-local-network-connection"
|
||||
vpn_gateway_address = "10.11.12.13"
|
||||
address_space_prefixes = ["10.10.10.0/31", "10.10.10.1/31"]
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAzureLocalNetworkConnectionUpdate = `
|
||||
resource "azure_local_network_connection" "foo" {
|
||||
name = "terraform-local-network-connection"
|
||||
vpn_gateway_address = "10.11.12.14"
|
||||
address_space_prefixes = ["10.10.10.2/30", "10.10.10.3/30"]
|
||||
}
|
||||
`
|
|
@ -1,22 +1,18 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/networksecuritygroup"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/networksecuritygroup"
|
||||
)
|
||||
|
||||
func resourceAzureSecurityGroup() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureSecurityGroupCreate,
|
||||
Read: resourceAzureSecurityGroupRead,
|
||||
Update: resourceAzureSecurityGroupUpdate,
|
||||
Delete: resourceAzureSecurityGroupDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
|
@ -38,63 +34,6 @@ func resourceAzureSecurityGroup() *schema.Resource {
|
|||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"rule": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "Inbound",
|
||||
},
|
||||
|
||||
"priority": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"action": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "Allow",
|
||||
},
|
||||
|
||||
"source_cidr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"source_port": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"destination_cidr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"destination_port": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"protocol": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "TCP",
|
||||
},
|
||||
},
|
||||
},
|
||||
Set: resourceAzureSecurityGroupRuleHash,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -126,70 +65,9 @@ func resourceAzureSecurityGroupCreate(d *schema.ResourceData, meta interface{})
|
|||
|
||||
d.SetId(name)
|
||||
|
||||
// Create all rules that are configured
|
||||
if rs := d.Get("rule").(*schema.Set); rs.Len() > 0 {
|
||||
|
||||
// Create an empty schema.Set to hold all rules
|
||||
rules := &schema.Set{
|
||||
F: resourceAzureSecurityGroupRuleHash,
|
||||
}
|
||||
|
||||
for _, rule := range rs.List() {
|
||||
// Create a single rule
|
||||
err := resourceAzureSecurityGroupRuleCreate(d, meta, rule.(map[string]interface{}))
|
||||
|
||||
// We need to update this first to preserve the correct state
|
||||
rules.Add(rule)
|
||||
d.Set("rule", rules)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resourceAzureSecurityGroupRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAzureSecurityGroupRuleCreate(
|
||||
d *schema.ResourceData,
|
||||
meta interface{},
|
||||
rule map[string]interface{}) error {
|
||||
mc := meta.(*Client).mgmtClient
|
||||
|
||||
// Make sure all required parameters are there
|
||||
if err := verifySecurityGroupRuleParams(rule); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := rule["name"].(string)
|
||||
|
||||
// Create the rule
|
||||
req, err := networksecuritygroup.NewClient(mc).SetNetworkSecurityGroupRule(d.Id(),
|
||||
networksecuritygroup.RuleRequest{
|
||||
Name: name,
|
||||
Type: networksecuritygroup.RuleType(rule["type"].(string)),
|
||||
Priority: rule["priority"].(int),
|
||||
Action: networksecuritygroup.RuleAction(rule["action"].(string)),
|
||||
SourceAddressPrefix: rule["source_cidr"].(string),
|
||||
SourcePortRange: rule["source_port"].(string),
|
||||
DestinationAddressPrefix: rule["destination_cidr"].(string),
|
||||
DestinationPortRange: rule["destination_port"].(string),
|
||||
Protocol: networksecuritygroup.RuleProtocol(rule["protocol"].(string)),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Network Security Group rule %s: %s", name, err)
|
||||
}
|
||||
|
||||
if err := mc.WaitForOperation(req, nil); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error waiting for Network Security Group rule %s to be created: %s", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAzureSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
|
||||
mc := meta.(*Client).mgmtClient
|
||||
|
||||
|
@ -205,70 +83,9 @@ func resourceAzureSecurityGroupRead(d *schema.ResourceData, meta interface{}) er
|
|||
d.Set("label", sg.Label)
|
||||
d.Set("location", sg.Location)
|
||||
|
||||
// Create an empty schema.Set to hold all rules
|
||||
rules := &schema.Set{
|
||||
F: resourceAzureSecurityGroupRuleHash,
|
||||
}
|
||||
|
||||
for _, r := range sg.Rules {
|
||||
if !r.IsDefault {
|
||||
rule := map[string]interface{}{
|
||||
"name": r.Name,
|
||||
"type": string(r.Type),
|
||||
"priority": r.Priority,
|
||||
"action": string(r.Action),
|
||||
"source_cidr": r.SourceAddressPrefix,
|
||||
"source_port": r.SourcePortRange,
|
||||
"destination_cidr": r.DestinationAddressPrefix,
|
||||
"destination_port": r.DestinationPortRange,
|
||||
"protocol": string(r.Protocol),
|
||||
}
|
||||
rules.Add(rule)
|
||||
}
|
||||
}
|
||||
|
||||
d.Set("rule", rules)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAzureSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
// Check if the rule set as a whole has changed
|
||||
if d.HasChange("rule") {
|
||||
o, n := d.GetChange("rule")
|
||||
ors := o.(*schema.Set).Difference(n.(*schema.Set))
|
||||
nrs := n.(*schema.Set).Difference(o.(*schema.Set))
|
||||
|
||||
// Now first loop through all the old rules and delete any obsolete ones
|
||||
for _, rule := range ors.List() {
|
||||
// Delete the rule as it no longer exists in the config
|
||||
err := resourceAzureSecurityGroupRuleDelete(d, meta, rule.(map[string]interface{}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we save the state of the currently configured rules
|
||||
rules := o.(*schema.Set).Intersection(n.(*schema.Set))
|
||||
d.Set("rule", rules)
|
||||
|
||||
// Then loop through al the currently configured rules and create the new ones
|
||||
for _, rule := range nrs.List() {
|
||||
err := resourceAzureSecurityGroupRuleCreate(d, meta, rule.(map[string]interface{}))
|
||||
|
||||
// We need to update this first to preserve the correct state
|
||||
rules.Add(rule)
|
||||
d.Set("rule", rules)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resourceAzureSecurityGroupRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAzureSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
mc := meta.(*Client).mgmtClient
|
||||
|
||||
|
@ -288,66 +105,3 @@ func resourceAzureSecurityGroupDelete(d *schema.ResourceData, meta interface{})
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAzureSecurityGroupRuleDelete(
|
||||
d *schema.ResourceData, meta interface{}, rule map[string]interface{}) error {
|
||||
mc := meta.(*Client).mgmtClient
|
||||
|
||||
name := rule["name"].(string)
|
||||
|
||||
// Delete the rule
|
||||
req, err := networksecuritygroup.NewClient(mc).DeleteNetworkSecurityGroupRule(d.Id(), name)
|
||||
if err != nil {
|
||||
if management.IsResourceNotFoundError(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error deleting Network Security Group rule %s: %s", name, err)
|
||||
}
|
||||
|
||||
if err := mc.WaitForOperation(req, nil); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error waiting for Network Security Group rule %s to be deleted: %s", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAzureSecurityGroupRuleHash(v interface{}) int {
|
||||
var buf bytes.Buffer
|
||||
m := v.(map[string]interface{})
|
||||
buf.WriteString(fmt.Sprintf(
|
||||
"%s-%d-%s-%s-%s-%s-%s-%s",
|
||||
m["type"].(string),
|
||||
m["priority"].(int),
|
||||
m["action"].(string),
|
||||
m["source_cidr"].(string),
|
||||
m["source_port"].(string),
|
||||
m["destination_cidr"].(string),
|
||||
m["destination_port"].(string),
|
||||
m["protocol"].(string)))
|
||||
|
||||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
func verifySecurityGroupRuleParams(rule map[string]interface{}) error {
|
||||
typ := rule["type"].(string)
|
||||
if typ != "Inbound" && typ != "Outbound" {
|
||||
return fmt.Errorf("Parameter type only accepts 'Inbound' or 'Outbound' as values")
|
||||
}
|
||||
|
||||
action := rule["action"].(string)
|
||||
if action != "Allow" && action != "Deny" {
|
||||
return fmt.Errorf("Parameter action only accepts 'Allow' or 'Deny' as values")
|
||||
}
|
||||
|
||||
protocol := rule["protocol"].(string)
|
||||
if protocol != "TCP" && protocol != "UDP" && protocol != "*" {
|
||||
_, err := strconv.ParseInt(protocol, 0, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Parameter type only accepts 'TCP', 'UDP' or '*' as values")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
netsecgroup "github.com/Azure/azure-sdk-for-go/management/networksecuritygroup"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureSecurityGroupRule returns the *schema.Resource for
|
||||
// a network security group rule on Azure.
|
||||
func resourceAzureSecurityGroupRule() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureSecurityGroupRuleCreate,
|
||||
Read: resourceAzureSecurityGroupRuleRead,
|
||||
Update: resourceAzureSecurityGroupRuleUpdate,
|
||||
Exists: resourceAzureSecurityGroupRuleExists,
|
||||
Delete: resourceAzureSecurityGroupRuleDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"security_group_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["netsecgroup_secgroup_name"],
|
||||
},
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_type"],
|
||||
},
|
||||
"priority": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_priority"],
|
||||
},
|
||||
"action": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_action"],
|
||||
},
|
||||
"source_address_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_src_addr_prefix"],
|
||||
},
|
||||
"source_port_range": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_src_port_range"],
|
||||
},
|
||||
"destination_address_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_dest_addr_prefix"],
|
||||
},
|
||||
"destination_port_range": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_dest_port_range"],
|
||||
},
|
||||
"protocol": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_protocol"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureSecurityGroupRuleCreate does all the necessary API calls to
|
||||
// create a new network security group rule on Azure.
|
||||
func resourceAzureSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
netSecClient := netsecgroup.NewClient(mgmtClient)
|
||||
|
||||
// create and configure the RuleResponse:
|
||||
name := d.Get("name").(string)
|
||||
rule := netsecgroup.RuleRequest{
|
||||
Name: name,
|
||||
Type: netsecgroup.RuleType(d.Get("type").(string)),
|
||||
Priority: d.Get("priority").(int),
|
||||
Action: netsecgroup.RuleAction(d.Get("action").(string)),
|
||||
SourceAddressPrefix: d.Get("source_address_prefix").(string),
|
||||
SourcePortRange: d.Get("source_port_range").(string),
|
||||
DestinationAddressPrefix: d.Get("destination_address_prefix").(string),
|
||||
DestinationPortRange: d.Get("destination_port_range").(string),
|
||||
Protocol: netsecgroup.RuleProtocol(d.Get("protocol").(string)),
|
||||
}
|
||||
|
||||
// send the create request to Azure:
|
||||
log.Println("[INFO] Sending network security group rule creation request to Azure.")
|
||||
reqID, err := netSecClient.SetNetworkSecurityGroupRule(
|
||||
d.Get("security_group_name").(string),
|
||||
rule,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error sending network security group rule creation request to Azure: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating network security group rule on Azure: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureSecurityGroupRuleRead does all the necessary API calls to
|
||||
// read the state of a network security group ruke off Azure.
|
||||
func resourceAzureSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
netSecClient := netsecgroup.NewClient(mgmtClient)
|
||||
|
||||
secGroupName := d.Get("security_group_name").(string)
|
||||
|
||||
// get info on the network security group and check its rules for this one:
|
||||
log.Println("[INFO] Sending network security group rule query to Azure.")
|
||||
secgroup, err := netSecClient.GetNetworkSecurityGroup(secGroupName)
|
||||
if err != nil {
|
||||
if !management.IsResourceNotFoundError(err) {
|
||||
return fmt.Errorf("Error issuing network security group rules query: %s", err)
|
||||
} else {
|
||||
// it meants that the network security group this rule belonged to has
|
||||
// been deleted; so we must remove this resource from the schema:
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// find our security rule:
|
||||
var found bool
|
||||
name := d.Get("name").(string)
|
||||
for _, rule := range secgroup.Rules {
|
||||
if rule.Name == name {
|
||||
found = true
|
||||
log.Println("[DEBUG] Reading state of Azure network security group rule.")
|
||||
|
||||
d.Set("type", rule.Type)
|
||||
d.Set("priority", rule.Priority)
|
||||
d.Set("action", rule.Action)
|
||||
d.Set("source_address_prefix", rule.SourceAddressPrefix)
|
||||
d.Set("source_port_range", rule.SourcePortRange)
|
||||
d.Set("destination_address_prefix", rule.DestinationAddressPrefix)
|
||||
d.Set("destination_port_range", rule.DestinationPortRange)
|
||||
d.Set("protocol", rule.Protocol)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// check if the rule still exists, and is not, remove the resource:
|
||||
if !found {
|
||||
d.SetId("")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureSecurityGroupRuleUpdate does all the necessary API calls to
|
||||
// update the state of a network security group ruke off Azure.
|
||||
func resourceAzureSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
netSecClient := netsecgroup.NewClient(mgmtClient)
|
||||
|
||||
secGroupName := d.Get("security_group_name").(string)
|
||||
|
||||
// get info on the network security group and check its rules for this one:
|
||||
log.Println("[INFO] Sending network security group rule query for update to Azure.")
|
||||
secgroup, err := netSecClient.GetNetworkSecurityGroup(secGroupName)
|
||||
if err != nil {
|
||||
if !management.IsResourceNotFoundError(err) {
|
||||
return fmt.Errorf("Error issuing network security group rules query: %s", err)
|
||||
} else {
|
||||
// it meants that the network security group this rule belonged to has
|
||||
// been deleted; so we must remove this resource from the schema:
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// try and find our security group rule:
|
||||
var found bool
|
||||
name := d.Get("name").(string)
|
||||
for _, rule := range secgroup.Rules {
|
||||
if rule.Name == name {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
// check is the resource has not been deleted in the meantime:
|
||||
if !found {
|
||||
// if not; remove the resource:
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
// else, start building up the rule request struct:
|
||||
newRule := netsecgroup.RuleRequest{
|
||||
Name: d.Get("name").(string),
|
||||
Type: netsecgroup.RuleType(d.Get("type").(string)),
|
||||
Priority: d.Get("priority").(int),
|
||||
Action: netsecgroup.RuleAction(d.Get("action").(string)),
|
||||
SourceAddressPrefix: d.Get("source_address_prefix").(string),
|
||||
SourcePortRange: d.Get("source_port_range").(string),
|
||||
DestinationAddressPrefix: d.Get("destination_address_prefix").(string),
|
||||
DestinationPortRange: d.Get("destination_port_range").(string),
|
||||
Protocol: netsecgroup.RuleProtocol(d.Get("protocol").(string)),
|
||||
}
|
||||
|
||||
// send the create request to Azure:
|
||||
log.Println("[INFO] Sending network security group rule update request to Azure.")
|
||||
reqID, err := netSecClient.SetNetworkSecurityGroupRule(
|
||||
secGroupName,
|
||||
newRule,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error sending network security group rule update request to Azure: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating network security group rule on Azure: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureSecurityGroupRuleExists does all the necessary API calls to
|
||||
// check for the existence of the network security group rule on Azure.
|
||||
func resourceAzureSecurityGroupRuleExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
netSecClient := netsecgroup.NewClient(mgmtClient)
|
||||
|
||||
secGroupName := d.Get("security_group_name").(string)
|
||||
|
||||
// get info on the network security group and search for our rule:
|
||||
log.Println("[INFO] Sending network security group rule query for existence check to Azure.")
|
||||
secgroup, err := netSecClient.GetNetworkSecurityGroup(secGroupName)
|
||||
if err != nil {
|
||||
if !management.IsResourceNotFoundError(err) {
|
||||
return false, fmt.Errorf("Error issuing network security group rules query: %s", err)
|
||||
} else {
|
||||
// it meants that the network security group this rule belonged to has
|
||||
// been deleted; so we must remove this resource from the schema:
|
||||
d.SetId("")
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// try and find our security group rule:
|
||||
name := d.Get("name").(string)
|
||||
for _, rule := range secgroup.Rules {
|
||||
if rule.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// if here; it means the resource has been deleted in the
|
||||
// meantime and must be removed from the schema:
|
||||
d.SetId("")
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// resourceAzureSecurityGroupRuleDelete does all the necessary API calls to
|
||||
// delete a network security group rule off Azure.
|
||||
func resourceAzureSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
netSecClient := netsecgroup.NewClient(mgmtClient)
|
||||
|
||||
secGroupName := d.Get("security_group_name").(string)
|
||||
|
||||
// get info on the network security group and search for our rule:
|
||||
log.Println("[INFO] Sending network security group rule query for deletion to Azure.")
|
||||
secgroup, err := netSecClient.GetNetworkSecurityGroup(secGroupName)
|
||||
if err != nil {
|
||||
if management.IsResourceNotFoundError(err) {
|
||||
// it meants that the network security group this rule belonged to has
|
||||
// been deleted; so we need do nothing more but stop tracking the resource:
|
||||
d.SetId("")
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Error issuing network security group rules query: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// check is the resource has not been deleted in the meantime:
|
||||
name := d.Get("name").(string)
|
||||
for _, rule := range secgroup.Rules {
|
||||
if rule.Name == name {
|
||||
// if not; we shall issue the delete:
|
||||
reqID, err := netSecClient.DeleteNetworkSecurityGroupRule(secGroupName, name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error sending network security group rule delete request to Azure: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting network security group rule off Azure: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
netsecgroup "github.com/Azure/azure-sdk-for-go/management/networksecuritygroup"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureSecurityGroupRule(t *testing.T) {
|
||||
name := "azure_security_group_rule.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureSecurityGroupRuleDeleted,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureSecurityGroupRule,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureSecurityGroupRuleExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-secgroup-rule"),
|
||||
resource.TestCheckResourceAttr(name, "security_group_name", testAccSecurityGroupName),
|
||||
resource.TestCheckResourceAttr(name, "type", "Inbound"),
|
||||
resource.TestCheckResourceAttr(name, "action", "Deny"),
|
||||
resource.TestCheckResourceAttr(name, "priority", "200"),
|
||||
resource.TestCheckResourceAttr(name, "source_address_prefix", "100.0.0.0/32"),
|
||||
resource.TestCheckResourceAttr(name, "source_port_range", "1000"),
|
||||
resource.TestCheckResourceAttr(name, "destination_address_prefix", "10.0.0.0/32"),
|
||||
resource.TestCheckResourceAttr(name, "protocol", "TCP"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAzureSecurityGroupRuleExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Azure security group rule not found: %s", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure network security group rule ID not set: %s", name)
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
secGroupClient := netsecgroup.NewClient(mgmtClient)
|
||||
|
||||
secGroup, err := secGroupClient.GetNetworkSecurityGroup(testAccSecurityGroupName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting network security group details: %s", err)
|
||||
}
|
||||
|
||||
for _, rule := range secGroup.Rules {
|
||||
if rule.Name == resource.Primary.ID {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Azure security group rule doesn't exist: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureSecurityGroupRuleDeleted(s *terraform.State) error {
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_security_group_rule" {
|
||||
continue
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure network security group ID not set.")
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
secGroupClient := netsecgroup.NewClient(mgmtClient)
|
||||
|
||||
secGroup, err := secGroupClient.GetNetworkSecurityGroup(testAccSecurityGroupName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting network security group details: %s", err)
|
||||
}
|
||||
|
||||
for _, rule := range secGroup.Rules {
|
||||
if rule.Name == resource.Primary.ID {
|
||||
return fmt.Errorf("Azure network security group rule still exists!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAzureSecurityGroupRule = testAccAzureSecurityGroupConfig + `
|
||||
resource "azure_security_group_rule" "foo" {
|
||||
name = "terraform-secgroup-rule"
|
||||
security_group_name = "${azure_security_group.foo.name}"
|
||||
type = "Inbound"
|
||||
action = "Deny"
|
||||
priority = 200
|
||||
source_address_prefix = "100.0.0.0/32"
|
||||
source_port_range = "1000"
|
||||
destination_address_prefix = "10.0.0.0/32"
|
||||
destination_port_range = "1000"
|
||||
protocol = "TCP"
|
||||
}
|
||||
`
|
|
@ -4,10 +4,10 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/networksecuritygroup"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/networksecuritygroup"
|
||||
)
|
||||
|
||||
func TestAccAzureSecurityGroup_basic(t *testing.T) {
|
||||
|
@ -19,72 +19,16 @@ func TestAccAzureSecurityGroup_basic(t *testing.T) {
|
|||
CheckDestroy: testAccCheckAzureSecurityGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureSecurityGroup_basic,
|
||||
Config: testAccAzureSecurityGroupConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureSecurityGroupExists(
|
||||
"azure_security_group.foo", &group),
|
||||
testAccCheckAzureSecurityGroupBasicAttributes(&group),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "name", "terraform-security-group"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "location", "West US"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.936204579.name", "RDP"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.936204579.source_port", "*"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.936204579.destination_port", "3389"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAzureSecurityGroup_update(t *testing.T) {
|
||||
var group networksecuritygroup.SecurityGroupResponse
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureSecurityGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureSecurityGroup_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureSecurityGroupExists(
|
||||
"azure_security_group.foo", &group),
|
||||
testAccCheckAzureSecurityGroupBasicAttributes(&group),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "name", "terraform-security-group"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "location", "West US"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.936204579.name", "RDP"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.936204579.source_cidr", "*"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.936204579.destination_port", "3389"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAzureSecurityGroup_update,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureSecurityGroupExists(
|
||||
"azure_security_group.foo", &group),
|
||||
testAccCheckAzureSecurityGroupUpdatedAttributes(&group),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.3322523298.name", "RDP"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.3322523298.source_cidr", "192.168.0.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.3322523298.destination_port", "3389"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.3929353075.name", "WINRM"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.3929353075.source_cidr", "192.168.0.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"azure_security_group.foo", "rule.3929353075.destination_port", "5985"),
|
||||
"azure_security_group.foo", "label", "terraform testing security group"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -120,89 +64,6 @@ func testAccCheckAzureSecurityGroupExists(
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureSecurityGroupBasicAttributes(
|
||||
group *networksecuritygroup.SecurityGroupResponse) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
||||
if group.Name != "terraform-security-group" {
|
||||
return fmt.Errorf("Bad name: %s", group.Name)
|
||||
}
|
||||
|
||||
for _, r := range group.Rules {
|
||||
if !r.IsDefault {
|
||||
if r.Name != "RDP" {
|
||||
return fmt.Errorf("Bad rule name: %s", r.Name)
|
||||
}
|
||||
if r.Priority != 101 {
|
||||
return fmt.Errorf("Bad rule priority: %d", r.Priority)
|
||||
}
|
||||
if r.SourceAddressPrefix != "*" {
|
||||
return fmt.Errorf("Bad source CIDR: %s", r.SourceAddressPrefix)
|
||||
}
|
||||
if r.DestinationAddressPrefix != "*" {
|
||||
return fmt.Errorf("Bad destination CIDR: %s", r.DestinationAddressPrefix)
|
||||
}
|
||||
if r.DestinationPortRange != "3389" {
|
||||
return fmt.Errorf("Bad destination port: %s", r.DestinationPortRange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureSecurityGroupUpdatedAttributes(
|
||||
group *networksecuritygroup.SecurityGroupResponse) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
||||
if group.Name != "terraform-security-group" {
|
||||
return fmt.Errorf("Bad name: %s", group.Name)
|
||||
}
|
||||
|
||||
foundRDP := false
|
||||
foundWINRM := false
|
||||
for _, r := range group.Rules {
|
||||
if !r.IsDefault {
|
||||
if r.Name == "RDP" {
|
||||
if r.SourceAddressPrefix != "192.168.0.0/24" {
|
||||
return fmt.Errorf("Bad source CIDR: %s", r.SourceAddressPrefix)
|
||||
}
|
||||
|
||||
foundRDP = true
|
||||
}
|
||||
|
||||
if r.Name == "WINRM" {
|
||||
if r.Priority != 102 {
|
||||
return fmt.Errorf("Bad rule priority: %d", r.Priority)
|
||||
}
|
||||
if r.SourceAddressPrefix != "192.168.0.0/24" {
|
||||
return fmt.Errorf("Bad source CIDR: %s", r.SourceAddressPrefix)
|
||||
}
|
||||
if r.DestinationAddressPrefix != "*" {
|
||||
return fmt.Errorf("Bad destination CIDR: %s", r.DestinationAddressPrefix)
|
||||
}
|
||||
if r.DestinationPortRange != "5985" {
|
||||
return fmt.Errorf("Bad destination port: %s", r.DestinationPortRange)
|
||||
}
|
||||
|
||||
foundWINRM = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !foundRDP {
|
||||
return fmt.Errorf("RDP rule not found")
|
||||
}
|
||||
|
||||
if !foundWINRM {
|
||||
return fmt.Errorf("WINRM rule not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureSecurityGroupDestroy(s *terraform.State) error {
|
||||
mc := testAccProvider.Meta().(*Client).mgmtClient
|
||||
|
||||
|
@ -228,44 +89,9 @@ func testAccCheckAzureSecurityGroupDestroy(s *terraform.State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const testAccAzureSecurityGroup_basic = `
|
||||
var testAccAzureSecurityGroupConfig = fmt.Sprintf(`
|
||||
resource "azure_security_group" "foo" {
|
||||
name = "terraform-security-group"
|
||||
name = "%s"
|
||||
location = "West US"
|
||||
|
||||
rule {
|
||||
name = "RDP"
|
||||
priority = 101
|
||||
source_cidr = "*"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = "3389"
|
||||
protocol = "TCP"
|
||||
}
|
||||
}`
|
||||
|
||||
const testAccAzureSecurityGroup_update = `
|
||||
resource "azure_security_group" "foo" {
|
||||
name = "terraform-security-group"
|
||||
location = "West US"
|
||||
|
||||
rule {
|
||||
name = "RDP"
|
||||
priority = 101
|
||||
source_cidr = "192.168.0.0/24"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = "3389"
|
||||
protocol = "TCP"
|
||||
}
|
||||
|
||||
rule {
|
||||
name = "WINRM"
|
||||
priority = 102
|
||||
source_cidr = "192.168.0.0/24"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = "5985"
|
||||
protocol = "TCP"
|
||||
}
|
||||
}`
|
||||
label = "terraform testing security group"
|
||||
}`, testAccSecurityGroupName)
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureStorageBlob returns the *schema.Resource associated
|
||||
// with a storage blob on Azure.
|
||||
func resourceAzureStorageBlob() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureStorageBlobCreate,
|
||||
Read: resourceAzureStorageBlobRead,
|
||||
Update: resourceAzureStorageBlobUpdate,
|
||||
Exists: resourceAzureStorageBlobExists,
|
||||
Delete: resourceAzureStorageBlobDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["type"],
|
||||
},
|
||||
"size": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return int64(0), nil
|
||||
},
|
||||
},
|
||||
"storage_container_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["storage_container_name"],
|
||||
},
|
||||
"storage_service_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["storage_service_name"],
|
||||
},
|
||||
"url": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: parameterDescriptions["url"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureStorageBlobCreate does all the necessary API calls to
|
||||
// create the storage blob on Azure.
|
||||
func resourceAzureStorageBlobCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("[INFO] Issuing create on Azure storage blob.")
|
||||
name := d.Get("name").(string)
|
||||
blobType := d.Get("type").(string)
|
||||
cont := d.Get("storage_container_name").(string)
|
||||
switch blobType {
|
||||
case "BlockBlob":
|
||||
err = blobClient.CreateBlockBlob(cont, name)
|
||||
case "PageBlob":
|
||||
size := int64(d.Get("size").(int))
|
||||
err = blobClient.PutPageBlob(cont, name, size)
|
||||
default:
|
||||
err = fmt.Errorf("Invalid blob type specified; see parameter desciptions for more info.")
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return resourceAzureStorageBlobRead(d, meta)
|
||||
}
|
||||
|
||||
// resourceAzureStorageBlobRead does all the necessary API calls to
|
||||
// read the status of the storage blob off Azure.
|
||||
func resourceAzureStorageBlobRead(d *schema.ResourceData, meta interface{}) error {
|
||||
// check for it's existence:
|
||||
exists, err := resourceAzureStorageBlobExists(d, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if it exists; read relevant information:
|
||||
if exists {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
cont := d.Get("storage_container_name").(string)
|
||||
url := blobClient.GetBlobURL(cont, name)
|
||||
d.Set("url", url)
|
||||
}
|
||||
|
||||
// NOTE: no need to unset the ID here, as resourceAzureStorageBlobExists
|
||||
// already should have done so if it were required.
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageBlobUpdate does all the necessary API calls to
|
||||
// update a blob on Azure.
|
||||
func resourceAzureStorageBlobUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
// NOTE: although empty as most paramters have ForceNew set; this is
|
||||
// still required in case of changes to the storage_service_key
|
||||
|
||||
// run the ExistsFunc beforehand to ensure the resource's existence nonetheless:
|
||||
_, err := resourceAzureStorageBlobExists(d, meta)
|
||||
return err
|
||||
}
|
||||
|
||||
// resourceAzureStorageBlobExists does all the necessary API calls to
|
||||
// check for the existence of the blob on Azure.
|
||||
func resourceAzureStorageBlobExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
log.Println("[INFO] Querying Azure for storage blob's existence.")
|
||||
name := d.Get("name").(string)
|
||||
cont := d.Get("storage_container_name").(string)
|
||||
exists, err := blobClient.BlobExists(cont, name)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Error whilst checking for Azure storage blob's existence: %s", err)
|
||||
}
|
||||
|
||||
// if not found; it means it was deleted in the meantime and
|
||||
// we must remove it from the schema.
|
||||
if !exists {
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageBlobDelete does all the necessary API calls to
|
||||
// delete the blob off Azure.
|
||||
func resourceAzureStorageBlobDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("[INFO] Issuing storage blob delete command off Azure.")
|
||||
name := d.Get("name").(string)
|
||||
cont := d.Get("storage_container_name").(string)
|
||||
if _, err = blobClient.DeleteBlobIfExists(cont, name); err != nil {
|
||||
return fmt.Errorf("Error whilst deleting storage blob: %s", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureStorageBlockBlob(t *testing.T) {
|
||||
name := "azure_storage_blob.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureStorageBlobDeleted("block"),
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureStorageBlockBlobConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureStorageBlobExists(name, "block"),
|
||||
resource.TestCheckResourceAttr(name, "name", "tftesting-blob"),
|
||||
resource.TestCheckResourceAttr(name, "type", "BlockBlob"),
|
||||
resource.TestCheckResourceAttr(name, "storage_container_name",
|
||||
fmt.Sprintf("%s-block", testAccStorageContainerName)),
|
||||
resource.TestCheckResourceAttr(name, "storage_service_name", testAccStorageServiceName),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAzureStoragePageBlob(t *testing.T) {
|
||||
name := "azure_storage_blob.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureStorageBlobDeleted("page"),
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureStoragePageBlobConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureStorageBlobExists(name, "page"),
|
||||
resource.TestCheckResourceAttr(name, "name", "tftesting-blob"),
|
||||
resource.TestCheckResourceAttr(name, "type", "PageBlob"),
|
||||
resource.TestCheckResourceAttr(name, "size", "512"),
|
||||
resource.TestCheckResourceAttr(name, "storage_container_name",
|
||||
fmt.Sprintf("%s-page", testAccStorageContainerName)),
|
||||
resource.TestCheckResourceAttr(name, "storage_service_name", testAccStorageServiceName),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAzureStorageBlobExists(name, typ string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Azure Storage Container resource not found: %s", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Storage Container ID not set: %s", name)
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, testAccStorageServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := blobClient.BlobExists(fmt.Sprintf("%s-%s", testAccStorageContainerName, typ),
|
||||
resource.Primary.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("Azure Storage Blob %s doesn't exist.", name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureStorageBlobDeleted(typ string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_storage_blob" {
|
||||
continue
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, testAccStorageServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := blobClient.BlobExists(fmt.Sprintf("%s-%s", testAccStorageContainerName,
|
||||
typ), resource.Primary.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("Azure Storage Blob still exists.")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var testAccAzureStorageBlockBlobConfig = fmt.Sprintf(`
|
||||
resource "azure_storage_container" "foo" {
|
||||
name = "%s-block"
|
||||
container_access_type = "blob"
|
||||
# NOTE: A pre-existing Storage Service is used here so as to avoid
|
||||
# the huge wait for creation of one.
|
||||
storage_service_name = "%s"
|
||||
}
|
||||
|
||||
resource "azure_storage_blob" "foo" {
|
||||
name = "tftesting-blob"
|
||||
type = "BlockBlob"
|
||||
# NOTE: A pre-existing Storage Service is used here so as to avoid
|
||||
# the huge wait for creation of one.
|
||||
storage_service_name = "${azure_storage_container.foo.storage_service_name}"
|
||||
storage_container_name = "${azure_storage_container.foo.name}"
|
||||
}
|
||||
`, testAccStorageContainerName, testAccStorageServiceName)
|
||||
|
||||
var testAccAzureStoragePageBlobConfig = fmt.Sprintf(`
|
||||
resource "azure_storage_container" "foo" {
|
||||
name = "%s-page"
|
||||
container_access_type = "blob"
|
||||
# NOTE: A pre-existing Storage Service is used here so as to avoid
|
||||
# the huge wait for creation of one.
|
||||
storage_service_name = "%s"
|
||||
}
|
||||
|
||||
resource "azure_storage_blob" "foo" {
|
||||
name = "tftesting-blob"
|
||||
type = "PageBlob"
|
||||
# NOTE: A pre-existing Storage Service is used here so as to avoid
|
||||
# the huge wait for creation of one.
|
||||
storage_service_name = "${azure_storage_container.foo.storage_service_name}"
|
||||
storage_container_name = "${azure_storage_container.foo.name}"
|
||||
# NOTE: must be a multiple of 512:
|
||||
size = 512
|
||||
}
|
||||
`, testAccStorageContainerName, testAccStorageServiceName)
|
|
@ -0,0 +1,163 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/storage"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureStorageContainer returns the *schema.Resource associated
|
||||
// to a storage container on Azure.
|
||||
func resourceAzureStorageContainer() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureStorageContainerCreate,
|
||||
Read: resourceAzureStorageContainerRead,
|
||||
Exists: resourceAzureStorageContainerExists,
|
||||
Delete: resourceAzureStorageContainerDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"storage_service_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["storage_service_name"],
|
||||
},
|
||||
"container_access_type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["container_access_type"],
|
||||
},
|
||||
"properties": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Computed: true,
|
||||
Elem: schema.TypeString,
|
||||
Description: parameterDescriptions["properties"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureStorageContainerCreate does all the necessary API calls to
|
||||
// create the storage container on Azure.
|
||||
func resourceAzureStorageContainerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("[INFO] Creating storage container on Azure.")
|
||||
name := d.Get("name").(string)
|
||||
accessType := storage.ContainerAccessType(d.Get("container_access_type").(string))
|
||||
err = blobClient.CreateContainer(name, accessType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create storage container on Azure: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return resourceAzureStorageContainerRead(d, meta)
|
||||
}
|
||||
|
||||
// resourceAzureStorageContainerRead does all the necessary API calls to
|
||||
// read the status of the storage container off Azure.
|
||||
func resourceAzureStorageContainerRead(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("[INFO] Querying Azure for storage containers.")
|
||||
name := d.Get("name").(string)
|
||||
containers, err := blobClient.ListContainers(storage.ListContainersParameters{
|
||||
Prefix: name,
|
||||
Timeout: 90,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to query Azure for its storage containers: %s", err)
|
||||
}
|
||||
|
||||
// search for our storage container and update its stats:
|
||||
var found bool
|
||||
// loop just to make sure we got the right container:
|
||||
for _, cont := range containers.Containers {
|
||||
if cont.Name == name {
|
||||
found = true
|
||||
|
||||
props := make(map[string]interface{})
|
||||
props["last_modified"] = cont.Properties.LastModified
|
||||
props["lease_status"] = cont.Properties.LeaseStatus
|
||||
props["lease_state"] = cont.Properties.LeaseState
|
||||
props["lease_duration"] = cont.Properties.LeaseDuration
|
||||
|
||||
d.Set("properties", props)
|
||||
}
|
||||
}
|
||||
|
||||
// if not found; it means the resource has been deleted
|
||||
// in the meantime; so we must untrack it:
|
||||
if !found {
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageContainerExists does all the necessary API calls to
|
||||
// check if the storage container already exists on Azure.
|
||||
func resourceAzureStorageContainerExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
log.Println("[INFO] Checking existence of storage container on Azure.")
|
||||
name := d.Get("name").(string)
|
||||
exists, err := blobClient.ContainerExists(name)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to query for Azure storage container existence: %s", err)
|
||||
}
|
||||
|
||||
// if it does not exist; untrack the resource:
|
||||
if !exists {
|
||||
d.SetId("")
|
||||
}
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageContainerDelete does all the necessary API calls to
|
||||
// delete a storage container off Azure.
|
||||
func resourceAzureStorageContainerDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storName := d.Get("storage_service_name").(string)
|
||||
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, storName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("[INFO] Issuing Azure storage container deletion call.")
|
||||
name := d.Get("name").(string)
|
||||
if _, err := blobClient.DeleteContainerIfExists(name); err != nil {
|
||||
return fmt.Errorf("Failed deleting storage container off Azure: %s", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureStorageContainer(t *testing.T) {
|
||||
name := "azure_storage_container.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureStorageContainerDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureStorageContainerConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureStorageContainerExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", testAccStorageContainerName),
|
||||
resource.TestCheckResourceAttr(name, "storage_service_name", testAccStorageServiceName),
|
||||
resource.TestCheckResourceAttr(name, "container_access_type", "blob"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// because containers take a while to get deleted, sleep for one minute:
|
||||
time.Sleep(3 * time.Minute)
|
||||
}
|
||||
|
||||
func testAccCheckAzureStorageContainerExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Azure Storage Container resource not found: %s", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Storage Container ID not set: %s", name)
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, testAccStorageServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := blobClient.ContainerExists(resource.Primary.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("Azure Storage Container %s doesn't exist.", name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureStorageContainerDestroyed(s *terraform.State) error {
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_storage_container" {
|
||||
continue
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
blobClient, err := getStorageServiceBlobClient(mgmtClient, testAccStorageServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := blobClient.ContainerExists(resource.Primary.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("Azure Storage Container still exists.")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAzureStorageContainerConfig = fmt.Sprintf(`
|
||||
resource "azure_storage_container" "foo" {
|
||||
name = "%s"
|
||||
container_access_type = "blob"
|
||||
# NOTE: A pre-existing Storage Service is used here so as to avoid
|
||||
# the huge wait for creation of one.
|
||||
storage_service_name = "%s"
|
||||
}
|
||||
`, testAccStorageContainerName, testAccStorageServiceName)
|
|
@ -0,0 +1,103 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureStorageQueue returns the *schema.Resource associated
|
||||
// to a storage queue on Azure.
|
||||
func resourceAzureStorageQueue() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureStorageQueueCreate,
|
||||
Read: resourceAzureStorageQueueRead,
|
||||
Delete: resourceAzureStorageQueueDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"storage_service_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["storage_service_name"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureStorageQueueCreate does all the necessary API calls to
|
||||
// create a storage queue on Azure.
|
||||
func resourceAzureStorageQueueCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storServName := d.Get("storage_service_name").(string)
|
||||
queueClient, err := getStorageServiceQueueClient(mgmtClient, storServName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create the queue:
|
||||
log.Println("Sending Storage Queue creation request to Azure.")
|
||||
name := d.Get("name").(string)
|
||||
err = queueClient.CreateQueue(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creation Storage Queue on Azure: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageQueueRead does all the necessary API calls to
|
||||
// read the state of the storage queue off Azure.
|
||||
func resourceAzureStorageQueueRead(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storServName := d.Get("storage_service_name").(string)
|
||||
queueClient, err := getStorageServiceQueueClient(mgmtClient, storServName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check for queue's existence:
|
||||
log.Println("[INFO] Sending Storage Queue existence query to Azure.")
|
||||
name := d.Get("name").(string)
|
||||
exists, err := queueClient.QueueExists(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error checking for Storage Queue existence: %s", err)
|
||||
}
|
||||
|
||||
// If the queue has been deleted in the meantime;
|
||||
// untrack the resource from the schema.
|
||||
if !exists {
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageQueueDelete does all the necessary API calls to
|
||||
// delete the storage queue off Azure.
|
||||
func resourceAzureStorageQueueDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
mgmtClient := meta.(*Client).mgmtClient
|
||||
storServName := d.Get("storage_service_name").(string)
|
||||
queueClient, err := getStorageServiceQueueClient(mgmtClient, storServName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// issue the deletion of the storage queue:
|
||||
log.Println("[INFO] Sending Storage Queue deletion request to Azure.")
|
||||
name := d.Get("name").(string)
|
||||
err = queueClient.DeleteQueue(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting Storage queue off Azure: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureStorageQueue(t *testing.T) {
|
||||
name := "azure_storage_queue.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureStorageQueueDeleted,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureStorageQueueConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureStorageQueueExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-queue"),
|
||||
resource.TestCheckResourceAttr(name, "storage_service_name", testAccStorageServiceName),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAzureStorageQueueExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Azure Storage Queue resource '%s' is missing.", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Storage Service Queue ID %s is missing.", name)
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
queueClient, err := getStorageServiceQueueClient(mgmtClient, testAccStorageServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := queueClient.QueueExists(resource.Primary.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error querying Azure for Storage Queue existence: %s", err)
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("Azure Storage Queue %s doesn't exist!", resource.Primary.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureStorageQueueDeleted(s *terraform.State) error {
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_storage_queue" {
|
||||
continue
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Storage Service Queue ID %s is missing.", resource.Primary.ID)
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
queueClient, err := getStorageServiceQueueClient(mgmtClient, testAccStorageServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := queueClient.QueueExists(resource.Primary.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error querying Azure for Storage Queue existence: %s", err)
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("Azure Storage Queue %s still exists!", resource.Primary.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAzureStorageQueueConfig = fmt.Sprintf(`
|
||||
resource "azure_storage_queue" "foo" {
|
||||
name = "terraform-queue"
|
||||
storage_service_name = "%s"
|
||||
}
|
||||
`, testAccStorageServiceName)
|
|
@ -0,0 +1,227 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/storageservice"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureStorageService returns the *schema.Resource associated
|
||||
// to an Azure hosted service.
|
||||
func resourceAzureStorageService() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureStorageServiceCreate,
|
||||
Read: resourceAzureStorageServiceRead,
|
||||
Exists: resourceAzureStorageServiceExists,
|
||||
Delete: resourceAzureStorageServiceDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
// General attributes:
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
// TODO(aznashwan): constrain name in description
|
||||
Description: parameterDescriptions["name"],
|
||||
},
|
||||
"location": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["location"],
|
||||
},
|
||||
"label": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: "Made by Terraform.",
|
||||
Description: parameterDescriptions["label"],
|
||||
},
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["description"],
|
||||
},
|
||||
// Functional attributes:
|
||||
"account_type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["account_type"],
|
||||
},
|
||||
"affinity_group": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Description: parameterDescriptions["affinity_group"],
|
||||
},
|
||||
"properties": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: schema.TypeString,
|
||||
},
|
||||
// Computed attributes:
|
||||
"url": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"primary_key": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"secondary_key": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureStorageServiceCreate does all the necessary API calls to
|
||||
// create a new Azure storage service.
|
||||
func resourceAzureStorageServiceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
storageServiceClient := storageservice.NewClient(mgmtClient)
|
||||
|
||||
// get all the values:
|
||||
log.Println("[INFO] Creating Azure Storage Service creation parameters.")
|
||||
name := d.Get("name").(string)
|
||||
location := d.Get("location").(string)
|
||||
accountType := storageservice.AccountType(d.Get("account_type").(string))
|
||||
affinityGroup := d.Get("affinity_group").(string)
|
||||
description := d.Get("description").(string)
|
||||
label := base64.StdEncoding.EncodeToString([]byte(d.Get("label").(string)))
|
||||
var props []storageservice.ExtendedProperty
|
||||
if given := d.Get("properties").(map[string]interface{}); len(given) > 0 {
|
||||
props = []storageservice.ExtendedProperty{}
|
||||
for k, v := range given {
|
||||
props = append(props, storageservice.ExtendedProperty{
|
||||
Name: k,
|
||||
Value: v.(string),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// create parameters and send request:
|
||||
log.Println("[INFO] Sending Storage Service creation request to Azure.")
|
||||
reqID, err := storageServiceClient.CreateStorageService(
|
||||
storageservice.StorageAccountCreateParameters{
|
||||
ServiceName: name,
|
||||
Location: location,
|
||||
Description: description,
|
||||
Label: label,
|
||||
AffinityGroup: affinityGroup,
|
||||
AccountType: accountType,
|
||||
ExtendedProperties: storageservice.ExtendedPropertyList{
|
||||
ExtendedProperty: props,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create Azure storage service %s: %s", name, err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed creating storage service %s: %s", name, err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return resourceAzureStorageServiceRead(d, meta)
|
||||
}
|
||||
|
||||
// resourceAzureStorageServiceRead does all the necessary API calls to
|
||||
// read the state of the storage service off Azure.
|
||||
func resourceAzureStorageServiceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient := meta.(*Client)
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
storageServiceClient := storageservice.NewClient(mgmtClient)
|
||||
|
||||
// get our storage service:
|
||||
log.Println("[INFO] Sending query about storage service to Azure.")
|
||||
name := d.Get("name").(string)
|
||||
storsvc, err := storageServiceClient.GetStorageService(name)
|
||||
if err != nil {
|
||||
if !management.IsResourceNotFoundError(err) {
|
||||
return fmt.Errorf("Failed to query about Azure about storage service: %s", err)
|
||||
} else {
|
||||
// it means that the resource has been deleted from Azure
|
||||
// in the meantime and we must remove its associated Resource.
|
||||
d.SetId("")
|
||||
return nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// read values:
|
||||
d.Set("url", storsvc.URL)
|
||||
log.Println("[INFO] Querying keys of Azure storage service.")
|
||||
keys, err := storageServiceClient.GetStorageServiceKeys(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed querying keys for Azure storage service: %s", err)
|
||||
}
|
||||
d.Set("primary_key", keys.PrimaryKey)
|
||||
d.Set("secondary_key", keys.SecondaryKey)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageServiceExists does all the necessary API calls to
|
||||
// check if the storage service exists on Azure.
|
||||
func resourceAzureStorageServiceExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
azureClient, ok := meta.(*Client)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("Failed to convert to *Client, got: %T", meta)
|
||||
}
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
storageServiceClient := storageservice.NewClient(mgmtClient)
|
||||
|
||||
// get our storage service:
|
||||
log.Println("[INFO] Sending query about storage service to Azure.")
|
||||
name := d.Get("name").(string)
|
||||
_, err := storageServiceClient.GetStorageService(name)
|
||||
if err != nil {
|
||||
if !management.IsResourceNotFoundError(err) {
|
||||
return false, fmt.Errorf("Failed to query about Azure about storage service: %s", err)
|
||||
} else {
|
||||
// it means that the resource has been deleted from Azure
|
||||
// in the meantime and we must remove its associated Resource.
|
||||
d.SetId("")
|
||||
return false, nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// resourceAzureStorageServiceDelete does all the necessary API calls to
|
||||
// delete the storage service off Azure.
|
||||
func resourceAzureStorageServiceDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
azureClient, ok := meta.(*Client)
|
||||
if !ok {
|
||||
return fmt.Errorf("Failed to convert to *Client, got: %T", meta)
|
||||
}
|
||||
mgmtClient := azureClient.mgmtClient
|
||||
storageClient := storageservice.NewClient(mgmtClient)
|
||||
|
||||
// issue the deletion:
|
||||
name := d.Get("name").(string)
|
||||
log.Println("[INFO] Issuing delete of storage service off Azure.")
|
||||
reqID, err := storageClient.DeleteStorageService(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error whilst issuing deletion of storage service off Azure: %s", err)
|
||||
}
|
||||
err = mgmtClient.WaitForOperation(reqID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error whilst deleting storage service off Azure: %s", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/storageservice"
|
||||
"github.com/Azure/azure-sdk-for-go/storage"
|
||||
)
|
||||
|
||||
// getStorageClientForStorageService is helper function which returns the
|
||||
// storage.Client associated to the given storage service name.
|
||||
func getStorageClientForStorageService(mgmtClient management.Client, serviceName string) (storage.Client, error) {
|
||||
var storageClient storage.Client
|
||||
storageServiceClient := storageservice.NewClient(mgmtClient)
|
||||
|
||||
keys, err := storageServiceClient.GetStorageServiceKeys(serviceName)
|
||||
if err != nil {
|
||||
return storageClient, fmt.Errorf("Failed getting Storage Service keys for %s: %s", serviceName, err)
|
||||
}
|
||||
|
||||
storageClient, err = storage.NewBasicClient(serviceName, keys.PrimaryKey)
|
||||
if err != nil {
|
||||
return storageClient, fmt.Errorf("Failed creating Storage Service client for %s: %s", serviceName, err)
|
||||
}
|
||||
|
||||
return storageClient, err
|
||||
}
|
||||
|
||||
// getStorageServiceBlobClient is a helper function which returns the
|
||||
// storage.BlobStorageClient associated to the given storage service name.
|
||||
func getStorageServiceBlobClient(mgmtClient management.Client, serviceName string) (storage.BlobStorageClient, error) {
|
||||
storageClient, err := getStorageClientForStorageService(mgmtClient, serviceName)
|
||||
if err != nil {
|
||||
return storage.BlobStorageClient{}, err
|
||||
}
|
||||
|
||||
return storageClient.GetBlobService(), nil
|
||||
}
|
||||
|
||||
// getStorageServiceQueueClient is a helper function which returns the
|
||||
// storage.QueueServiceClient associated to the given storage service name.
|
||||
func getStorageServiceQueueClient(mgmtClient management.Client, serviceName string) (storage.QueueServiceClient, error) {
|
||||
storageClient, err := getStorageClientForStorageService(mgmtClient, serviceName)
|
||||
if err != nil {
|
||||
return storage.QueueServiceClient{}, err
|
||||
}
|
||||
|
||||
return storageClient.GetQueueService(), err
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/storageservice"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureStorageService(t *testing.T) {
|
||||
name := "azure_storage_service.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccAzureStorageServiceDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureStorageServiceConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccAzureStorageServiceExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "tftesting"),
|
||||
resource.TestCheckResourceAttr(name, "location", "North Europe"),
|
||||
resource.TestCheckResourceAttr(name, "description", "very descriptive"),
|
||||
resource.TestCheckResourceAttr(name, "account_type", "Standard_LRS"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccAzureStorageServiceExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Azure Storage Service Resource not found: %s", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Storage Service ID not set.")
|
||||
}
|
||||
|
||||
mgmtClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
_, err := storageservice.NewClient(mgmtClient).GetStorageService(resource.Primary.ID)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func testAccAzureStorageServiceDestroyed(s *terraform.State) error {
|
||||
mgmgClient := testAccProvider.Meta().(*Client).mgmtClient
|
||||
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_storage_service" {
|
||||
continue
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Azure Storage Service ID not set.")
|
||||
}
|
||||
|
||||
_, err := storageservice.NewClient(mgmgClient).GetStorageService(resource.Primary.ID)
|
||||
return testAccResourceDestroyedErrorFilter("Storage Service", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAzureStorageServiceConfig = `
|
||||
resource "azure_storage_service" "foo" {
|
||||
# NOTE: storage service names constrained to lowercase letters only.
|
||||
name = "tftesting"
|
||||
location = "West US"
|
||||
description = "very descriptive"
|
||||
account_type = "Standard_LRS"
|
||||
}
|
||||
`
|
|
@ -5,12 +5,11 @@ import (
|
|||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/networksecuritygroup"
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualnetwork"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/networksecuritygroup"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/virtualnetwork"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -37,6 +36,14 @@ func resourceAzureVirtualNetwork() *schema.Resource {
|
|||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"dns_servers_names": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
|
||||
"subnet": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
|
@ -94,11 +101,7 @@ func resourceAzureVirtualNetworkCreate(d *schema.ResourceData, meta interface{})
|
|||
}
|
||||
}
|
||||
|
||||
network, err := createVirtualNetwork(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
network := createVirtualNetwork(d)
|
||||
nc.Configuration.VirtualNetworkSites = append(nc.Configuration.VirtualNetworkSites, network)
|
||||
|
||||
req, err := virtualnetwork.NewClient(mc).SetVirtualNetworkConfiguration(nc)
|
||||
|
@ -187,11 +190,7 @@ func resourceAzureVirtualNetworkUpdate(d *schema.ResourceData, meta interface{})
|
|||
found := false
|
||||
for i, n := range nc.Configuration.VirtualNetworkSites {
|
||||
if n.Name == d.Id() {
|
||||
network, err := createVirtualNetwork(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
network := createVirtualNetwork(d)
|
||||
nc.Configuration.VirtualNetworkSites[i] = network
|
||||
|
||||
found = true
|
||||
|
@ -263,15 +262,19 @@ func resourceAzureSubnetHash(v interface{}) int {
|
|||
return hashcode.String(subnet)
|
||||
}
|
||||
|
||||
func createVirtualNetwork(d *schema.ResourceData) (virtualnetwork.VirtualNetworkSite, error) {
|
||||
var addressPrefix []string
|
||||
err := mapstructure.WeakDecode(d.Get("address_space"), &addressPrefix)
|
||||
if err != nil {
|
||||
return virtualnetwork.VirtualNetworkSite{}, fmt.Errorf("Error decoding address_space: %s", err)
|
||||
func createVirtualNetwork(d *schema.ResourceData) virtualnetwork.VirtualNetworkSite {
|
||||
// fetch address spaces:
|
||||
var prefixes []string
|
||||
for _, prefix := range d.Get("address_space").([]interface{}) {
|
||||
prefixes = append(prefixes, prefix.(string))
|
||||
}
|
||||
|
||||
addressSpace := virtualnetwork.AddressSpace{
|
||||
AddressPrefix: addressPrefix,
|
||||
// fetch DNS references:
|
||||
var dnsRefs []virtualnetwork.DNSServerRef
|
||||
for _, dns := range d.Get("dns_servers_names").([]interface{}) {
|
||||
dnsRefs = append(dnsRefs, virtualnetwork.DNSServerRef{
|
||||
Name: dns.(string),
|
||||
})
|
||||
}
|
||||
|
||||
// Add all subnets that are configured
|
||||
|
@ -287,11 +290,14 @@ func createVirtualNetwork(d *schema.ResourceData) (virtualnetwork.VirtualNetwork
|
|||
}
|
||||
|
||||
return virtualnetwork.VirtualNetworkSite{
|
||||
Name: d.Get("name").(string),
|
||||
Location: d.Get("location").(string),
|
||||
AddressSpace: addressSpace,
|
||||
Subnets: subnets,
|
||||
}, nil
|
||||
Name: d.Get("name").(string),
|
||||
Location: d.Get("location").(string),
|
||||
AddressSpace: virtualnetwork.AddressSpace{
|
||||
AddressPrefix: prefixes,
|
||||
},
|
||||
DNSServersRef: dnsRefs,
|
||||
Subnets: subnets,
|
||||
}
|
||||
}
|
||||
|
||||
func associateSecurityGroups(d *schema.ResourceData, meta interface{}) error {
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management/virtualnetwork"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/svanharmelen/azure-sdk-for-go/management/virtualnetwork"
|
||||
)
|
||||
|
||||
func TestAccAzureVirtualNetwork_basic(t *testing.T) {
|
||||
|
@ -214,16 +214,19 @@ const testAccAzureVirtualNetwork_advanced = `
|
|||
resource "azure_security_group" "foo" {
|
||||
name = "terraform-security-group1"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
rule {
|
||||
name = "RDP"
|
||||
priority = 101
|
||||
source_cidr = "*"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = "3389"
|
||||
protocol = "TCP"
|
||||
}
|
||||
resource "azure_security_group_rule" "foo" {
|
||||
name = "terraform-secgroup-rule"
|
||||
security_group_name = "${azure_security_group.foo.name}"
|
||||
type = "Inbound"
|
||||
action = "Deny"
|
||||
priority = 200
|
||||
source_address_prefix = "100.0.0.0/32"
|
||||
source_port_range = "1000"
|
||||
destination_address_prefix = "10.0.0.0/32"
|
||||
destination_port_range = "1000"
|
||||
protocol = "TCP"
|
||||
}
|
||||
|
||||
resource "azure_virtual_network" "foo" {
|
||||
|
@ -242,31 +245,24 @@ const testAccAzureVirtualNetwork_update = `
|
|||
resource "azure_security_group" "foo" {
|
||||
name = "terraform-security-group1"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
rule {
|
||||
name = "RDP"
|
||||
priority = 101
|
||||
source_cidr = "*"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = "3389"
|
||||
protocol = "TCP"
|
||||
}
|
||||
resource "azure_security_group_rule" "foo" {
|
||||
name = "terraform-secgroup-rule"
|
||||
security_group_name = "${azure_security_group.foo.name}"
|
||||
type = "Inbound"
|
||||
action = "Deny"
|
||||
priority = 200
|
||||
source_address_prefix = "100.0.0.0/32"
|
||||
source_port_range = "1000"
|
||||
destination_address_prefix = "10.0.0.0/32"
|
||||
destination_port_range = "1000"
|
||||
protocol = "TCP"
|
||||
}
|
||||
|
||||
resource "azure_security_group" "bar" {
|
||||
name = "terraform-security-group2"
|
||||
location = "West US"
|
||||
|
||||
rule {
|
||||
name = "SSH"
|
||||
priority = 101
|
||||
source_cidr = "*"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = "22"
|
||||
protocol = "TCP"
|
||||
}
|
||||
}
|
||||
|
||||
resource "azure_virtual_network" "foo" {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
)
|
||||
|
||||
// testAccResourceDestroyedErrorFilter tests whether the given error is an azure ResourceNotFound
|
||||
// error and properly annotates it if otherwise:
|
||||
func testAccResourceDestroyedErrorFilter(resource string, err error) error {
|
||||
switch {
|
||||
case err == nil:
|
||||
return fmt.Errorf("Azure %s still exists.", resource)
|
||||
case err != nil && management.IsResourceNotFoundError(err):
|
||||
return nil
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
|
@ -46,3 +46,14 @@ The following arguments are supported:
|
|||
* `certificate` - (Optional) The certificate used to authenticate with the
|
||||
Azure API. If a `settings_file` is not provided `certificate` is required.
|
||||
It can also be sourced from the `AZURE_CERTIFICATE` environment variable.
|
||||
|
||||
## Testing:
|
||||
|
||||
The following environment variables must be set for the running of the
|
||||
acceptance test suite:
|
||||
|
||||
* A valid combination of the above which are required for authentification.
|
||||
|
||||
* `AZURE_STORAGE` - The name of a storage account to be used in tests which
|
||||
require a storage backend. The storage account needs to be located in
|
||||
the Western US Azure region.
|
||||
|
|
|
@ -17,7 +17,7 @@ it will attach that disk. Otherwise it will create and attach a new empty disk.
|
|||
resource "azure_data_disk" "data" {
|
||||
lun = 0
|
||||
size = 10
|
||||
storage = "yourstorage"
|
||||
storage_service_name = "yourstorage"
|
||||
virtual_machine = "server1"
|
||||
}
|
||||
```
|
||||
|
@ -43,10 +43,10 @@ The following arguments are supported:
|
|||
* `caching` - (Optional) The caching behavior of data disk. Valid options are:
|
||||
`None`, `ReadOnly` and `ReadWrite` (defaults `None`)
|
||||
|
||||
* `storage ` - (Optional) The name of an existing storage account within the
|
||||
subscription which will be used to store the VHD of this disk. Required
|
||||
if no value is supplied for `media_link`. Changing this forces a new
|
||||
resource to be created.
|
||||
* `storage_service_name` - (Optional) The name of an existing storage account
|
||||
within the subscription which will be used to store the VHD of this disk.
|
||||
Required if no value is supplied for `media_link`. Changing this forces
|
||||
a new resource to be created.
|
||||
|
||||
* `media_link` - (Optional) The location of the blob in storage where the VHD
|
||||
of this disk will be created. The storage account where must be associated
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_dns_server"
|
||||
sidebar_current: "docs-azure-resource-dns-server"
|
||||
description: |-
|
||||
Creates a new DNS server definition to be used internally in Azure.
|
||||
---
|
||||
|
||||
# azure\_dns\_server
|
||||
|
||||
Creates a new DNS server definition to be used internally in Azure.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_dns_server" "google-dns" {
|
||||
name = "google"
|
||||
dns_address = "8.8.8.8"
|
||||
}
|
||||
`
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the DNS server reference. Changing this
|
||||
forces a new resource to be created.
|
||||
|
||||
* `dns_address` - (Required) The IP address of the DNS server.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The DNS server definition ID. Coincides with the given `name`.
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_hosted_service"
|
||||
sidebar_current: "docs-azure-hosted-service"
|
||||
description: |-
|
||||
Creates a new hosted service on Azure with its own .cloudapp.net domain.
|
||||
---
|
||||
|
||||
# azure\_hosted\_service
|
||||
|
||||
Creates a new hosted service on Azure with its own .cloudapp.net domain.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_hosted_service" "terraform-service" {
|
||||
name = "terraform-service"
|
||||
location = "North Europe"
|
||||
ephemeral_contents = false
|
||||
description = "Hosted service created by Terraform."
|
||||
label = "tf-hs-01"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the hosted service. Must be unique on Azure.
|
||||
|
||||
* `location` - (Required) The location where the hosted service should be created.
|
||||
For a list of all Azure locations, please consult [this link](http://azure.microsoft.com/en-us/regions/).
|
||||
|
||||
* `ephemeral_contents` - (Required) A boolean value (true|false), specifying
|
||||
whether all the resources present in the hosted hosted service should be
|
||||
destroyed following the hosted service's destruction.
|
||||
|
||||
* `reverse_dns_fqdn` - (Optional) The reverse of the fully qualified domain name
|
||||
for the hosted service.
|
||||
|
||||
* `label` - (Optional) A label to be used for tracking purposes. Must be
|
||||
non-void. Defaults to `Made by Terraform.`.
|
||||
|
||||
* `description` - (Optional) A description for the hosted service.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The hosted service ID. Coincides with the given `name`.
|
|
@ -18,7 +18,7 @@ resource "azure_instance" "web" {
|
|||
name = "terraform-test"
|
||||
image = "Ubuntu Server 14.04 LTS"
|
||||
size = "Basic_A1"
|
||||
storage = "yourstorage"
|
||||
storage_service_name = "yourstorage"
|
||||
location = "West US"
|
||||
username = "terraform"
|
||||
password = "Pass!admin123"
|
||||
|
@ -56,9 +56,9 @@ The following arguments are supported:
|
|||
belongs to. If a value is supplied `subnet` is required. Changing this
|
||||
forces a new resource to be created.
|
||||
|
||||
* `storage` - (Optional) The name of an existing storage account within the
|
||||
subscription which will be used to store the VHDs of this instance.
|
||||
Changing this forces a new resource to be created.
|
||||
* `storage_service_name` - (Optional) The name of an existing storage account
|
||||
within the subscription which will be used to store the VHDs of this
|
||||
instance. Changing this forces a new resource to be created.
|
||||
|
||||
* `reverse_dns` - (Optional) The DNS address to which the IP address of the
|
||||
hosted service resolves when queried using a reverse DNS query. Changing
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_local_network_connection"
|
||||
sidebar_current: "docs-azure-resource-local-network-connection"
|
||||
description: |-
|
||||
Defines a new connection to a remote network throguh a VPN tunnel.
|
||||
---
|
||||
|
||||
# azure\_local\_network\_connection
|
||||
|
||||
Defines a new connection to a remote network throguh a VPN tunnel.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_local_network_connection" "localnet" {
|
||||
name = "terraform-local-network-connection"
|
||||
vpn_gateway_address = "45.12.189.2"
|
||||
address_space_prefixes = ["10.10.10.0/24", "10.10.11.0/24"]
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name by which this local network connection will
|
||||
be referenced by. Changing this forces a new resource to be created.
|
||||
|
||||
* `vpn_gateway_address` - (Required) The public IPv4 of the VPN endpoint.
|
||||
|
||||
* `address_space_prefixes` - (Required) List of address spaces accessible
|
||||
through the VPN connection. The elements are in the CIDR format.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The local network connection ID.
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_security_group"
|
||||
sidebar_current: "docs-azure-resource-security-group"
|
||||
description: |-
|
||||
Creates a new network security group within the context of the specified subscription.
|
||||
---
|
||||
|
||||
# azure\_security\_group
|
||||
|
||||
Creates a new network security group within the context of the specified
|
||||
subscription.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_security_group" "web" {
|
||||
name = "webservers"
|
||||
location = "West US"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the security group. Changing this forces a
|
||||
new resource to be created.
|
||||
|
||||
* `label` - (Optional) The identifier for the security group. The label can be
|
||||
up to 1024 characters long. Changing this forces a new resource to be
|
||||
created (defaults to the security group name)
|
||||
|
||||
* `location` - (Required) The location/region where the security group is
|
||||
created. Changing this forces a new resource to be created.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The security group ID.
|
||||
* `label` - The identifier for the security group.
|
|
@ -1,84 +0,0 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_security_group"
|
||||
sidebar_current: "docs-azure-resource-security-group"
|
||||
description: |-
|
||||
Creates a new network security group within the context of the specified subscription.
|
||||
---
|
||||
|
||||
# azure\_security\_group
|
||||
|
||||
Creates a new network security group within the context of the specified
|
||||
subscription.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_security_group" "web" {
|
||||
name = "webservers"
|
||||
location = "West US"
|
||||
|
||||
rule {
|
||||
name = "HTTPS"
|
||||
priority = 101
|
||||
source_cidr = "*"
|
||||
source_port = "*"
|
||||
destination_cidr = "*"
|
||||
destination_port = "443"
|
||||
protocol = "TCP"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the security group. Changing this forces a
|
||||
new resource to be created.
|
||||
|
||||
* `label` - (Optional) The identifier for the security group. The label can be
|
||||
up to 1024 characters long. Changing this forces a new resource to be
|
||||
created (defaults to the security group name)
|
||||
|
||||
* `location` - (Required) The location/region where the security group is
|
||||
created. Changing this forces a new resource to be created.
|
||||
|
||||
* `rule` - (Required) Can be specified multiple times to define multiple
|
||||
rules. Each `rule` block supports fields documented below.
|
||||
|
||||
The `rule` block supports:
|
||||
|
||||
* `name` - (Required) The name of the security rule.
|
||||
|
||||
* `type ` - (Optional) The type of the security rule. Valid options are:
|
||||
`Inbound` and `Outbound` (defaults `Inbound`)
|
||||
|
||||
* `priority` - (Required) The priority of the network security rule. Rules with
|
||||
lower priority are evaluated first. This value can be between 100 and 4096.
|
||||
|
||||
* `action` - (Optional) The action that is performed when the security rule is
|
||||
matched. Valid options are: `Allow` and `Deny` (defaults `Allow`)
|
||||
|
||||
* `source_cidr` - (Required) The CIDR or source IP range. An asterisk (\*) can
|
||||
also be used to match all source IPs.
|
||||
|
||||
* `source_port` - (Required) The source port or range. This value can be
|
||||
between 0 and 65535. An asterisk (\*) can also be used to match all ports.
|
||||
|
||||
* `destination_cidr` - (Required) The CIDR or destination IP range. An asterisk
|
||||
(\*) can also be used to match all destination IPs.
|
||||
|
||||
* `destination_port` - (Required) The destination port or range. This value can
|
||||
be between 0 and 65535. An asterisk (\*) can also be used to match all
|
||||
ports.
|
||||
|
||||
* `protocol` - (Optional) The protocol of the security rule. Valid options are:
|
||||
`TCP`, `UDP` and `*` (defaults `TCP`)
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The security group ID.
|
||||
* `label` - The identifier for the security group.
|
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_security_group_rule"
|
||||
sidebar_current: "docs-azure-resource-security-group-rule"
|
||||
description: |-
|
||||
Creates a new network security rule to be associated with a given security group.
|
||||
---
|
||||
|
||||
# azure\_security\_group\_rule
|
||||
|
||||
Creates a new network security rule to be associated with a given security group.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_security_group" "web" {
|
||||
...
|
||||
}
|
||||
|
||||
resource "azure_security_group_rule" "ssh_access" {
|
||||
name = "ssh-access-rule"
|
||||
security_group_name = "${azure_security_group.web.name}"
|
||||
type = "Inbound"
|
||||
action = "Allow"
|
||||
priority = 200
|
||||
source_address_prefix = "100.0.0.0/32"
|
||||
source_port_range = "*"
|
||||
destination_address_prefix = "10.0.0.0/32"
|
||||
destination_port_range = "22"
|
||||
protocol = "TCP"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
* `name` - (Required) The name of the security group the rule should be
|
||||
applied to.
|
||||
|
||||
* `security_group_name` - (Required) The name of the security group m
|
||||
|
||||
* `type` - (Required) The type of the security rule. Valid options are:
|
||||
`Inbound` and `Outbound`.
|
||||
|
||||
* `priority` - (Required) The priority of the network security rule. Rules with
|
||||
lower priority are evaluated first. This value can be between 100 and 4096.
|
||||
|
||||
* `action` - (Optional) The action that is performed when the security rule is
|
||||
matched. Valid options are: `Allow` and `Deny`.
|
||||
|
||||
* `source_address_prefix` - (Required) The address prefix of packet sources that
|
||||
that should be subjected to the rule. An asterisk (\*) can also be used to
|
||||
match all source IPs.
|
||||
|
||||
* `source_port_range` - (Required) The source port or range. This value can be
|
||||
between 0 and 65535. An asterisk (\*) can also be used to match all ports.
|
||||
|
||||
* `destination_address_prefix` - (Required) The address prefix of packet
|
||||
destinations that should be subjected to the rule. An asterisk
|
||||
(\*) can also be used to match all destination IPs.
|
||||
|
||||
* `destination_port_range` - (Required) The destination port or range. This value
|
||||
can be between 0 and 65535. An asterisk (\*) can also be used to match all
|
||||
ports.
|
||||
|
||||
* `protocol` - (Optional) The protocol of the security rule. Valid options are:
|
||||
`TCP`, `UDP` and `*`.
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The security group rule ID. Coincides with its given `name`.
|
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_storage_blob"
|
||||
sidebar_current: "docs-azure-storage-blob"
|
||||
description: |-
|
||||
Creates a new storage blob within a given storage container on Azure.
|
||||
---
|
||||
|
||||
# azure\_storage\_blob
|
||||
|
||||
Creates a new storage blob within a given storage container on Azure.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_storage_blob" "foo" {
|
||||
name = "tftesting-blob"
|
||||
storage_service_name = "tfstorserv"
|
||||
storage_container_name = "terraform-storage-container"
|
||||
type = "PageBlob"
|
||||
size = 1024
|
||||
}
|
||||
````
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the storage blob. Must be unique within
|
||||
the storage service the blob is located.
|
||||
|
||||
* `storage_service_name` - (Required) The name of the storage service within
|
||||
which the storage container in which the blob will be created resides.
|
||||
|
||||
* `storage_container_name` - (Required) The name of the storage container
|
||||
in which this blob should be created. Must be located on the storage
|
||||
service given with `storage_service_name`.
|
||||
|
||||
* `type` - (Required) The type of the storage blob to be created. One of either
|
||||
`BlockBlob` or `PageBlob`.
|
||||
|
||||
* `size` - (Optional) Used only for `PageBlob`'s to specify the size in bytes
|
||||
of the blob to be created. Must be a multiple of 512. Defaults to 0.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The storage blob ID. Coincides with the given `name`.
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_storage_container"
|
||||
sidebar_current: "docs-azure-storage-container"
|
||||
description: |-
|
||||
Creates a new storage container within a given storage service on Azure.
|
||||
---
|
||||
|
||||
# azure\_storage\_container
|
||||
|
||||
Creates a new storage container within a given storage service on Azure.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_storage_container" "stor-cont" {
|
||||
name = "terraform-storage-container"
|
||||
container_access_type = "blob"
|
||||
storage_service_name = "tfstorserv"
|
||||
}
|
||||
````
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the storage container. Must be unique within
|
||||
the storage service the container is located.
|
||||
|
||||
* `storage_service_name` - (Required) The name of the storage service within
|
||||
which the storage container should be created.
|
||||
|
||||
* `container_access_type` - (Required) The 'interface' for access the container
|
||||
provides. Can be either `blob`, `container` or ``.
|
||||
|
||||
* `properties` - (Optional) Key-value definition of additional properties
|
||||
associated to the storage service.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The storage container ID. Coincides with the given `name`.
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_storage_queue"
|
||||
sidebar_current: "docs-azure-storage-queue"
|
||||
description: |-
|
||||
Creates a new storage queue within a given storage service on Azure.
|
||||
---
|
||||
|
||||
# azure\_storage\_queue
|
||||
|
||||
Creates a new storage queue within a given storage service on Azure.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_storage_queue" "stor-queue" {
|
||||
name = "terraform-storage-queue"
|
||||
storage_service_name = "tfstorserv"
|
||||
}
|
||||
````
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the storage queue. Must be unique within
|
||||
the storage service the queue is located.
|
||||
|
||||
* `storage_service_name` - (Required) The name of the storage service within
|
||||
which the storage queue should be created.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The storage queue ID. Coincides with the given `name`.
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_storage_service"
|
||||
sidebar_current: "docs-azure-storage-service"
|
||||
description: |-
|
||||
Creates a new storage service on Azure in which storage containers may be created.
|
||||
---
|
||||
|
||||
# azure\_storage\_service
|
||||
|
||||
Creates a new storage service on Azure in which storage containers may be created.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_storage_service" "tfstor" {
|
||||
name = "tfstor"
|
||||
location = "West US"
|
||||
description = "Made by Terraform."
|
||||
account_type = "Standard_LRS"
|
||||
}
|
||||
````
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the storage service. Must be between 4 and 24
|
||||
lowercase-only characters or digits Must be unique on Azure.
|
||||
|
||||
* `location` - (Required) The location where the storage service should be created.
|
||||
For a list of all Azure locations, please consult [this link](http://azure.microsoft.com/en-us/regions/).
|
||||
|
||||
* `account_type` - (Required) The type of storage account to be created.
|
||||
Available options include `Standard_LRS`, `Standard_ZRS`, `Standard_GRS`,
|
||||
`Standard_RAGRS` and `Premium_LRS`. To learn more about the differences
|
||||
of each storage account type, please consult [this link](http://blogs.msdn.com/b/windowsazurestorage/archive/2013/12/11/introducing-read-access-geo-replicated-storage-ra-grs-for-windows-azure-storage.aspx).
|
||||
|
||||
* `affinity_group` - (Optional) The affinity group the storage service should
|
||||
belong to.
|
||||
|
||||
* `properties` - (Optional) Key-value definition of additional properties
|
||||
associated to the storage service. For additional information on what
|
||||
these properties do, please consult [this link](https://msdn.microsoft.com/en-us/library/azure/hh452235.aspx).
|
||||
|
||||
* `label` - (Optional) A label to be used for tracking purposes. Must be
|
||||
non-void. Defaults to `Made by Terraform.`.
|
||||
|
||||
* `description` - (Optional) A description for the storage service.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The storage service ID. Coincides with the given `name`.
|
|
@ -40,6 +40,9 @@ The following arguments are supported:
|
|||
* `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.
|
||||
|
||||
|
|
|
@ -17,14 +17,46 @@
|
|||
<a href="/docs/providers/azure/r/data_disk.html">azure_data_disk</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-dns-server") %>>
|
||||
<a href="/docs/providers/azure/r/dns_server.html">azure_dns_server</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-hosted-service") %>>
|
||||
<a href="/docs/providers/azure/r/hosted_service.html">azure_hosted_service</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-instance") %>>
|
||||
<a href="/docs/providers/azure/r/instance.html">azure_instance</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-local-network") %>>
|
||||
<a href="/docs/providers/azure/r/local_network_connection.html">azure_local_network_connection</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-security-group") %>>
|
||||
<a href="/docs/providers/azure/r/security_group.html">azure_security_group</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-security-group-rule") %>>
|
||||
<a href="/docs/providers/azure/r/security_group_rule.html">azure_security_group_rule</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-storage-blob") %>>
|
||||
<a href="/docs/providers/azure/r/storage_blob.html">azure_storage_blob</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-storage-container") %>>
|
||||
<a href="/docs/providers/azure/r/storage_container.html">azure_storage_container</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-storage-queue") %>>
|
||||
<a href="/docs/providers/azure/r/storage_queue.html">azure_storage_queue</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-storage-service") %>>
|
||||
<a href="/docs/providers/azure/r/storage_service.html">azure_storage_service</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-virtual-network") %>>
|
||||
<a href="/docs/providers/azure/r/virtual_network.html">azure_virtual_network</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue