github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_glacier_vault.go (about) 1 package aws 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "regexp" 8 9 "github.com/hashicorp/errwrap" 10 "github.com/hashicorp/terraform/helper/schema" 11 12 "github.com/aws/aws-sdk-go/aws" 13 "github.com/aws/aws-sdk-go/aws/awserr" 14 "github.com/aws/aws-sdk-go/service/glacier" 15 ) 16 17 func resourceAwsGlacierVault() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceAwsGlacierVaultCreate, 20 Read: resourceAwsGlacierVaultRead, 21 Update: resourceAwsGlacierVaultUpdate, 22 Delete: resourceAwsGlacierVaultDelete, 23 24 Importer: &schema.ResourceImporter{ 25 State: schema.ImportStatePassthrough, 26 }, 27 28 Schema: map[string]*schema.Schema{ 29 "name": &schema.Schema{ 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 34 value := v.(string) 35 if !regexp.MustCompile(`^[.0-9A-Za-z-_]+$`).MatchString(value) { 36 errors = append(errors, fmt.Errorf( 37 "only alphanumeric characters, hyphens, underscores, and periods are allowed in %q", k)) 38 } 39 if len(value) > 255 { 40 errors = append(errors, fmt.Errorf( 41 "%q cannot be longer than 255 characters", k)) 42 } 43 return 44 }, 45 }, 46 47 "location": &schema.Schema{ 48 Type: schema.TypeString, 49 Computed: true, 50 }, 51 52 "arn": &schema.Schema{ 53 Type: schema.TypeString, 54 Computed: true, 55 }, 56 57 "access_policy": &schema.Schema{ 58 Type: schema.TypeString, 59 Optional: true, 60 ValidateFunc: validateJsonString, 61 StateFunc: func(v interface{}) string { 62 json, _ := normalizeJsonString(v) 63 return json 64 }, 65 }, 66 67 "notification": &schema.Schema{ 68 Type: schema.TypeList, 69 Optional: true, 70 Elem: &schema.Resource{ 71 Schema: map[string]*schema.Schema{ 72 "events": &schema.Schema{ 73 Type: schema.TypeSet, 74 Required: true, 75 Elem: &schema.Schema{Type: schema.TypeString}, 76 Set: schema.HashString, 77 }, 78 "sns_topic": &schema.Schema{ 79 Type: schema.TypeString, 80 Required: true, 81 }, 82 }, 83 }, 84 }, 85 86 "tags": tagsSchema(), 87 }, 88 } 89 } 90 91 func resourceAwsGlacierVaultCreate(d *schema.ResourceData, meta interface{}) error { 92 glacierconn := meta.(*AWSClient).glacierconn 93 94 input := &glacier.CreateVaultInput{ 95 VaultName: aws.String(d.Get("name").(string)), 96 } 97 98 out, err := glacierconn.CreateVault(input) 99 if err != nil { 100 return fmt.Errorf("Error creating Glacier Vault: %s", err) 101 } 102 103 d.SetId(d.Get("name").(string)) 104 d.Set("location", *out.Location) 105 106 return resourceAwsGlacierVaultUpdate(d, meta) 107 } 108 109 func resourceAwsGlacierVaultUpdate(d *schema.ResourceData, meta interface{}) error { 110 glacierconn := meta.(*AWSClient).glacierconn 111 112 if err := setGlacierVaultTags(glacierconn, d); err != nil { 113 return err 114 } 115 116 if d.HasChange("access_policy") { 117 if err := resourceAwsGlacierVaultPolicyUpdate(glacierconn, d); err != nil { 118 return err 119 } 120 } 121 122 if d.HasChange("notification") { 123 if err := resourceAwsGlacierVaultNotificationUpdate(glacierconn, d); err != nil { 124 return err 125 } 126 } 127 128 return resourceAwsGlacierVaultRead(d, meta) 129 } 130 131 func resourceAwsGlacierVaultRead(d *schema.ResourceData, meta interface{}) error { 132 glacierconn := meta.(*AWSClient).glacierconn 133 134 input := &glacier.DescribeVaultInput{ 135 VaultName: aws.String(d.Id()), 136 } 137 138 out, err := glacierconn.DescribeVault(input) 139 if err != nil { 140 return fmt.Errorf("Error reading Glacier Vault: %s", err.Error()) 141 } 142 143 awsClient := meta.(*AWSClient) 144 d.Set("name", out.VaultName) 145 d.Set("arn", out.VaultARN) 146 147 location, err := buildGlacierVaultLocation(awsClient.accountid, d.Id()) 148 if err != nil { 149 return err 150 } 151 d.Set("location", location) 152 153 tags, err := getGlacierVaultTags(glacierconn, d.Id()) 154 if err != nil { 155 return err 156 } 157 d.Set("tags", tags) 158 159 log.Printf("[DEBUG] Getting the access_policy for Vault %s", d.Id()) 160 pol, err := glacierconn.GetVaultAccessPolicy(&glacier.GetVaultAccessPolicyInput{ 161 VaultName: aws.String(d.Id()), 162 }) 163 164 if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "ResourceNotFoundException" { 165 d.Set("access_policy", "") 166 } else if pol != nil { 167 policy, err := normalizeJsonString(*pol.Policy.Policy) 168 if err != nil { 169 return errwrap.Wrapf("access policy contains an invalid JSON: {{err}}", err) 170 } 171 d.Set("access_policy", policy) 172 } else { 173 return err 174 } 175 176 notifications, err := getGlacierVaultNotification(glacierconn, d.Id()) 177 if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "ResourceNotFoundException" { 178 d.Set("notification", "") 179 } else if pol != nil { 180 d.Set("notification", notifications) 181 } else { 182 return err 183 } 184 185 return nil 186 } 187 188 func resourceAwsGlacierVaultDelete(d *schema.ResourceData, meta interface{}) error { 189 glacierconn := meta.(*AWSClient).glacierconn 190 191 log.Printf("[DEBUG] Glacier Delete Vault: %s", d.Id()) 192 _, err := glacierconn.DeleteVault(&glacier.DeleteVaultInput{ 193 VaultName: aws.String(d.Id()), 194 }) 195 if err != nil { 196 return fmt.Errorf("Error deleting Glacier Vault: %s", err.Error()) 197 } 198 return nil 199 } 200 201 func resourceAwsGlacierVaultNotificationUpdate(glacierconn *glacier.Glacier, d *schema.ResourceData) error { 202 203 if v, ok := d.GetOk("notification"); ok { 204 settings := v.([]interface{}) 205 206 if len(settings) > 1 { 207 return fmt.Errorf("Only a single Notification Block is allowed for Glacier Vault") 208 } else if len(settings) == 1 { 209 s := settings[0].(map[string]interface{}) 210 var events []*string 211 for _, id := range s["events"].(*schema.Set).List() { 212 events = append(events, aws.String(id.(string))) 213 } 214 215 _, err := glacierconn.SetVaultNotifications(&glacier.SetVaultNotificationsInput{ 216 VaultName: aws.String(d.Id()), 217 VaultNotificationConfig: &glacier.VaultNotificationConfig{ 218 SNSTopic: aws.String(s["sns_topic"].(string)), 219 Events: events, 220 }, 221 }) 222 223 if err != nil { 224 return fmt.Errorf("Error Updating Glacier Vault Notifications: %s", err.Error()) 225 } 226 } 227 } else { 228 _, err := glacierconn.DeleteVaultNotifications(&glacier.DeleteVaultNotificationsInput{ 229 VaultName: aws.String(d.Id()), 230 }) 231 232 if err != nil { 233 return fmt.Errorf("Error Removing Glacier Vault Notifications: %s", err.Error()) 234 } 235 236 } 237 238 return nil 239 } 240 241 func resourceAwsGlacierVaultPolicyUpdate(glacierconn *glacier.Glacier, d *schema.ResourceData) error { 242 vaultName := d.Id() 243 policyContents := d.Get("access_policy").(string) 244 245 policy := &glacier.VaultAccessPolicy{ 246 Policy: aws.String(policyContents), 247 } 248 249 if policyContents != "" { 250 log.Printf("[DEBUG] Glacier Vault: %s, put policy", vaultName) 251 252 _, err := glacierconn.SetVaultAccessPolicy(&glacier.SetVaultAccessPolicyInput{ 253 VaultName: aws.String(d.Id()), 254 Policy: policy, 255 }) 256 257 if err != nil { 258 return fmt.Errorf("Error putting Glacier Vault policy: %s", err.Error()) 259 } 260 } else { 261 log.Printf("[DEBUG] Glacier Vault: %s, delete policy: %s", vaultName, policy) 262 _, err := glacierconn.DeleteVaultAccessPolicy(&glacier.DeleteVaultAccessPolicyInput{ 263 VaultName: aws.String(d.Id()), 264 }) 265 266 if err != nil { 267 return fmt.Errorf("Error deleting Glacier Vault policy: %s", err.Error()) 268 } 269 } 270 271 return nil 272 } 273 274 func setGlacierVaultTags(conn *glacier.Glacier, d *schema.ResourceData) error { 275 if d.HasChange("tags") { 276 oraw, nraw := d.GetChange("tags") 277 o := oraw.(map[string]interface{}) 278 n := nraw.(map[string]interface{}) 279 create, remove := diffGlacierVaultTags(mapGlacierVaultTags(o), mapGlacierVaultTags(n)) 280 281 // Set tags 282 if len(remove) > 0 { 283 tagsToRemove := &glacier.RemoveTagsFromVaultInput{ 284 VaultName: aws.String(d.Id()), 285 TagKeys: glacierStringsToPointyString(remove), 286 } 287 288 log.Printf("[DEBUG] Removing tags: from %s", d.Id()) 289 _, err := conn.RemoveTagsFromVault(tagsToRemove) 290 if err != nil { 291 return err 292 } 293 } 294 if len(create) > 0 { 295 tagsToAdd := &glacier.AddTagsToVaultInput{ 296 VaultName: aws.String(d.Id()), 297 Tags: glacierVaultTagsFromMap(create), 298 } 299 300 log.Printf("[DEBUG] Creating tags: for %s", d.Id()) 301 _, err := conn.AddTagsToVault(tagsToAdd) 302 if err != nil { 303 return err 304 } 305 } 306 } 307 308 return nil 309 } 310 311 func mapGlacierVaultTags(m map[string]interface{}) map[string]string { 312 results := make(map[string]string) 313 for k, v := range m { 314 results[k] = v.(string) 315 } 316 317 return results 318 } 319 320 func diffGlacierVaultTags(oldTags, newTags map[string]string) (map[string]string, []string) { 321 322 create := make(map[string]string) 323 for k, v := range newTags { 324 create[k] = v 325 } 326 327 // Build the list of what to remove 328 var remove []string 329 for k, v := range oldTags { 330 old, ok := create[k] 331 if !ok || old != v { 332 // Delete it! 333 remove = append(remove, k) 334 } 335 } 336 337 return create, remove 338 } 339 340 func getGlacierVaultTags(glacierconn *glacier.Glacier, vaultName string) (map[string]string, error) { 341 request := &glacier.ListTagsForVaultInput{ 342 VaultName: aws.String(vaultName), 343 } 344 345 log.Printf("[DEBUG] Getting the tags: for %s", vaultName) 346 response, err := glacierconn.ListTagsForVault(request) 347 if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "NoSuchTagSet" { 348 return map[string]string{}, nil 349 } else if err != nil { 350 return nil, err 351 } 352 353 return glacierVaultTagsToMap(response.Tags), nil 354 } 355 356 func glacierVaultTagsToMap(responseTags map[string]*string) map[string]string { 357 results := make(map[string]string, len(responseTags)) 358 for k, v := range responseTags { 359 results[k] = *v 360 } 361 362 return results 363 } 364 365 func glacierVaultTagsFromMap(responseTags map[string]string) map[string]*string { 366 results := make(map[string]*string, len(responseTags)) 367 for k, v := range responseTags { 368 results[k] = aws.String(v) 369 } 370 371 return results 372 } 373 374 func glacierStringsToPointyString(s []string) []*string { 375 results := make([]*string, len(s)) 376 for i, x := range s { 377 results[i] = aws.String(x) 378 } 379 380 return results 381 } 382 383 func glacierPointersToStringList(pointers []*string) []interface{} { 384 list := make([]interface{}, len(pointers)) 385 for i, v := range pointers { 386 list[i] = *v 387 } 388 return list 389 } 390 391 func buildGlacierVaultLocation(accountId, vaultName string) (string, error) { 392 if accountId == "" { 393 return "", errors.New("AWS account ID unavailable - failed to construct Vault location") 394 } 395 return fmt.Sprintf("/" + accountId + "/vaults/" + vaultName), nil 396 } 397 398 func getGlacierVaultNotification(glacierconn *glacier.Glacier, vaultName string) ([]map[string]interface{}, error) { 399 request := &glacier.GetVaultNotificationsInput{ 400 VaultName: aws.String(vaultName), 401 } 402 403 response, err := glacierconn.GetVaultNotifications(request) 404 if err != nil { 405 return nil, fmt.Errorf("Error reading Glacier Vault Notifications: %s", err.Error()) 406 } 407 408 notifications := make(map[string]interface{}, 0) 409 410 log.Print("[DEBUG] Flattening Glacier Vault Notifications") 411 412 notifications["events"] = schema.NewSet(schema.HashString, glacierPointersToStringList(response.VaultNotificationConfig.Events)) 413 notifications["sns_topic"] = *response.VaultNotificationConfig.SNSTopic 414 415 return []map[string]interface{}{notifications}, nil 416 }