Adding the last parts of the docs for the new Azure provider

Next to the remaining docs, I also updated the code so any Virtual
Network related API calls are now synchronised by using a mutex (thanks
@aznashwan for pointing that out!).
This commit is contained in:
Sander van Harmelen 2015-05-29 00:10:21 +02:00
parent a2aeb9f79d
commit cef8259923
17 changed files with 359 additions and 226 deletions

View File

@ -3,6 +3,7 @@ package azure
import ( import (
"fmt" "fmt"
"os" "os"
"sync"
"github.com/svanharmelen/azure-sdk-for-go/management" "github.com/svanharmelen/azure-sdk-for-go/management"
) )
@ -16,30 +17,42 @@ type Config struct {
ManagementURL string ManagementURL string
} }
// NewClient returns a new Azure management client which is created // Client contains all the handles required for managing Azure services.
// using different functions depending on the supplied settings type Client struct {
func (c *Config) NewClient() (management.Client, error) { // unfortunately; because of how Azure's network API works; doing networking operations
if c.SettingsFile != "" { // concurrently is very hazardous, and we need a mutex to guard the management.Client.
if _, err := os.Stat(c.SettingsFile); os.IsNotExist(err) { mutex *sync.Mutex
return nil, fmt.Errorf("Publish Settings file %q does not exist!", c.SettingsFile) mgmtClient management.Client
} }
return management.ClientFromPublishSettingsFile(c.SettingsFile, c.SubscriptionID) // NewClientFromSettingsFile returns a new Azure management
} // client created using a publish settings file.
func (c *Config) NewClientFromSettingsFile() (*Client, error) {
if c.ManagementURL != "" { if _, err := os.Stat(c.SettingsFile); os.IsNotExist(err) {
return management.NewClientFromConfig( return nil, fmt.Errorf("Publish Settings file %q does not exist!", c.SettingsFile)
c.SubscriptionID, }
c.Certificate,
management.ClientConfig{ManagementURL: c.ManagementURL}, mc, err := management.ClientFromPublishSettingsFile(c.SettingsFile, c.SubscriptionID)
) if err != nil {
} return nil, nil
}
if c.SubscriptionID != "" && len(c.Certificate) > 0 {
return management.NewClient(c.SubscriptionID, c.Certificate) return &Client{
} mutex: &sync.Mutex{},
mgmtClient: mc,
return nil, fmt.Errorf( }, nil
"Insufficient configuration data. Please specify either a 'settings_file'\n" + }
"or both a 'subscription_id' and 'certificate' with an optional 'management_url'.")
// NewClient returns a new Azure management client created
// using a subscription ID and certificate.
func (c *Config) NewClient() (*Client, error) {
mc, err := management.NewClient(c.SubscriptionID, c.Certificate)
if err != nil {
return nil, nil
}
return &Client{
mutex: &sync.Mutex{},
mgmtClient: mc,
}, nil
} }

View File

@ -1,6 +1,8 @@
package azure package azure
import ( import (
"fmt"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -26,12 +28,6 @@ func Provider() terraform.ResourceProvider {
Optional: true, Optional: true,
DefaultFunc: schema.EnvDefaultFunc("AZURE_CERTIFICATE", ""), DefaultFunc: schema.EnvDefaultFunc("AZURE_CERTIFICATE", ""),
}, },
"management_url": &schema.Schema{
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("AZURE_MANAGEMENT_URL", ""),
},
}, },
ResourcesMap: map[string]*schema.Resource{ ResourcesMap: map[string]*schema.Resource{
@ -50,8 +46,17 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
SettingsFile: d.Get("settings_file").(string), SettingsFile: d.Get("settings_file").(string),
SubscriptionID: d.Get("subscription_id").(string), SubscriptionID: d.Get("subscription_id").(string),
Certificate: []byte(d.Get("certificate").(string)), Certificate: []byte(d.Get("certificate").(string)),
ManagementURL: d.Get("management_url").(string),
} }
return config.NewClient() if config.SettingsFile != "" {
return config.NewClientFromSettingsFile()
}
if config.SubscriptionID != "" && len(config.Certificate) > 0 {
return config.NewClient()
}
return nil, fmt.Errorf(
"Insufficient configuration data. Please specify either a 'settings_file'\n" +
"or both a 'subscription_id' and 'certificate'.")
} }

View File

