Merge resources unto upstream.
This commit is contained in:
parent
dd24b58bf3
commit
9670e69613
Binary file not shown.
|
@ -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,17 @@ func Provider() terraform.ResourceProvider {
|
|||
},
|
||||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"azure_data_disk": resourceAzureDataDisk(),
|
||||
"azure_instance": resourceAzureInstance(),
|
||||
"azure_security_group": resourceAzureSecurityGroup(),
|
||||
"azure_data_disk": resourceAzureDataDisk(),
|
||||
"azure_hosted_service": resourceAzureHostedService(),
|
||||
"azure_storage_service": resourceAzureStorageService(),
|
||||
"azure_storage_container": resourceAzureStorageContainer(),
|
||||
"azure_storage_blob": resourceAzureStorageBlob(),
|
||||
"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,17 @@ 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.
|
||||
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}"
|
||||
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}"
|
||||
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}"
|
||||
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}"
|
||||
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
|
||||
|
|
|
@ -5,11 +5,11 @@ import (
|
|||
"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 +313,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 +324,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 +346,24 @@ 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"
|
||||
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 +378,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" {
|
||||
|
@ -399,38 +400,40 @@ 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"
|
||||
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"
|
||||
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 +455,4 @@ resource "azure_instance" "foo" {
|
|||
public_port = 5985
|
||||
private_port = 5985
|
||||
}
|
||||
}`, os.Getenv("AZURE_STORAGE"))
|
||||
}`, testAccStorageServiceName)
|
||||
|
|
|
@ -0,0 +1,265 @@
|
|||
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, ok := meta.(*Client)
|
||||
if !ok {
|
||||
return fmt.Errorf("Failed to convert to *Client, got: %T", meta)
|
||||
}
|
||||
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, ok := meta.(*Client)
|
||||
if !ok {
|
||||
return fmt.Errorf("Failed to convert to *Client, got: %T", meta)
|
||||
}
|
||||
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, ok := meta.(*Client)
|
||||
if !ok {
|
||||
return fmt.Errorf("Failed to convert to *Client, got: %T", meta)
|
||||
}
|
||||
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, ok := meta.(*Client)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("Failed to convert to *Client, got: %T", meta)
|
||||
}
|
||||
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, ok := meta.(*Client)
|
||||
if !ok {
|
||||
return fmt.Errorf("Failed to convert to *Client, got: %T", meta)
|
||||
}
|
||||
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,320 @@
|
|||
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"],
|
||||
},
|
||||
// TODO(aznashwan): update Sander's docs to remove default.
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_type"],
|
||||
},
|
||||
"priority": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
Description: parameterDescriptions["netsecgroup_priority"],
|
||||
},
|
||||
// TODO(aznashwan): update Sander's docs to remove default.
|
||||
"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"],
|
||||
},
|
||||
// TODO(aznashwan): update Sander's docs to remove default.
|
||||
"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{
|
||||
// TODO(aznashwan): security checks here:
|
||||
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{
|
||||
// TODO(azhnashwan): Parameter check here:
|
||||
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,186 @@
|
|||
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,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return "BlockBlob", nil
|
||||
},
|
||||
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,139 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureStorageBlockBlobConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureStorageBlobExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "tftesting-blob"),
|
||||
resource.TestCheckResourceAttr(name, "type", "BlockBlob"),
|
||||
resource.TestCheckResourceAttr(name, "storage_container_name", testAccStorageContainerName),
|
||||
resource.TestCheckResourceAttr(name, "storage_service_name", testAccStorageServiceName),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// because containers take a while to get deleted, sleep for a while:
|
||||
time.Sleep(5 * time.Minute)
|
||||
}
|
||||
|
||||
func TestAccAzureStoragePageBlob(t *testing.T) {
|
||||
name := "azure_storage_blob.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureStorageBlobDeleted,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureStoragePageBlobConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureStorageBlobExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "tftesting-blob"),
|
||||
resource.TestCheckResourceAttr(name, "type", "PageBlob"),
|
||||
resource.TestCheckResourceAttr(name, "size", "512"),
|
||||
resource.TestCheckResourceAttr(name, "storage_container_name", testAccStorageContainerName),
|
||||
resource.TestCheckResourceAttr(name, "storage_service_name", testAccStorageServiceName),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// because containers take a while to get deleted, sleep for a while:
|
||||
time.Sleep(5 * time.Minute)
|
||||
}
|
||||
|
||||
func testAccCheckAzureStorageBlobExists(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.BlobExists(testAccStorageContainerName, 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(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(testAccStorageContainerName, resource.Primary.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("Azure Storage Blob still exists.")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
var testAccAzureStorageBlockBlobConfig = testAccAzureStorageContainerConfig + fmt.Sprintf(`
|
||||
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 = "%s"
|
||||
storage_container_name = "%s"
|
||||
}
|
||||
`, testAccStorageServiceName, testAccStorageContainerName)
|
||||
|
||||
var testAccAzureStoragePageBlobConfig = testAccAzureStorageContainerConfig + fmt.Sprintf(`
|
||||
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 = "%s"
|
||||
storage_container_name = "%s"
|
||||
# NOTE: must be a multiple of 512:
|
||||
size = 512
|
||||
}
|
||||
`, testAccStorageServiceName, testAccStorageContainerName)
|
|
@ -0,0 +1,166 @@
|
|||
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,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return "", nil
|
||||
},
|
||||
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,96 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"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,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,31 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// getStorageServiceBlobClient is a helper function which returns the
|
||||
// storage.BlobStorageClient associated to the given storage account name.
|
||||
func getStorageServiceBlobClient(mgmtClient management.Client, serviceName string) (storage.BlobStorageClient, error) {
|
||||
log.Println("[INFO] Begun generating Azure Storage Service Blob client.")
|
||||
var blobClient storage.BlobStorageClient
|
||||
|
||||
storageServiceClient := storageservice.NewClient(mgmtClient)
|
||||
|
||||
keys, err := storageServiceClient.GetStorageServiceKeys(serviceName)
|
||||
if err != nil {
|
||||
return blobClient, fmt.Errorf("Error reading Storage Service %s's keys from Azure: %s", serviceName, err)
|
||||
}
|
||||
|
||||
storageClient, err := storage.NewBasicClient(serviceName, keys.PrimaryKey)
|
||||
if err != nil {
|
||||
return blobClient, fmt.Errorf("Error creating Storage Service Client for %s: %s", serviceName, err)
|
||||
}
|
||||
|
||||
return storageClient.GetBlobService(), nil
|
||||
}
|
|
@ -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
|
||||
|
@ -289,9 +292,12 @@ func createVirtualNetwork(d *schema.ResourceData) (virtualnetwork.VirtualNetwork
|
|||
return virtualnetwork.VirtualNetworkSite{
|
||||
Name: d.Get("name").(string),
|
||||
Location: d.Get("location").(string),
|
||||
AddressSpace: addressSpace,
|
||||
AddressSpace: virtualnetwork.AddressSpace{
|
||||
AddressPrefix: prefixes,
|
||||
},
|
||||
DNSServersRef: dnsRefs,
|
||||
Subnets: subnets,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue