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