@ -41,7 +41,7 @@ func resourceAzureDataDisk() *schema.Resource {
"size": &schema.Schema{ "size": &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Optional: true,
}, },
"caching": &schema.Schema{ "caching": &schema.Schema{
@ -78,7 +78,7 @@ func resourceAzureDataDisk() *schema.Resource {
} }
func resourceAzureDataDiskCreate(d *schema.ResourceData, meta interface{}) error { func resourceAzureDataDiskCreate(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
if err := verifyDataDiskParameters(d); err != nil { if err := verifyDataDiskParameters(d); err != nil {
return err return err
@ -129,7 +129,7 @@ func resourceAzureDataDiskCreate(d *schema.ResourceData, meta interface{}) error
} }
func resourceAzureDataDiskRead(d *schema.ResourceData, meta interface{}) error { func resourceAzureDataDiskRead(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
lun := d.Get("lun").(int) lun := d.Get("lun").(int)
vm := d.Get("virtual_machine").(string) vm := d.Get("virtual_machine").(string)
@ -163,7 +163,9 @@ func resourceAzureDataDiskRead(d *schema.ResourceData, meta interface{}) error {
} }
func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
diskClient := virtualmachinedisk.NewClient(mc)
lun := d.Get("lun").(int) lun := d.Get("lun").(int)
vm := d.Get("virtual_machine").(string) vm := d.Get("virtual_machine").(string)
@ -172,7 +174,7 @@ func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error
ovm, _ := d.GetChange("virtual_machine") ovm, _ := d.GetChange("virtual_machine")
log.Printf("[DEBUG] Detaching data disk: %s", d.Id()) log.Printf("[DEBUG] Detaching data disk: %s", d.Id())
req, err := virtualmachinedisk.NewClient(mc). req, err := diskClient.
DeleteDataDisk(ovm.(string), ovm.(string), ovm.(string), olun.(int), false) DeleteDataDisk(ovm.(string), ovm.(string), ovm.(string), olun.(int), false)
if err != nil { if err != nil {
return fmt.Errorf("Error detaching data disk %s: %s", d.Id(), err) return fmt.Errorf("Error detaching data disk %s: %s", d.Id(), err)
@ -186,7 +188,7 @@ func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error
log.Printf("[DEBUG] Verifying data disk %s is properly detached...", d.Id()) log.Printf("[DEBUG] Verifying data disk %s is properly detached...", d.Id())
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
disk, err := virtualmachinedisk.NewClient(mc).GetDisk(d.Id()) disk, err := diskClient.GetDisk(d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error retrieving disk %s: %s", d.Id(), err) return fmt.Errorf("Error retrieving disk %s: %s", d.Id(), err)
} }
@ -208,7 +210,7 @@ func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error
} }
log.Printf("[DEBUG] Updating disk: %s", d.Id()) log.Printf("[DEBUG] Updating disk: %s", d.Id())
req, err := virtualmachinedisk.NewClient(mc).UpdateDisk(d.Id(), p) req, err := diskClient.UpdateDisk(d.Id(), p)
if err != nil { if err != nil {
return fmt.Errorf("Error updating disk %s: %s", d.Id(), err) return fmt.Errorf("Error updating disk %s: %s", d.Id(), err)
} }
@ -228,7 +230,7 @@ func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error
} }
log.Printf("[DEBUG] Attaching data disk: %s", d.Id()) log.Printf("[DEBUG] Attaching data disk: %s", d.Id())
req, err = virtualmachinedisk.NewClient(mc).AddDataDisk(vm, vm, vm, p) req, err = diskClient.AddDataDisk(vm, vm, vm, p)
if err != nil { if err != nil {
return fmt.Errorf("Error attaching data disk %s to instance %s: %s", d.Id(), vm, err) return fmt.Errorf("Error attaching data disk %s to instance %s: %s", d.Id(), vm, err)
} }
@ -253,7 +255,7 @@ func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error
} }
log.Printf("[DEBUG] Updating data disk: %s", d.Id()) log.Printf("[DEBUG] Updating data disk: %s", d.Id())
req, err := virtualmachinedisk.NewClient(mc).UpdateDataDisk(vm, vm, vm, lun, p) req, err := diskClient.UpdateDataDisk(vm, vm, vm, lun, p)
if err != nil { if err != nil {
return fmt.Errorf("Error updating data disk %s: %s", d.Id(), err) return fmt.Errorf("Error updating data disk %s: %s", d.Id(), err)
} }
@ -269,7 +271,8 @@ func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error
} }
func resourceAzureDataDiskDelete(d *schema.ResourceData, meta interface{}) error { func resourceAzureDataDiskDelete(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
lun := d.Get("lun").(int) lun := d.Get("lun").(int)
vm := d.Get("virtual_machine").(string) vm := d.Get("virtual_machine").(string)

View File

@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/svanharmelen/azure-sdk-for-go/management"
"github.com/svanharmelen/azure-sdk-for-go/management/virtualmachinedisk" "github.com/svanharmelen/azure-sdk-for-go/management/virtualmachinedisk"
) )
@ -102,7 +101,7 @@ func testAccCheckAzureDataDiskExists(
return err return err
} }
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
d, err := virtualmachinedisk.NewClient(mc).GetDataDisk(vm, vm, vm, lun) d, err := virtualmachinedisk.NewClient(mc).GetDataDisk(vm, vm, vm, lun)
if err != nil { if err != nil {
return err return err
@ -139,7 +138,7 @@ func testAccCheckAzureDataDiskAttributes(
} }
func testAccCheckAzureDataDiskDestroy(s *terraform.State) error { func testAccCheckAzureDataDiskDestroy(s *terraform.State) error {
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "azure_data_disk" { if rs.Type != "azure_data_disk" {

View File

@ -89,6 +89,7 @@ func resourceAzureInstance() *schema.Resource {
"automatic_updates": &schema.Schema{ "automatic_updates": &schema.Schema{
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: false,
ForceNew: true, ForceNew: true,
}, },
@ -129,7 +130,8 @@ func resourceAzureInstance() *schema.Resource {
"protocol": &schema.Schema{ "protocol": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
Default: "tcp",
}, },
"public_port": &schema.Schema{ "public_port": &schema.Schema{
@ -166,7 +168,7 @@ func resourceAzureInstance() *schema.Resource {
} }
func resourceAzureInstanceCreate(d *schema.ResourceData, meta interface{}) (err error) { func resourceAzureInstanceCreate(d *schema.ResourceData, meta interface{}) (err error) {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
name := d.Get("name").(string) name := d.Get("name").(string)
@ -324,7 +326,7 @@ func resourceAzureInstanceCreate(d *schema.ResourceData, meta interface{}) (err
} }
func resourceAzureInstanceRead(d *schema.ResourceData, meta interface{}) error { func resourceAzureInstanceRead(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
log.Printf("[DEBUG] Retrieving Cloud Service for instance: %s", d.Id()) log.Printf("[DEBUG] Retrieving Cloud Service for instance: %s", d.Id())
cs, err := hostedservice.NewClient(mc).GetHostedService(d.Id()) cs, err := hostedservice.NewClient(mc).GetHostedService(d.Id())
@ -414,7 +416,7 @@ func resourceAzureInstanceRead(d *schema.ResourceData, meta interface{}) error {
} }
func resourceAzureInstanceUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAzureInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
// First check if anything we can update changed, and if not just return // First check if anything we can update changed, and if not just return
if !d.HasChange("size") && !d.HasChange("endpoint") && !d.HasChange("security_group") { if !d.HasChange("size") && !d.HasChange("endpoint") && !d.HasChange("security_group") {
@ -490,7 +492,7 @@ func resourceAzureInstanceUpdate(d *schema.ResourceData, meta interface{}) error
} }
func resourceAzureInstanceDelete(d *schema.ResourceData, meta interface{}) error { func resourceAzureInstanceDelete(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
log.Printf("[DEBUG] Deleting instance: %s", d.Id()) log.Printf("[DEBUG] Deleting instance: %s", d.Id())
req, err := hostedservice.NewClient(mc).DeleteHostedService(d.Id(), true) req, err := hostedservice.NewClient(mc).DeleteHostedService(d.Id(), true)

View File

@ -7,7 +7,6 @@ import (
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "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/hostedservice"
"github.com/svanharmelen/azure-sdk-for-go/management/virtualmachine" "github.com/svanharmelen/azure-sdk-for-go/management/virtualmachine"
) )
@ -132,7 +131,7 @@ func testAccCheckAzureInstanceExists(
return fmt.Errorf("No instance ID is set") return fmt.Errorf("No instance ID is set")
} }
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
vm, err := virtualmachine.NewClient(mc).GetDeployment(rs.Primary.ID, rs.Primary.ID) vm, err := virtualmachine.NewClient(mc).GetDeployment(rs.Primary.ID, rs.Primary.ID)
if err != nil { if err != nil {
return err return err
@ -284,7 +283,7 @@ func testAccCheckAzureInstanceUpdatedAttributes(
} }
func testAccCheckAzureInstanceDestroy(s *terraform.State) error { func testAccCheckAzureInstanceDestroy(s *terraform.State) error {
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "azure_instance" { if rs.Type != "azure_instance" {

View File

@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"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/networksecuritygroup"
) )
@ -100,7 +99,7 @@ func resourceAzureSecurityGroup() *schema.Resource {
} }
func resourceAzureSecurityGroupCreate(d *schema.ResourceData, meta interface{}) (err error) { func resourceAzureSecurityGroupCreate(d *schema.ResourceData, meta interface{}) (err error) {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
name := d.Get("name").(string) name := d.Get("name").(string)
@ -152,8 +151,10 @@ func resourceAzureSecurityGroupCreate(d *schema.ResourceData, meta interface{})
} }
func resourceAzureSecurityGroupRuleCreate( func resourceAzureSecurityGroupRuleCreate(
d *schema.ResourceData, meta interface{}, rule map[string]interface{}) error { d *schema.ResourceData,
mc := meta.(management.Client) meta interface{},
rule map[string]interface{}) error {
mc := meta.(*Client).mgmtClient
// Make sure all required parameters are there // Make sure all required parameters are there
if err := verifySecurityGroupRuleParams(rule); err != nil { if err := verifySecurityGroupRuleParams(rule); err != nil {
@ -189,7 +190,7 @@ func resourceAzureSecurityGroupRuleCreate(
} }
func resourceAzureSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { func resourceAzureSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
sg, err := networksecuritygroup.NewClient(mc).GetNetworkSecurityGroup(d.Id()) sg, err := networksecuritygroup.NewClient(mc).GetNetworkSecurityGroup(d.Id())
if err != nil { if err != nil {
@ -264,7 +265,7 @@ func resourceAzureSecurityGroupUpdate(d *schema.ResourceData, meta interface{})
} }
func resourceAzureSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { func resourceAzureSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
log.Printf("[DEBUG] Deleting Network Security Group: %s", d.Id()) log.Printf("[DEBUG] Deleting Network Security Group: %s", d.Id())
req, err := networksecuritygroup.NewClient(mc).DeleteNetworkSecurityGroup(d.Id()) req, err := networksecuritygroup.NewClient(mc).DeleteNetworkSecurityGroup(d.Id())
@ -285,7 +286,7 @@ func resourceAzureSecurityGroupDelete(d *schema.ResourceData, meta interface{})
func resourceAzureSecurityGroupRuleDelete( func resourceAzureSecurityGroupRuleDelete(
d *schema.ResourceData, meta interface{}, rule map[string]interface{}) error { d *schema.ResourceData, meta interface{}, rule map[string]interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
name := rule["name"].(string) name := rule["name"].(string)

View File

@ -6,7 +6,6 @@ import (
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"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/networksecuritygroup"
) )
@ -104,7 +103,7 @@ func testAccCheckAzureSecurityGroupExists(
return fmt.Errorf("No Network Security Group ID is set") return fmt.Errorf("No Network Security Group ID is set")
} }
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
sg, err := networksecuritygroup.NewClient(mc).GetNetworkSecurityGroup(rs.Primary.ID) sg, err := networksecuritygroup.NewClient(mc).GetNetworkSecurityGroup(rs.Primary.ID)
if err != nil { if err != nil {
return err return err
@ -204,7 +203,7 @@ func testAccCheckAzureSecurityGroupUpdatedAttributes(
} }
func testAccCheckAzureSecurityGroupDestroy(s *terraform.State) error { func testAccCheckAzureSecurityGroupDestroy(s *terraform.State) error {
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "azure_security_group" { if rs.Type != "azure_security_group" {

View File

@ -69,10 +69,16 @@ func resourceAzureVirtualNetwork() *schema.Resource {
} }
func resourceAzureVirtualNetworkCreate(d *schema.ResourceData, meta interface{}) error { func resourceAzureVirtualNetworkCreate(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) ac := meta.(*Client)
mc := ac.mgmtClient
name := d.Get("name").(string) name := d.Get("name").(string)
// Lock the client just before we get the virtual network configuration and immediately
// set an defer to unlock the client again whenever this function exits
ac.mutex.Lock()
defer ac.mutex.Unlock()
nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration() nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
if err != nil { if err != nil {
if strings.Contains(err.Error(), "ResourceNotFound") { if strings.Contains(err.Error(), "ResourceNotFound") {
@ -115,7 +121,7 @@ func resourceAzureVirtualNetworkCreate(d *schema.ResourceData, meta interface{})
} }
func resourceAzureVirtualNetworkRead(d *schema.ResourceData, meta interface{}) error { func resourceAzureVirtualNetworkRead(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration() nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
if err != nil { if err != nil {
@ -165,7 +171,13 @@ func resourceAzureVirtualNetworkRead(d *schema.ResourceData, meta interface{}) e
} }
func resourceAzureVirtualNetworkUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAzureVirtualNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) ac := meta.(*Client)
mc := ac.mgmtClient
// Lock the client just before we get the virtual network configuration and immediately
// set an defer to unlock the client again whenever this function exits
ac.mutex.Lock()
defer ac.mutex.Unlock()
nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration() nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
if err != nil { if err != nil {
@ -208,7 +220,13 @@ func resourceAzureVirtualNetworkUpdate(d *schema.ResourceData, meta interface{})
} }
func resourceAzureVirtualNetworkDelete(d *schema.ResourceData, meta interface{}) error { func resourceAzureVirtualNetworkDelete(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) ac := meta.(*Client)
mc := ac.mgmtClient
// Lock the client just before we get the virtual network configuration and immediately
// set an defer to unlock the client again whenever this function exits
ac.mutex.Lock()
defer ac.mutex.Unlock()
nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration() nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
if err != nil { if err != nil {
@ -277,7 +295,8 @@ func createVirtualNetwork(d *schema.ResourceData) (virtualnetwork.VirtualNetwork
} }
func associateSecurityGroups(d *schema.ResourceData, meta interface{}) error { func associateSecurityGroups(d *schema.ResourceData, meta interface{}) error {
mc := meta.(management.Client) mc := meta.(*Client).mgmtClient
nsgClient := networksecuritygroup.NewClient(mc)
virtualNetwork := d.Get("name").(string) virtualNetwork := d.Get("name").(string)
@ -288,8 +307,7 @@ func associateSecurityGroups(d *schema.ResourceData, meta interface{}) error {
subnetName := subnet["name"].(string) subnetName := subnet["name"].(string)
// Get the associated (if any) security group // Get the associated (if any) security group
sg, err := networksecuritygroup.NewClient(mc). sg, err := nsgClient.GetNetworkSecurityGroupForSubnet(subnetName, d.Id())
GetNetworkSecurityGroupForSubnet(subnetName, d.Id())
if err != nil && !management.IsResourceNotFoundError(err) { if err != nil && !management.IsResourceNotFoundError(err) {
return fmt.Errorf( return fmt.Errorf(
"Error retrieving Network Security Group associations of subnet %s: %s", subnetName, err) "Error retrieving Network Security Group associations of subnet %s: %s", subnetName, err)
@ -302,8 +320,7 @@ func associateSecurityGroups(d *schema.ResourceData, meta interface{}) error {
// If there is an associated security group, make sure we first remove it from the subnet // If there is an associated security group, make sure we first remove it from the subnet
if sg.Name != "" { if sg.Name != "" {
req, err := networksecuritygroup.NewClient(mc). req, err := nsgClient.RemoveNetworkSecurityGroupFromSubnet(sg.Name, subnetName, virtualNetwork)
RemoveNetworkSecurityGroupFromSubnet(sg.Name, subnetName, virtualNetwork)
if err != nil { if err != nil {
return fmt.Errorf("Error removing Network Security Group %s from subnet %s: %s", return fmt.Errorf("Error removing Network Security Group %s from subnet %s: %s",
securityGroup, subnetName, err) securityGroup, subnetName, err)
@ -319,8 +336,7 @@ func associateSecurityGroups(d *schema.ResourceData, meta interface{}) error {
// If the desired security group is not empty, assign the security group to the subnet // If the desired security group is not empty, assign the security group to the subnet
if securityGroup != "" { if securityGroup != "" {
req, err := networksecuritygroup.NewClient(mc). req, err := nsgClient.AddNetworkSecurityToSubnet(securityGroup, subnetName, virtualNetwork)
AddNetworkSecurityToSubnet(securityGroup, subnetName, virtualNetwork)
if err != nil { if err != nil {
return fmt.Errorf("Error associating Network Security Group %s to subnet %s: %s", return fmt.Errorf("Error associating Network Security Group %s to subnet %s: %s",
securityGroup, subnetName, err) securityGroup, subnetName, err)

View File

@ -6,7 +6,6 @@ import (
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/svanharmelen/azure-sdk-for-go/management"
"github.com/svanharmelen/azure-sdk-for-go/management/virtualnetwork" "github.com/svanharmelen/azure-sdk-for-go/management/virtualnetwork"
) )
@ -138,7 +137,7 @@ func testAccCheckAzureVirtualNetworkExists(
return fmt.Errorf("No Virtual Network ID is set") return fmt.Errorf("No Virtual Network ID is set")
} }
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration() nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
if err != nil { if err != nil {
return err return err
@ -173,7 +172,7 @@ func testAccCheckAzureVirtualNetworkAttributes(
} }
func testAccCheckAzureVirtualNetworkDestroy(s *terraform.State) error { func testAccCheckAzureVirtualNetworkDestroy(s *terraform.State) error {
mc := testAccProvider.Meta().(management.Client) mc := testAccProvider.Meta().(*Client).mgmtClient
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "azure_virtual_network" { if rs.Type != "azure_virtual_network" {

View File

@ -33,11 +33,16 @@ resource "azure_instance" "web" {
The following arguments are supported: The following arguments are supported:
* `settings_file` - (Required) The path to a publish settings file used to * `settings_file` - (Optional) The path to a publish settings file used to
authenticate with the Azure API. You can download the settings file here: authenticate with the Azure API. You can download the settings file here:
https://manage.windowsazure.com/publishsettings. It must be provided, but https://manage.windowsazure.com/publishsettings. You must either provide
it can also be sourced from the `AZURE_SETTINGS_FILE` environment variable. (or source from the `AZURE_SETTINGS_FILE` environment variable) a settings
file or both a `subscription_id` and `certificate`.
* `subscription_id` - (Optional) The subscription ID to use. If not provided * `subscription_id` - (Optional) The subscription ID to use. If a
the first subscription ID in publish settings file will be used. It can `settings_file` is not provided `subscription_id` is required. It can also
also be sourced from the `AZURE_SUBSCRIPTION_ID` environment variable. be sourced from the `AZURE_SUBSCRIPTION_ID` environment variable.
* `certificate` - (Optional) The certificate used to authenticate with the
Azure API. If a `settings_file` is not provided `certificate` is required.
It can also be sourced from the `AZURE_CERTIFICATE` environment variable.

View File

@ -0,0 +1,70 @@
---
layout: "azure"
page_title: "Azure: azure_data_disk"
sidebar_current: "docs-azure-resource-data-disk"
description: |-
Adds a data disk to a virtual machine. If the name of an existing disk is given, it will attach that disk. Otherwise it will create and attach a new empty disk.
---
# azure\_data\_disk
Adds a data disk to a virtual machine. If the name of an existing disk is given,
it will attach that disk. Otherwise it will create and attach a new empty disk.
## Example Usage
```
resource "azure_data_disk" "data" {
lun = 0
size = 10
storage = "yourstorage"
virtual_machine = "server1"
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Optional) The name of an existing registered disk to attach to the
virtual machine. If left empty, a new empty disk will be created and
attached instead. Changing this forces a new resource to be created.
* `label` - (Optional) The identifier of the data disk. Changing this forces a
new resource to be created (defaults to "virtual_machine-lun")
* `lun` - (Required) The Logical Unit Number (LUN) for the disk. The LUN
specifies the slot in which the data drive appears when mounted for usage
by the virtual machine. Valid LUN values are 0 through 31.
* `size` - (Optional) The size, in GB, of an empty disk to be attached to the
virtual machine. Required when creating a new disk, not used otherwise.
* `caching` - (Optional) The caching behavior of data disk. Valid options are:
`None`, `ReadOnly` and `ReadWrite` (defaults `None`)
* `storage ` - (Optional) The name of an existing storage account within the
subscription which will be used to store the VHD of this disk. Required
if no value is supplied for `media_link`. Changing this forces a new
resource to be created.
* `media_link` - (Optional) The location of the blob in storage where the VHD
of this disk will be created. The storage account where must be associated
with the subscription. Changing this forces a new resource to be created.
* `source_media_link` - (Optional) The location of a blob in storage where a
VHD file is located that is imported and registered as a disk. If a value
is supplied, `media_link` will not be used.
* `virtual_machine` - (Required) The name of the virtual machine the disk will
be attached to.
## Attributes Reference
The following attributes are exported:
* `id` - The security group ID.
* `name` - The name of the disk.
* `label` - The identifier for the disk.
* `media_link` - The location of the blob in storage where the VHD of this disk
is created.

View File

@ -1,58 +0,0 @@
---
layout: "cloudstack"
page_title: "CloudStack: cloudstack_disk"
sidebar_current: "docs-cloudstack-resource-disk"
description: |-
Creates a disk volume from a disk offering. This disk volume will be attached to a virtual machine if the optional parameters are configured.
---
# cloudstack\_disk
Creates a disk volume from a disk offering. This disk volume will be attached to
a virtual machine if the optional parameters are configured.
## Example Usage
```
resource "cloudstack_disk" "default" {
name = "test-disk"
attach = "true"
disk_offering = "custom"
size = 50
virtual-machine = "server-1"
zone = "zone-1"
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) The name of the disk volume. Changing this forces a new
resource to be created.
* `attach` - (Optional) Determines whether or not to attach the disk volume to a
virtual machine (defaults false).
* `device` - (Optional) The device to map the disk volume to within the guest OS.
* `disk_offering` - (Required) The name or ID of the disk offering to use for
this disk volume.
* `size` - (Optional) The size of the disk volume in gigabytes.
* `shrink_ok` - (Optional) Verifies if the disk volume is allowed to shrink when
resizing (defaults false).
* `virtual_machine` - (Optional) The name of the virtual machine to which you
want to attach the disk volume.
* `zone` - (Required) The name or ID of the zone where this disk volume will be available.
Changing this forces a new resource to be created.
## Attributes Reference
The following attributes are exported:
* `id` - The ID of the disk volume.
* `device` - The device the disk volume is mapped to within the guest OS.

View File

@ -3,23 +3,32 @@ layout: "azure"
page_title: "Azure: azure_instance" page_title: "Azure: azure_instance"
sidebar_current: "docs-azure-resource-instance" sidebar_current: "docs-azure-resource-instance"
description: |- description: |-
Creates and automatically starts a virtual machine based on a service offering, disk offering, and template. Creates a hosted service, role and deployment and then creates a virtual machine in the deployment based on the specified configuration.
--- ---
# azure\_instance # azure\_instance
Creates and automatically starts a virtual machine based on a service offering, Creates a hosted service, role and deployment and then creates a virtual
disk offering, and template. machine in the deployment based on the specified configuration.
## Example Usage ## Example Usage
``` ```
resource "azure_instance" "web" { resource "azure_instance" "web" {
name = "server-1" name = "terraform-test"
service_offering= "small" image = "Ubuntu Server 14.04 LTS"
network = "network-1" size = "Basic_A1"
template = "CentOS 6.5" storage = "yourstorage"
zone = "zone-1" location = "West US"
username = "terraform"
password = "Pass!admin123"
endpoint {
name = "SSH"
protocol = "tcp"
public_port = 22
private_port = 22
}
} }
``` ```
@ -30,30 +39,81 @@ The following arguments are supported:
* `name` - (Required) The name of the instance. Changing this forces a new * `name` - (Required) The name of the instance. Changing this forces a new
resource to be created. resource to be created.
* `display_name` - (Optional) The display name of the instance. * `description` - (Optional) The description for the associated hosted service.
Changing this forces a new resource to be created (defaults to the instance
name).
* `service_offering` - (Required) The name or ID of the service offering used for this instance. * `image` - (Required) The name of an existing VM or OS image to use for this
instance. Changing this forces a new resource to be created.
* `network` - (Optional) The name or ID of the network to connect this instance to. * `size` - (Required) The size of the instance.
* `subnet` - (Optional) The name of the subnet to connect this instance to. If
a value is supplied `virtual_network` is required. Changing this forces a
new resource to be created.
* `virtual_network` - (Optional) The name of the virtual network the `subnet`
belongs to. If a value is supplied `subnet` is required. Changing this
forces a new resource to be created.
* `storage` - (Optional) The name of an existing storage account within the
subscription which will be used to store the VHDs of this instance.
Changing this forces a new resource to be created. Changing this forces a new resource to be created.
* `ipaddress` - (Optional) The IP address to assign to this instance. Changing * `reverse_dns` - (Optional) The DNS address to which the IP address of the
hosted service resolves when queried using a reverse DNS query. Changing
this forces a new resource to be created. this forces a new resource to be created.
* `template` - (Required) The name or ID of the template used for this instance. * `location` - (Required) The location/region where the cloud service is
created. Changing this forces a new resource to be created.
* `automatic_updates` - (Optional) If true this will enable automatic updates.
This attribute is only used when creating a Windows instance. Changing this
forces a new resource to be created (defaults false)
* `time_zone` - (Optional) The appropriate time zone for this instance in the
format 'America/Los_Angeles'. This attribute is only used when creating a
Windows instance. Changing this forces a new resource to be created
(defaults false)
* `username` - (Required) The username of a new user that will be created while
creating the instance. Changing this forces a new resource to be created.
* `password` - (Optional) The password of the new user that will be created
while creating the instance. Required when creating a Windows instance or
when not supplying an `ssh_key_thumbprint` while creating a Linux instance.
Changing this forces a new resource to be created. Changing this forces a new resource to be created.
* `zone` - (Required) The name of the zone where this instance will be created. * `ssh_key_thumbprint` - (Optional) The SSH thumbprint of an existing SSH key
Changing this forces a new resource to be created. within the subscription. This attribute is only used when creating a Linux
instance. Changing this forces a new resource to be created.
* `user_data` - (Optional) The user data to provide when launching the instance. * `security_group` - (Optional) The Network Security Group to associate with
this instance.
* `expunge` - (Optional) This determines if the instance is expunged when it is * `endpoint` - (Optional) Can be specified multiple times to define multiple
destroyed (defaults false) endpoints. Each `endpoint` block supports fields documented below.
The `endpoint` block supports:
* `name` - (Required) The name of the external endpoint.
* `protocol` - (Optional) The transport protocol for the endpoint. Valid
options are: `tcp` and `udp` (defaults `tcp`)
* `public_port` - (Required) The external port to use for the endpoint.
* `private_port` - (Required) The private port on which the instance is
listening.
## Attributes Reference ## Attributes Reference
The following attributes are exported: The following attributes are exported:
* `id` - The instance ID. * `id` - The instance ID.
* `display_name` - The display name of the instance. * `description` - The description for the associated hosted service.
* `subnet` - The subnet the instance is connected to.
* `endpoint` - The complete set of configured endpoints.
* `security_group` - The associated Network Security Group.
* `ip_address` - The private IP address assigned to the instance.
* `vip_address` - The public IP address assigned to the instance.

View File

@ -1,28 +1,32 @@
--- ---
layout: "cloudstack" layout: "azure"
page_title: "CloudStack: cloudstack_network_acl_rule" page_title: "Azure: azure_security_group"
sidebar_current: "docs-cloudstack-resource-network-acl-rule" sidebar_current: "docs-azure-resource-security-group"
description: |- description: |-
Creates network ACL rules for a given network ACL. Creates a new network security group within the context of the specified subscription.
--- ---
# cloudstack\_network\_acl\_rule # azure\_security\_group
Creates network ACL rules for a given network ACL. Creates a new network security group within the context of the specified
subscription.
## Example Usage ## Example Usage
``` ```
resource "cloudstack_network_acl_rule" "default" { resource "azure_security_group" "web" {
aclid = "f3843ce0-334c-4586-bbd3-0c2e2bc946c6" name = "webservers"
location = "West US"
rule { rule {
action = "allow" name = "HTTPS"
source_cidr = "10.0.0.0/8" priority = 101
protocol = "tcp" source_cidr = "*"
ports = ["80", "1000-2000"] source_port = "*"
traffic_type = "ingress" destination_cidr = "*"
} destination_port = "443"
protocol = "TCP"
}
} }
``` ```
@ -30,40 +34,51 @@ resource "cloudstack_network_acl_rule" "default" {
The following arguments are supported: The following arguments are supported:
* `aclid` - (Required) The network ACL ID for which to create the rules. * `name` - (Required) The name of the security group. Changing this forces a
Changing this forces a new resource to be created. new resource to be created.
* `managed` - (Optional) USE WITH CAUTION! If enabled all the firewall rules for * `label` - (Optional) The identifier for the security group. The label can be
this network ACL will be managed by this resource. This means it will delete up to 1024 characters long. Changing this forces a new resource to be
all firewall rules that are not in your config! (defaults false) created (defaults to the security group name)
* `rule` - (Optional) Can be specified multiple times. Each rule block supports * `location` - (Required) The location/region where the security group is
fields documented below. If `managed = false` at least one rule is required! created. Changing this forces a new resource to be created.
* `rule` - (Required) Can be specified multiple times to define multiple
rules. Each `rule` block supports fields documented below.
The `rule` block supports: The `rule` block supports:
* `action` - (Optional) The action for the rule. Valid options are: `allow` and * `name` - (Required) The name of the security rule.
`deny` (defaults allow).
* `source_cidr` - (Required) The source CIDR to allow access to the given ports. * `type ` - (Optional) The type of the security rule. Valid options are:
`Inbound` and `Outbound` (defaults `Inbound`)
* `protocol` - (Required) The name of the protocol to allow. Valid options are: * `priority` - (Required) The priority of the network security rule. Rules with
`tcp`, `udp`, `icmp`, `all` or a valid protocol number. lower priority are evaluated first. This value can be between 100 and 4096.
* `icmp_type` - (Optional) The ICMP type to allow. This can only be specified if * `action` - (Optional) The action that is performed when the security rule is
the protocol is ICMP. matched. Valid options are: `Allow` and `Deny` (defaults `Allow`)
* `icmp_code` - (Optional) The ICMP code to allow. This can only be specified if * `source_cidr` - (Required) The CIDR or source IP range. An asterisk (\*) can
the protocol is ICMP. also be used to match all source IPs.
* `ports` - (Optional) List of ports and/or port ranges to allow. This can only * `source_port` - (Required) The source port or range. This value can be
be specified if the protocol is TCP, UDP, ALL or a valid protocol number. between 0 and 65535. An asterisk (\*) can also be used to match all ports.
* `traffic_type` - (Optional) The traffic type for the rule. Valid options are: * `destination_cidr` - (Required) The CIDR or destination IP range. An asterisk
`ingress` or `egress` (defaults ingress). (\*) can also be used to match all destination IPs.
* `destination_port` - (Required) The destination port or range. This value can
be between 0 and 65535. An asterisk (\*) can also be used to match all
ports.
* `protocol` - (Optional) The protocol of the security rule. Valid options are:
`TCP`, `UDP` and `*` (defaults `TCP`)
## Attributes Reference ## Attributes Reference
The following attributes are exported: The following attributes are exported:
* `id` - The ACL ID for which the rules are created. * `id` - The security group ID.
* `label` - The identifier for the security group.

View File

@ -1,25 +1,28 @@
--- ---
layout: "cloudstack" layout: "azure"
page_title: "CloudStack: cloudstack_network" page_title: "Azure: azure_virtual_network"
sidebar_current: "docs-cloudstack-resource-network" sidebar_current: "docs-azure-resource-virtual-network"
description: |- description: |-
Creates a network. Creates a new virtual network including any configured subnets. Each subnet can optionally be configured with a security group to be associated with the subnet.
--- ---
# cloudstack\_network # azure\_virtual\_network
Creates a network. Creates a new virtual network including any configured subnets. Each subnet can
optionally be configured with a security group to be associated with the subnet.
## Example Usage ## Example Usage
Basic usage:
``` ```
resource "cloudstack_network" "default" { resource "azure_virtual_network" "default" {
name = "test-network" name = "test-network"
cidr = "10.0.0.0/16" address_space = ["10.1.2.0/24"]
network_offering = "Default Network" location = "West US"
zone = "zone-1"
subnet {
name = "subnet1"
address_prefix = "10.1.2.0/25"
}
} }
``` ```
@ -27,28 +30,30 @@ resource "cloudstack_network" "default" {
The following arguments are supported: The following arguments are supported:
* `name` - (Required) The name of the network. * `name` - (Required) The name of the virtual network. Changing this forces a
new resource to be created.
* `display_text` - (Optional) The display text of the network. * `address_space` - (Required) The address space that is used the virtual
network. You can supply more than one address space. Changing this forces
a new resource to be created.
* `cidr` - (Required) The CIDR block for the network. Changing this forces a new * `location` - (Required) The location/region where the virtual network is
resource to be created. created. Changing this forces a new resource to be created.
* `network_offering` - (Required) The name or ID of the network offering to use * `subnet` - (Required) Can be specified multiple times to define multiple
for this network. subnets. Each `subnet` block supports fields documented below.
* `vpc` - (Optional) The name of the VPC to create this network for. Changing The `subnet` block supports:
this forces a new resource to be created.
* `aclid` - (Optional) The ID of a network ACL that should be attached to the * `name` - (Required) The name of the subnet.
network. Changing this forces a new resource to be created.
* `zone` - (Required) The name or ID of the zone where this disk volume will be * `address_prefix` - (Required) The address prefix to use for the subnet.
available. Changing this forces a new resource to be created.
* `security_group` - (Optional) The Network Security Group to associate with
the subnet.
## Attributes Reference ## Attributes Reference
The following attributes are exported: The following attributes are exported:
* `id` - The ID of the network. * `id` - The virtual NetworkConfiguration ID.
* `display_text` - The display text of the network.

View File

@ -13,8 +13,8 @@
<li<%= sidebar_current(/^docs-azure-resource/) %>> <li<%= sidebar_current(/^docs-azure-resource/) %>>
<a href="#">Resources</a> <a href="#">Resources</a>
<ul class="nav nav-visible"> <ul class="nav nav-visible">
<li<%= sidebar_current("docs-azure-resource-disk") %>> <li<%= sidebar_current("docs-azure-resource-data-disk") %>>
<a href="/docs/providers/azure/r/disk.html">azure_disk</a> <a href="/docs/providers/azure/r/data_disk.html">azure_data_disk</a>
</li> </li>
<li<%= sidebar_current("docs-azure-resource-instance") %>> <li<%= sidebar_current("docs-azure-resource-instance") %>>