github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/builtin/providers/azure/provider.go (about)

     1  package azure
     2  
     3  import (
     4  	"encoding/xml"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/hashicorp/terraform/terraform"
    11  	"github.com/mitchellh/go-homedir"
    12  )
    13  
    14  // Provider returns a terraform.ResourceProvider.
    15  func Provider() terraform.ResourceProvider {
    16  	return &schema.Provider{
    17  		Schema: map[string]*schema.Schema{
    18  			"settings_file": &schema.Schema{
    19  				Type:         schema.TypeString,
    20  				Optional:     true,
    21  				DefaultFunc:  schema.EnvDefaultFunc("AZURE_SETTINGS_FILE", nil),
    22  				ValidateFunc: validateSettingsFile,
    23  			},
    24  
    25  			"subscription_id": &schema.Schema{
    26  				Type:        schema.TypeString,
    27  				Optional:    true,
    28  				DefaultFunc: schema.EnvDefaultFunc("AZURE_SUBSCRIPTION_ID", ""),
    29  			},
    30  
    31  			"certificate": &schema.Schema{
    32  				Type:        schema.TypeString,
    33  				Optional:    true,
    34  				DefaultFunc: schema.EnvDefaultFunc("AZURE_CERTIFICATE", ""),
    35  			},
    36  		},
    37  
    38  		ResourcesMap: map[string]*schema.Resource{
    39  			"azure_instance":                          resourceAzureInstance(),
    40  			"azure_affinity_group":                    resourceAzureAffinityGroup(),
    41  			"azure_data_disk":                         resourceAzureDataDisk(),
    42  			"azure_sql_database_server":               resourceAzureSqlDatabaseServer(),
    43  			"azure_sql_database_server_firewall_rule": resourceAzureSqlDatabaseServerFirewallRule(),
    44  			"azure_sql_database_service":              resourceAzureSqlDatabaseService(),
    45  			"azure_hosted_service":                    resourceAzureHostedService(),
    46  			"azure_storage_service":                   resourceAzureStorageService(),
    47  			"azure_storage_container":                 resourceAzureStorageContainer(),
    48  			"azure_storage_blob":                      resourceAzureStorageBlob(),
    49  			"azure_storage_queue":                     resourceAzureStorageQueue(),
    50  			"azure_virtual_network":                   resourceAzureVirtualNetwork(),
    51  			"azure_dns_server":                        resourceAzureDnsServer(),
    52  			"azure_local_network_connection":          resourceAzureLocalNetworkConnection(),
    53  			"azure_security_group":                    resourceAzureSecurityGroup(),
    54  			"azure_security_group_rule":               resourceAzureSecurityGroupRule(),
    55  		},
    56  
    57  		ConfigureFunc: providerConfigure,
    58  	}
    59  }
    60  
    61  func providerConfigure(d *schema.ResourceData) (interface{}, error) {
    62  	config := Config{
    63  		SubscriptionID: d.Get("subscription_id").(string),
    64  		Certificate:    []byte(d.Get("certificate").(string)),
    65  	}
    66  
    67  	settingsFile := d.Get("settings_file").(string)
    68  	if settingsFile != "" {
    69  		// any errors from readSettings would have been caught at the validate
    70  		// step, so we can avoid handling them now
    71  		settings, _, _ := readSettings(settingsFile)
    72  		config.Settings = settings
    73  		return config.NewClientFromSettingsData()
    74  	}
    75  
    76  	if config.SubscriptionID != "" && len(config.Certificate) > 0 {
    77  		return config.NewClient()
    78  	}
    79  
    80  	return nil, fmt.Errorf(
    81  		"Insufficient configuration data. Please specify either a 'settings_file'\n" +
    82  			"or both a 'subscription_id' and 'certificate'.")
    83  }
    84  
    85  func validateSettingsFile(v interface{}, k string) ([]string, []error) {
    86  	value := v.(string)
    87  	if value == "" {
    88  		return nil, nil
    89  	}
    90  
    91  	_, warnings, errors := readSettings(value)
    92  	return warnings, errors
    93  }
    94  
    95  const settingsPathWarnMsg = `
    96  settings_file is not valid XML, so we are assuming it is a file path. This
    97  support will be removed in the future. Please update your configuration to use
    98  ${file("filename.publishsettings")} instead.`
    99  
   100  func readSettings(pathOrContents string) (s []byte, ws []string, es []error) {
   101  	var settings settingsData
   102  	if err := xml.Unmarshal([]byte(pathOrContents), &settings); err == nil {
   103  		s = []byte(pathOrContents)
   104  		return
   105  	}
   106  
   107  	ws = append(ws, settingsPathWarnMsg)
   108  	path, err := homedir.Expand(pathOrContents)
   109  	if err != nil {
   110  		es = append(es, fmt.Errorf("Error expanding path: %s", err))
   111  		return
   112  	}
   113  
   114  	s, err = ioutil.ReadFile(path)
   115  	if err != nil {
   116  		es = append(es, fmt.Errorf("Could not read file '%s': %s", path, err))
   117  	}
   118  	return
   119  }
   120  
   121  func isFile(v string) (bool, error) {
   122  	if _, err := os.Stat(v); err != nil {
   123  		return false, err
   124  	}
   125  	return true, nil
   126  }
   127  
   128  // settingsData is a private struct used to test the unmarshalling of the
   129  // settingsFile contents, to determine if the contents are valid XML
   130  type settingsData struct {
   131  	XMLName xml.Name `xml:"PublishData"`
   132  }