github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/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 "tags": tagsSchema(), 94 }, 95 } 96 } 97 98 func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { 99 client := meta.(*ArmClient).storageServiceClient 100 101 resourceGroupName := d.Get("resource_group_name").(string) 102 storageAccountName := d.Get("name").(string) 103 accountType := d.Get("account_type").(string) 104 location := d.Get("location").(string) 105 tags := d.Get("tags").(map[string]interface{}) 106 107 opts := storage.AccountCreateParameters{ 108 Location: &location, 109 Properties: &storage.AccountPropertiesCreateParameters{ 110 AccountType: storage.AccountType(accountType), 111 }, 112 Tags: expandTags(tags), 113 } 114 115 accResp, err := client.Create(resourceGroupName, storageAccountName, opts) 116 if err != nil { 117 return fmt.Errorf("Error creating Azure Storage Account '%s': %s", storageAccountName, err) 118 } 119 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response.Response, http.StatusOK) 120 if err != nil { 121 return fmt.Errorf("Error creating Azure Storage Account %q: %s", storageAccountName, err) 122 } 123 124 // The only way to get the ID back apparently is to read the resource again 125 account, err := client.GetProperties(resourceGroupName, storageAccountName) 126 if err != nil { 127 return fmt.Errorf("Error retrieving Azure Storage Account %q: %s", storageAccountName, err) 128 } 129 130 d.SetId(*account.ID) 131 132 return resourceArmStorageAccountRead(d, meta) 133 } 134 135 // resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined 136 // and idempotent operation for CreateOrUpdate. In particular updating all of the parameters 137 // available requires a call to Update per parameter... 138 func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error { 139 client := meta.(*ArmClient).storageServiceClient 140 id, err := parseAzureResourceID(d.Id()) 141 if err != nil { 142 return err 143 } 144 storageAccountName := id.Path["storageAccounts"] 145 resourceGroupName := id.ResourceGroup 146 147 d.Partial(true) 148 149 if d.HasChange("account_type") { 150 accountType := d.Get("account_type").(string) 151 152 opts := storage.AccountUpdateParameters{ 153 Properties: &storage.AccountPropertiesUpdateParameters{ 154 AccountType: storage.AccountType(accountType), 155 }, 156 } 157 accResp, err := client.Update(resourceGroupName, storageAccountName, opts) 158 if err != nil { 159 return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err) 160 } 161 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response.Response, http.StatusOK) 162 if err != nil { 163 return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err) 164 } 165 166 d.SetPartial("account_type") 167 } 168 169 if d.HasChange("tags") { 170 tags := d.Get("tags").(map[string]interface{}) 171 172 opts := storage.AccountUpdateParameters{ 173 Tags: expandTags(tags), 174 } 175 accResp, err := client.Update(resourceGroupName, storageAccountName, opts) 176 if err != nil { 177 return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err) 178 } 179 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response.Response, http.StatusOK) 180 if err != nil { 181 return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err) 182 } 183 184 d.SetPartial("tags") 185 } 186 187 d.Partial(false) 188 return nil 189 } 190 191 func resourceArmStorageAccountRead(d *schema.ResourceData, meta interface{}) error { 192 client := meta.(*ArmClient).storageServiceClient 193 194 id, err := parseAzureResourceID(d.Id()) 195 if err != nil { 196 return err 197 } 198 name := id.Path["storageAccounts"] 199 resGroup := id.ResourceGroup 200 201 resp, err := client.GetProperties(resGroup, name) 202 if err != nil { 203 if resp.StatusCode == http.StatusNotFound { 204 d.SetId("") 205 return nil 206 } 207 208 return fmt.Errorf("Error reading the state of AzureRM Storage Account %q: %s", name, err) 209 } 210 211 d.Set("location", resp.Location) 212 d.Set("account_type", resp.Properties.AccountType) 213 d.Set("primary_location", resp.Properties.PrimaryLocation) 214 d.Set("secondary_location", resp.Properties.SecondaryLocation) 215 216 if resp.Properties.PrimaryEndpoints != nil { 217 d.Set("primary_blob_endpoint", resp.Properties.PrimaryEndpoints.Blob) 218 d.Set("primary_queue_endpoint", resp.Properties.PrimaryEndpoints.Queue) 219 d.Set("primary_table_endpoint", resp.Properties.PrimaryEndpoints.Table) 220 d.Set("primary_file_endpoint", resp.Properties.PrimaryEndpoints.File) 221 } 222 223 if resp.Properties.SecondaryEndpoints != nil { 224 if resp.Properties.SecondaryEndpoints.Blob != nil { 225 d.Set("secondary_blob_endpoint", resp.Properties.SecondaryEndpoints.Blob) 226 } else { 227 d.Set("secondary_blob_endpoint", "") 228 } 229 if resp.Properties.SecondaryEndpoints.Queue != nil { 230 d.Set("secondary_queue_endpoint", resp.Properties.SecondaryEndpoints.Queue) 231 } else { 232 d.Set("secondary_queue_endpoint", "") 233 } 234 if resp.Properties.SecondaryEndpoints.Table != nil { 235 d.Set("secondary_table_endpoint", resp.Properties.SecondaryEndpoints.Table) 236 } else { 237 d.Set("secondary_table_endpoint", "") 238 } 239 } 240 241 flattenAndSetTags(d, resp.Tags) 242 243 return nil 244 } 245 246 func resourceArmStorageAccountDelete(d *schema.ResourceData, meta interface{}) error { 247 client := meta.(*ArmClient).storageServiceClient 248 249 id, err := parseAzureResourceID(d.Id()) 250 if err != nil { 251 return err 252 } 253 name := id.Path["storageAccounts"] 254 resGroup := id.ResourceGroup 255 256 accResp, err := client.Delete(resGroup, name) 257 if err != nil { 258 return fmt.Errorf("Error issuing AzureRM delete request for storage account %q: %s", name, err) 259 } 260 _, err = pollIndefinitelyAsNeeded(client.Client, accResp.Response, http.StatusNotFound) 261 if err != nil { 262 return fmt.Errorf("Error polling for AzureRM delete request for storage account %q: %s", name, err) 263 } 264 265 return nil 266 } 267 268 func validateArmStorageAccountName(v interface{}, k string) (ws []string, es []error) { 269 input := v.(string) 270 271 if !regexp.MustCompile(`\A([a-z0-9]{3,24})\z`).MatchString(input) { 272 es = append(es, fmt.Errorf("name can only consist of lowercase letters and numbers, and must be between 3 and 24 characters long")) 273 } 274 275 return 276 } 277 278 func validateArmStorageAccountType(v interface{}, k string) (ws []string, es []error) { 279 validAccountTypes := []string{"standard_lrs", "standard_zrs", 280 "standard_grs", "standard_ragrs", "premium_lrs"} 281 282 input := strings.ToLower(v.(string)) 283 284 for _, valid := range validAccountTypes { 285 if valid == input { 286 return 287 } 288 } 289 290 es = append(es, fmt.Errorf("Invalid storage account type %q", input)) 291 return 292 }