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 }