github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/builtin/providers/azurerm/resource_arm_storage_account.go (about)

     1  package azurerm
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/Azure/azure-sdk-for-go/arm/storage"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  )
    12  
    13  func resourceArmStorageAccount() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceArmStorageAccountCreate,
    16  		Read:   resourceArmStorageAccountRead,
    17  		Update: resourceArmStorageAccountUpdate,
    18  		Delete: resourceArmStorageAccountDelete,
    19  		Importer: &schema.ResourceImporter{
    20  			State: schema.ImportStatePassthrough,
    21  		},
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": {
    25  				Type:         schema.TypeString,
    26  				Required:     true,
    27  				ForceNew:     true,
    28  				ValidateFunc: validateArmStorageAccountName,
    29  			},
    30  
    31  			"resource_group_name": {
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  				ForceNew: true,
    35  			},
    36  
    37  			"location": {
    38  				Type:      schema.TypeString,
    39  				Required:  true,
    40  				ForceNew:  true,
    41  				StateFunc: azureRMNormalizeLocation,
    42  			},
    43  
    44  			"account_type": {
    45  				Type:         schema.TypeString,
    46  				Required:     true,
    47  				ValidateFunc: validateArmStorageAccountType,
    48  			},
    49  
    50  			"primary_location": {
    51  				Type:     schema.TypeString,
    52  				Computed: true,
    53  			},
    54  
    55  			"secondary_location": {
    56  				Type:     schema.TypeString,
    57  				Computed: true,
    58  			},
    59  
    60  			"primary_blob_endpoint": {
    61  				Type:     schema.TypeString,
    62  				Computed: true,
    63  			},
    64  
    65  			"secondary_blob_endpoint": {
    66  				Type:     schema.TypeString,
    67  				Computed: true,
    68  			},
    69  
    70  			"primary_queue_endpoint": {
    71  				Type:     schema.TypeString,
    72  				Computed: true,
    73  			},
    74  
    75  			"secondary_queue_endpoint": {
    76  				Type:     schema.TypeString,
    77  				Computed: true,
    78  			},
    79  
    80  			"primary_table_endpoint": {
    81  				Type:     schema.TypeString,
    82  				Computed: true,
    83  			},
    84  
    85  			"secondary_table_endpoint": {
    86  				Type:     schema.TypeString,
    87  				Computed: true,
    88  			},
    89  
    90  			// NOTE: The API does not appear to expose a secondary file endpoint
    91  			"primary_file_endpoint": {
    92  				Type:     schema.TypeString,
    93  				Computed: true,
    94  			},
    95  
    96  			"primary_access_key": {
    97  				Type:     schema.TypeString,
    98  				Computed: true,
    99  			},
   100  
   101  			"secondary_access_key": {
   102  				Type:     schema.TypeString,
   103  				Computed: true,
   104  			},
   105  
   106  			"tags": tagsSchema(),
   107  		},
   108  	}
   109  }
   110  
   111  func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error {
   112  	client := meta.(*ArmClient).storageServiceClient
   113  
   114  	resourceGroupName := d.Get("resource_group_name").(string)
   115  	storageAccountName := d.Get("name").(string)
   116  	accountType := d.Get("account_type").(string)
   117  	location := d.Get("location").(string)
   118  	tags := d.Get("tags").(map[string]interface{})
   119  
   120  	sku := storage.Sku{
   121  		Name: storage.SkuName(accountType),
   122  	}
   123  
   124  	opts := storage.AccountCreateParameters{
   125  		Location: &location,
   126  		Sku:      &sku,
   127  		Tags:     expandTags(tags),
   128  	}
   129  
   130  	_, err := client.Create(resourceGroupName, storageAccountName, opts, make(chan struct{}))
   131  	if err != nil {
   132  		return fmt.Errorf("Error creating Azure Storage Account '%s': %s", storageAccountName, err)
   133  	}
   134  
   135  	// The only way to get the ID back apparently is to read the resource again
   136  	read, err := client.GetProperties(resourceGroupName, storageAccountName)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	if read.ID == nil {
   141  		return fmt.Errorf("Cannot read Storage Account %s (resource group %s) ID",
   142  			storageAccountName, resourceGroupName)
   143  	}
   144  
   145  	d.SetId(*read.ID)
   146  
   147  	return resourceArmStorageAccountRead(d, meta)
   148  }
   149  
   150  // resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined
   151  // and idempotent operation for CreateOrUpdate. In particular updating all of the parameters
   152  // available requires a call to Update per parameter...
   153  func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error {
   154  	client := meta.(*ArmClient).storageServiceClient
   155  	id, err := parseAzureResourceID(d.Id())
   156  	if err != nil {
   157  		return err
   158  	}
   159  	storageAccountName := id.Path["storageAccounts"]
   160  	resourceGroupName := id.ResourceGroup
   161  
   162  	d.Partial(true)
   163  
   164  	if d.HasChange("account_type") {
   165  		accountType := d.Get("account_type").(string)
   166  
   167  		sku := storage.Sku{
   168  			Name: storage.SkuName(accountType),
   169  		}
   170  
   171  		opts := storage.AccountUpdateParameters{
   172  			Sku: &sku,
   173  		}
   174  		_, err := client.Update(resourceGroupName, storageAccountName, opts)
   175  		if err != nil {
   176  			return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err)
   177  		}
   178  
   179  		d.SetPartial("account_type")
   180  	}
   181  
   182  	if d.HasChange("tags") {
   183  		tags := d.Get("tags").(map[string]interface{})
   184  
   185  		opts := storage.AccountUpdateParameters{
   186  			Tags: expandTags(tags),
   187  		}
   188  		_, err := client.Update(resourceGroupName, storageAccountName, opts)
   189  		if err != nil {
   190  			return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err)
   191  		}
   192  
   193  		d.SetPartial("tags")
   194  	}
   195  
   196  	d.Partial(false)
   197  	return nil
   198  }
   199  
   200  func resourceArmStorageAccountRead(d *schema.ResourceData, meta interface{}) error {
   201  	client := meta.(*ArmClient).storageServiceClient
   202  
   203  	id, err := parseAzureResourceID(d.Id())
   204  	if err != nil {
   205  		return err
   206  	}
   207  	name := id.Path["storageAccounts"]
   208  	resGroup := id.ResourceGroup
   209  
   210  	resp, err := client.GetProperties(resGroup, name)
   211  	if err != nil {
   212  		if resp.StatusCode == http.StatusNotFound {
   213  			d.SetId("")
   214  			return nil
   215  		}
   216  
   217  		return fmt.Errorf("Error reading the state of AzureRM Storage Account %q: %s", name, err)
   218  	}
   219  
   220  	keys, err := client.ListKeys(resGroup, name)
   221  	if err != nil {
   222  		return err
   223  	}
   224  
   225  	accessKeys := *keys.Keys
   226  	d.Set("primary_access_key", accessKeys[0].KeyName)
   227  	d.Set("secondary_access_key", accessKeys[1].KeyName)
   228  	d.Set("location", resp.Location)
   229  	d.Set("account_type", resp.Sku.Name)
   230  	d.Set("primary_location", resp.Properties.PrimaryLocation)
   231  	d.Set("secondary_location", resp.Properties.SecondaryLocation)
   232  
   233  	if resp.Properties.PrimaryEndpoints != nil {
   234  		d.Set("primary_blob_endpoint", resp.Properties.PrimaryEndpoints.Blob)
   235  		d.Set("primary_queue_endpoint", resp.Properties.PrimaryEndpoints.Queue)
   236  		d.Set("primary_table_endpoint", resp.Properties.PrimaryEndpoints.Table)
   237  		d.Set("primary_file_endpoint", resp.Properties.PrimaryEndpoints.File)
   238  	}
   239  
   240  	if resp.Properties.SecondaryEndpoints != nil {
   241  		if resp.Properties.SecondaryEndpoints.Blob != nil {
   242  			d.Set("secondary_blob_endpoint", resp.Properties.SecondaryEndpoints.Blob)
   243  		} else {
   244  			d.Set("secondary_blob_endpoint", "")
   245  		}
   246  		if resp.Properties.SecondaryEndpoints.Queue != nil {
   247  			d.Set("secondary_queue_endpoint", resp.Properties.SecondaryEndpoints.Queue)
   248  		} else {
   249  			d.Set("secondary_queue_endpoint", "")
   250  		}
   251  		if resp.Properties.SecondaryEndpoints.Table != nil {
   252  			d.Set("secondary_table_endpoint", resp.Properties.SecondaryEndpoints.Table)
   253  		} else {
   254  			d.Set("secondary_table_endpoint", "")
   255  		}
   256  	}
   257  
   258  	d.Set("name", resp.Name)
   259  
   260  	flattenAndSetTags(d, resp.Tags)
   261  
   262  	return nil
   263  }
   264  
   265  func resourceArmStorageAccountDelete(d *schema.ResourceData, meta interface{}) error {
   266  	client := meta.(*ArmClient).storageServiceClient
   267  
   268  	id, err := parseAzureResourceID(d.Id())
   269  	if err != nil {
   270  		return err
   271  	}
   272  	name := id.Path["storageAccounts"]
   273  	resGroup := id.ResourceGroup
   274  
   275  	_, err = client.Delete(resGroup, name)
   276  	if err != nil {
   277  		return fmt.Errorf("Error issuing AzureRM delete request for storage account %q: %s", name, err)
   278  	}
   279  
   280  	return nil
   281  }
   282  
   283  func validateArmStorageAccountName(v interface{}, k string) (ws []string, es []error) {
   284  	input := v.(string)
   285  
   286  	if !regexp.MustCompile(`\A([a-z0-9]{3,24})\z`).MatchString(input) {
   287  		es = append(es, fmt.Errorf("name can only consist of lowercase letters and numbers, and must be between 3 and 24 characters long"))
   288  	}
   289  
   290  	return
   291  }
   292  
   293  func validateArmStorageAccountType(v interface{}, k string) (ws []string, es []error) {
   294  	validAccountTypes := []string{"standard_lrs", "standard_zrs",
   295  		"standard_grs", "standard_ragrs", "premium_lrs"}
   296  
   297  	input := strings.ToLower(v.(string))
   298  
   299  	for _, valid := range validAccountTypes {
   300  		if valid == input {
   301  			return
   302  		}
   303  	}
   304  
   305  	es = append(es, fmt.Errorf("Invalid storage account type %q", input))
   306  	return
   307  }