github.com/sarguru/terraform@v0.6.17-0.20160525232901-8fcdfd7e3dc9/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": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 ForceNew: true, 25 ValidateFunc: validateArmStorageAccountName, 26 }, 27 28 "resource_group_name": &schema.Schema{ 29 Type: schema.TypeString, 30 Required: true, 31 ForceNew: true, 32 }, 33 34 "location": &schema.Schema{ 35 Type: schema.TypeString, 36 Required: true, 37 ForceNew: true, 38 StateFunc: azureRMNormalizeLocation, 39 }, 40 41 "account_type": &schema.Schema{ 42 Type: schema.TypeString, 43 Required: true, 44 ValidateFunc: validateArmStorageAccountType, 45 }, 46 47 "primary_location": &schema.Schema{ 48 Type: schema.TypeString, 49 Computed: true, 50 }, 51 52 "secondary_location": &schema.Schema{ 53 Type: schema.TypeString, 54 Computed: true, 55 }, 56 57 "primary_blob_endpoint": &schema.Schema{ 58 Type: schema.TypeString, 59 Computed: true, 60 }, 61 62 "secondary_blob_endpoint": &schema.Schema{ 63 Type: schema.TypeString, 64 Computed: true, 65 }, 66 67 "primary_queue_endpoint": &schema.Schema{ 68 Type: schema.TypeString, 69 Computed: true, 70 }, 71 72 "secondary_queue_endpoint": &schema.Schema{ 73 Type: schema.TypeString, 74 Computed: true, 75 }, 76 77 "primary_table_endpoint": &schema.Schema{ 78 Type: schema.TypeString, 79 Computed: true, 80 }, 81 82 "secondary_table_endpoint": &schema.Schema{ 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": &schema.Schema{ 89 Type: schema.TypeString, 90 Computed: true, 91 }, 92 93 "primary_access_key": &schema.Schema{ 94 Type: schema.TypeString, 95 Computed: true, 96 }, 97 98 "secondary_access_key": &schema.Schema{ 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 opts := storage.AccountCreateParameters{ 118 Location: &location, 119 Properties: &storage.AccountPropertiesCreateParameters{ 120 AccountType: storage.AccountType(accountType), 121 }, 122 Tags: expandTags(tags), 123 } 124 125 accResp, err := client.Create(resourceGroupName, storageAccountName, opts) 126 if err != nil { 127 return fmt.Errorf("Error creating Azure Storage Account '%s': %s", storageAccountName, err) 128 } 129 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response.Response, http.StatusOK) 130 if err != nil { 131 return fmt.Errorf("Error creating Azure Storage Account %q: %s", storageAccountName, err) 132 } 133 134 // The only way to get the ID back apparently is to read the resource again 135 account, err := client.GetProperties(resourceGroupName, storageAccountName) 136 if err != nil { 137 return fmt.Errorf("Error retrieving Azure Storage Account %q: %s", storageAccountName, err) 138 } 139 140 d.SetId(*account.ID) 141 142 return resourceArmStorageAccountRead(d, meta) 143 } 144 145 // resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined 146 // and idempotent operation for CreateOrUpdate. In particular updating all of the parameters 147 // available requires a call to Update per parameter... 148 func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error { 149 client := meta.(*ArmClient).storageServiceClient 150 id, err := parseAzureResourceID(d.Id()) 151 if err != nil { 152 return err 153 } 154 storageAccountName := id.Path["storageAccounts"] 155 resourceGroupName := id.ResourceGroup 156 157 d.Partial(true) 158 159 if d.HasChange("account_type") { 160 accountType := d.Get("account_type").(string) 161 162 opts := storage.AccountUpdateParameters{ 163 Properties: &storage.AccountPropertiesUpdateParameters{ 164 AccountType: storage.AccountType(accountType), 165 }, 166 } 167 accResp, err := client.Update(resourceGroupName, storageAccountName, opts) 168 if err != nil { 169 return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err) 170 } 171 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response.Response, http.StatusOK) 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 accResp, 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 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response.Response, http.StatusOK) 190 if err != nil { 191 return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err) 192 } 193 194 d.SetPartial("tags") 195 } 196 197 d.Partial(false) 198 return nil 199 } 200 201 func resourceArmStorageAccountRead(d *schema.ResourceData, meta interface{}) error { 202 client := meta.(*ArmClient).storageServiceClient 203 204 id, err := parseAzureResourceID(d.Id()) 205 if err != nil { 206 return err 207 } 208 name := id.Path["storageAccounts"] 209 resGroup := id.ResourceGroup 210 211 resp, err := client.GetProperties(resGroup, name) 212 if err != nil { 213 if resp.StatusCode == http.StatusNotFound { 214 d.SetId("") 215 return nil 216 } 217 218 return fmt.Errorf("Error reading the state of AzureRM Storage Account %q: %s", name, err) 219 } 220 221 keys, err := client.ListKeys(resGroup, name) 222 if err != nil { 223 return err 224 } 225 226 d.Set("primary_access_key", keys.Key1) 227 d.Set("secondary_access_key", keys.Key2) 228 d.Set("location", resp.Location) 229 d.Set("account_type", resp.Properties.AccountType) 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 flattenAndSetTags(d, resp.Tags) 259 260 return nil 261 } 262 263 func resourceArmStorageAccountDelete(d *schema.ResourceData, meta interface{}) error { 264 client := meta.(*ArmClient).storageServiceClient 265 266 id, err := parseAzureResourceID(d.Id()) 267 if err != nil { 268 return err 269 } 270 name := id.Path["storageAccounts"] 271 resGroup := id.ResourceGroup 272 273 accResp, err := client.Delete(resGroup, name) 274 if err != nil { 275 return fmt.Errorf("Error issuing AzureRM delete request for storage account %q: %s", name, err) 276 } 277 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response, http.StatusNotFound) 278 if err != nil { 279 return fmt.Errorf("Error polling for AzureRM delete request for storage account %q: %s", name, err) 280 } 281 282 return nil 283 } 284 285 func validateArmStorageAccountName(v interface{}, k string) (ws []string, es []error) { 286 input := v.(string) 287 288 if !regexp.MustCompile(`\A([a-z0-9]{3,24})\z`).MatchString(input) { 289 es = append(es, fmt.Errorf("name can only consist of lowercase letters and numbers, and must be between 3 and 24 characters long")) 290 } 291 292 return 293 } 294 295 func validateArmStorageAccountType(v interface{}, k string) (ws []string, es []error) { 296 validAccountTypes := []string{"standard_lrs", "standard_zrs", 297 "standard_grs", "standard_ragrs", "premium_lrs"} 298 299 input := strings.ToLower(v.(string)) 300 301 for _, valid := range validAccountTypes { 302 if valid == input { 303 return 304 } 305 } 306 307 es = append(es, fmt.Errorf("Invalid storage account type %q", input)) 308 return 309 }