github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/builtin/providers/aws/resource_aws_dynamodb_table.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/schema" 10 11 "github.com/aws/aws-sdk-go/aws" 12 "github.com/aws/aws-sdk-go/service/dynamodb" 13 "github.com/hashicorp/terraform/helper/hashcode" 14 ) 15 16 // A number of these are marked as computed because if you don't 17 // provide a value, DynamoDB will provide you with defaults (which are the 18 // default values specified below) 19 func resourceAwsDynamoDbTable() *schema.Resource { 20 return &schema.Resource{ 21 Create: resourceAwsDynamoDbTableCreate, 22 Read: resourceAwsDynamoDbTableRead, 23 Update: resourceAwsDynamoDbTableUpdate, 24 Delete: resourceAwsDynamoDbTableDelete, 25 26 Schema: map[string]*schema.Schema{ 27 "name": &schema.Schema{ 28 Type: schema.TypeString, 29 Required: true, 30 ForceNew: true, 31 }, 32 "hash_key": &schema.Schema{ 33 Type: schema.TypeString, 34 Required: true, 35 }, 36 "range_key": &schema.Schema{ 37 Type: schema.TypeString, 38 Optional: true, 39 }, 40 "write_capacity": &schema.Schema{ 41 Type: schema.TypeInt, 42 Required: true, 43 }, 44 "read_capacity": &schema.Schema{ 45 Type: schema.TypeInt, 46 Required: true, 47 }, 48 "attribute": &schema.Schema{ 49 Type: schema.TypeSet, 50 Required: true, 51 Elem: &schema.Resource{ 52 Schema: map[string]*schema.Schema{ 53 "name": &schema.Schema{ 54 Type: schema.TypeString, 55 Required: true, 56 }, 57 "type": &schema.Schema{ 58 Type: schema.TypeString, 59 Required: true, 60 }, 61 }, 62 }, 63 Set: func(v interface{}) int { 64 var buf bytes.Buffer 65 m := v.(map[string]interface{}) 66 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 67 return hashcode.String(buf.String()) 68 }, 69 }, 70 "local_secondary_index": &schema.Schema{ 71 Type: schema.TypeSet, 72 Optional: true, 73 Elem: &schema.Resource{ 74 Schema: map[string]*schema.Schema{ 75 "name": &schema.Schema{ 76 Type: schema.TypeString, 77 Required: true, 78 }, 79 "range_key": &schema.Schema{ 80 Type: schema.TypeString, 81 Required: true, 82 }, 83 "projection_type": &schema.Schema{ 84 Type: schema.TypeString, 85 Required: true, 86 }, 87 "non_key_attributes": &schema.Schema{ 88 Type: schema.TypeList, 89 Optional: true, 90 Elem: &schema.Schema{Type: schema.TypeString}, 91 }, 92 }, 93 }, 94 Set: func(v interface{}) int { 95 var buf bytes.Buffer 96 m := v.(map[string]interface{}) 97 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 98 return hashcode.String(buf.String()) 99 }, 100 }, 101 "global_secondary_index": &schema.Schema{ 102 Type: schema.TypeSet, 103 Optional: true, 104 Elem: &schema.Resource{ 105 Schema: map[string]*schema.Schema{ 106 "name": &schema.Schema{ 107 Type: schema.TypeString, 108 Required: true, 109 }, 110 "write_capacity": &schema.Schema{ 111 Type: schema.TypeInt, 112 Required: true, 113 }, 114 "read_capacity": &schema.Schema{ 115 Type: schema.TypeInt, 116 Required: true, 117 }, 118 "hash_key": &schema.Schema{ 119 Type: schema.TypeString, 120 Required: true, 121 }, 122 "range_key": &schema.Schema{ 123 Type: schema.TypeString, 124 Optional: true, 125 }, 126 "projection_type": &schema.Schema{ 127 Type: schema.TypeString, 128 Required: true, 129 }, 130 "non_key_attributes": &schema.Schema{ 131 Type: schema.TypeList, 132 Optional: true, 133 Elem: &schema.Schema{Type: schema.TypeString}, 134 }, 135 }, 136 }, 137 // GSI names are the uniqueness constraint 138 Set: func(v interface{}) int { 139 var buf bytes.Buffer 140 m := v.(map[string]interface{}) 141 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 142 buf.WriteString(fmt.Sprintf("%d-", m["write_capacity"].(int))) 143 buf.WriteString(fmt.Sprintf("%d-", m["read_capacity"].(int))) 144 return hashcode.String(buf.String()) 145 }, 146 }, 147 }, 148 } 149 } 150 151 func resourceAwsDynamoDbTableCreate(d *schema.ResourceData, meta interface{}) error { 152 dynamodbconn := meta.(*AWSClient).dynamodbconn 153 154 name := d.Get("name").(string) 155 156 log.Printf("[DEBUG] DynamoDB table create: %s", name) 157 158 throughput := &dynamodb.ProvisionedThroughput{ 159 ReadCapacityUnits: aws.Long(int64(d.Get("read_capacity").(int))), 160 WriteCapacityUnits: aws.Long(int64(d.Get("write_capacity").(int))), 161 } 162 163 hash_key_name := d.Get("hash_key").(string) 164 keyschema := []*dynamodb.KeySchemaElement{ 165 &dynamodb.KeySchemaElement{ 166 AttributeName: aws.String(hash_key_name), 167 KeyType: aws.String("HASH"), 168 }, 169 } 170 171 if range_key, ok := d.GetOk("range_key"); ok { 172 range_schema_element := &dynamodb.KeySchemaElement{ 173 AttributeName: aws.String(range_key.(string)), 174 KeyType: aws.String("RANGE"), 175 } 176 keyschema = append(keyschema, range_schema_element) 177 } 178 179 req := &dynamodb.CreateTableInput{ 180 TableName: aws.String(name), 181 ProvisionedThroughput: throughput, 182 KeySchema: keyschema, 183 } 184 185 if attributedata, ok := d.GetOk("attribute"); ok { 186 attributes := []*dynamodb.AttributeDefinition{} 187 attributeSet := attributedata.(*schema.Set) 188 for _, attribute := range attributeSet.List() { 189 attr := attribute.(map[string]interface{}) 190 attributes = append(attributes, &dynamodb.AttributeDefinition{ 191 AttributeName: aws.String(attr["name"].(string)), 192 AttributeType: aws.String(attr["type"].(string)), 193 }) 194 } 195 196 req.AttributeDefinitions = attributes 197 } 198 199 if lsidata, ok := d.GetOk("local_secondary_index"); ok { 200 fmt.Printf("[DEBUG] Adding LSI data to the table") 201 202 lsiSet := lsidata.(*schema.Set) 203 localSecondaryIndexes := []*dynamodb.LocalSecondaryIndex{} 204 for _, lsiObject := range lsiSet.List() { 205 lsi := lsiObject.(map[string]interface{}) 206 207 projection := &dynamodb.Projection{ 208 ProjectionType: aws.String(lsi["projection_type"].(string)), 209 } 210 211 if lsi["projection_type"] != "ALL" { 212 non_key_attributes := []*string{} 213 for _, attr := range lsi["non_key_attributes"].([]interface{}) { 214 non_key_attributes = append(non_key_attributes, aws.String(attr.(string))) 215 } 216 projection.NonKeyAttributes = non_key_attributes 217 } 218 219 localSecondaryIndexes = append(localSecondaryIndexes, &dynamodb.LocalSecondaryIndex{ 220 IndexName: aws.String(lsi["name"].(string)), 221 KeySchema: []*dynamodb.KeySchemaElement{ 222 &dynamodb.KeySchemaElement{ 223 AttributeName: aws.String(hash_key_name), 224 KeyType: aws.String("HASH"), 225 }, 226 &dynamodb.KeySchemaElement{ 227 AttributeName: aws.String(lsi["range_key"].(string)), 228 KeyType: aws.String("RANGE"), 229 }, 230 }, 231 Projection: projection, 232 }) 233 } 234 235 req.LocalSecondaryIndexes = localSecondaryIndexes 236 237 fmt.Printf("[DEBUG] Added %d LSI definitions", len(localSecondaryIndexes)) 238 } 239 240 if gsidata, ok := d.GetOk("global_secondary_index"); ok { 241 globalSecondaryIndexes := []*dynamodb.GlobalSecondaryIndex{} 242 243 gsiSet := gsidata.(*schema.Set) 244 for _, gsiObject := range gsiSet.List() { 245 gsi := gsiObject.(map[string]interface{}) 246 gsiObject := createGSIFromData(&gsi) 247 globalSecondaryIndexes = append(globalSecondaryIndexes, &gsiObject) 248 } 249 req.GlobalSecondaryIndexes = globalSecondaryIndexes 250 } 251 252 output, err := dynamodbconn.CreateTable(req) 253 if err != nil { 254 return fmt.Errorf("Error creating DynamoDB table: %s", err) 255 } 256 257 d.SetId(*output.TableDescription.TableName) 258 259 // Creation complete, nothing to re-read 260 return nil 261 } 262 263 func resourceAwsDynamoDbTableUpdate(d *schema.ResourceData, meta interface{}) error { 264 265 log.Printf("[DEBUG] Updating DynamoDB table %s", d.Id()) 266 dynamodbconn := meta.(*AWSClient).dynamodbconn 267 268 // Ensure table is active before trying to update 269 waitForTableToBeActive(d.Id(), meta) 270 271 // LSI can only be done at create-time, abort if it's been changed 272 if d.HasChange("local_secondary_index") { 273 return fmt.Errorf("Local secondary indexes can only be built at creation, you cannot update them!") 274 } 275 276 if d.HasChange("hash_key") { 277 return fmt.Errorf("Hash key can only be specified at creation, you cannot modify it.") 278 } 279 280 if d.HasChange("range_key") { 281 return fmt.Errorf("Range key can only be specified at creation, you cannot modify it.") 282 } 283 284 if d.HasChange("read_capacity") || d.HasChange("write_capacity") { 285 req := &dynamodb.UpdateTableInput{ 286 TableName: aws.String(d.Id()), 287 } 288 289 throughput := &dynamodb.ProvisionedThroughput{ 290 ReadCapacityUnits: aws.Long(int64(d.Get("read_capacity").(int))), 291 WriteCapacityUnits: aws.Long(int64(d.Get("write_capacity").(int))), 292 } 293 req.ProvisionedThroughput = throughput 294 295 _, err := dynamodbconn.UpdateTable(req) 296 297 if err != nil { 298 return err 299 } 300 301 waitForTableToBeActive(d.Id(), meta) 302 } 303 304 if d.HasChange("global_secondary_index") { 305 log.Printf("[DEBUG] Changed GSI data") 306 req := &dynamodb.UpdateTableInput{ 307 TableName: aws.String(d.Id()), 308 } 309 310 o, n := d.GetChange("global_secondary_index") 311 312 oldSet := o.(*schema.Set) 313 newSet := n.(*schema.Set) 314 315 // Track old names so we can know which ones we need to just update based on 316 // capacity changes, terraform appears to only diff on the set hash, not the 317 // contents so we need to make sure we don't delete any indexes that we 318 // just want to update the capacity for 319 oldGsiNameSet := make(map[string]bool) 320 newGsiNameSet := make(map[string]bool) 321 322 for _, gsidata := range oldSet.List() { 323 gsiName := gsidata.(map[string]interface{})["name"].(string) 324 oldGsiNameSet[gsiName] = true 325 } 326 327 for _, gsidata := range newSet.List() { 328 gsiName := gsidata.(map[string]interface{})["name"].(string) 329 newGsiNameSet[gsiName] = true 330 } 331 332 // First determine what's new 333 for _, newgsidata := range newSet.List() { 334 updates := []*dynamodb.GlobalSecondaryIndexUpdate{} 335 newGsiName := newgsidata.(map[string]interface{})["name"].(string) 336 if _, exists := oldGsiNameSet[newGsiName]; !exists { 337 attributes := []*dynamodb.AttributeDefinition{} 338 gsidata := newgsidata.(map[string]interface{}) 339 gsi := createGSIFromData(&gsidata) 340 log.Printf("[DEBUG] Adding GSI %s", *gsi.IndexName) 341 update := &dynamodb.GlobalSecondaryIndexUpdate{ 342 Create: &dynamodb.CreateGlobalSecondaryIndexAction{ 343 IndexName: gsi.IndexName, 344 KeySchema: gsi.KeySchema, 345 ProvisionedThroughput: gsi.ProvisionedThroughput, 346 Projection: gsi.Projection, 347 }, 348 } 349 updates = append(updates, update) 350 351 // Hash key is required, range key isn't 352 hashkey_type, err := getAttributeType(d, *(gsi.KeySchema[0].AttributeName)) 353 if err != nil { 354 return err 355 } 356 357 attributes = append(attributes, &dynamodb.AttributeDefinition{ 358 AttributeName: gsi.KeySchema[0].AttributeName, 359 AttributeType: aws.String(hashkey_type), 360 }) 361 362 // If there's a range key, there will be 2 elements in KeySchema 363 if len(gsi.KeySchema) == 2 { 364 rangekey_type, err := getAttributeType(d, *(gsi.KeySchema[1].AttributeName)) 365 if err != nil { 366 return err 367 } 368 369 attributes = append(attributes, &dynamodb.AttributeDefinition{ 370 AttributeName: gsi.KeySchema[1].AttributeName, 371 AttributeType: aws.String(rangekey_type), 372 }) 373 } 374 375 req.AttributeDefinitions = attributes 376 req.GlobalSecondaryIndexUpdates = updates 377 _, err = dynamodbconn.UpdateTable(req) 378 379 if err != nil { 380 return err 381 } 382 383 waitForTableToBeActive(d.Id(), meta) 384 waitForGSIToBeActive(d.Id(), *gsi.IndexName, meta) 385 386 } 387 } 388 389 for _, oldgsidata := range oldSet.List() { 390 updates := []*dynamodb.GlobalSecondaryIndexUpdate{} 391 oldGsiName := oldgsidata.(map[string]interface{})["name"].(string) 392 if _, exists := newGsiNameSet[oldGsiName]; !exists { 393 gsidata := oldgsidata.(map[string]interface{}) 394 log.Printf("[DEBUG] Deleting GSI %s", gsidata["name"].(string)) 395 update := &dynamodb.GlobalSecondaryIndexUpdate{ 396 Delete: &dynamodb.DeleteGlobalSecondaryIndexAction{ 397 IndexName: aws.String(gsidata["name"].(string)), 398 }, 399 } 400 updates = append(updates, update) 401 402 req.GlobalSecondaryIndexUpdates = updates 403 _, err := dynamodbconn.UpdateTable(req) 404 405 if err != nil { 406 return err 407 } 408 409 waitForTableToBeActive(d.Id(), meta) 410 } 411 } 412 } 413 414 // Update any out-of-date read / write capacity 415 if gsiObjects, ok := d.GetOk("global_secondary_index"); ok { 416 gsiSet := gsiObjects.(*schema.Set) 417 if len(gsiSet.List()) > 0 { 418 log.Printf("Updating capacity as needed!") 419 420 // We can only change throughput, but we need to make sure it's actually changed 421 tableDescription, err := dynamodbconn.DescribeTable(&dynamodb.DescribeTableInput{ 422 TableName: aws.String(d.Id()), 423 }) 424 425 if err != nil { 426 return err 427 } 428 429 table := tableDescription.Table 430 431 updates := []*dynamodb.GlobalSecondaryIndexUpdate{} 432 433 for _, updatedgsidata := range gsiSet.List() { 434 gsidata := updatedgsidata.(map[string]interface{}) 435 gsiName := gsidata["name"].(string) 436 gsiWriteCapacity := gsidata["write_capacity"].(int) 437 gsiReadCapacity := gsidata["read_capacity"].(int) 438 439 log.Printf("[DEBUG] Updating GSI %s", gsiName) 440 gsi, err := getGlobalSecondaryIndex(gsiName, table.GlobalSecondaryIndexes) 441 442 if err != nil { 443 return err 444 } 445 446 capacityUpdated := false 447 448 if int64(gsiReadCapacity) != *(gsi.ProvisionedThroughput.ReadCapacityUnits) || 449 int64(gsiWriteCapacity) != *(gsi.ProvisionedThroughput.WriteCapacityUnits) { 450 capacityUpdated = true 451 } 452 453 if capacityUpdated { 454 update := &dynamodb.GlobalSecondaryIndexUpdate{ 455 Update: &dynamodb.UpdateGlobalSecondaryIndexAction{ 456 IndexName: aws.String(gsidata["name"].(string)), 457 ProvisionedThroughput: &dynamodb.ProvisionedThroughput{ 458 WriteCapacityUnits: aws.Long(int64(gsiWriteCapacity)), 459 ReadCapacityUnits: aws.Long(int64(gsiReadCapacity)), 460 }, 461 }, 462 } 463 updates = append(updates, update) 464 465 } 466 467 if len(updates) > 0 { 468 469 req := &dynamodb.UpdateTableInput{ 470 TableName: aws.String(d.Id()), 471 } 472 473 req.GlobalSecondaryIndexUpdates = updates 474 475 log.Printf("[DEBUG] Updating GSI read / write capacity on %s", d.Id()) 476 _, err := dynamodbconn.UpdateTable(req) 477 478 if err != nil { 479 log.Printf("[DEBUG] Error updating table: %s", err) 480 return err 481 } 482 } 483 } 484 } 485 486 } 487 488 return resourceAwsDynamoDbTableRead(d, meta) 489 } 490 491 func resourceAwsDynamoDbTableRead(d *schema.ResourceData, meta interface{}) error { 492 dynamodbconn := meta.(*AWSClient).dynamodbconn 493 log.Printf("[DEBUG] Loading data for DynamoDB table '%s'", d.Id()) 494 req := &dynamodb.DescribeTableInput{ 495 TableName: aws.String(d.Id()), 496 } 497 498 result, err := dynamodbconn.DescribeTable(req) 499 500 if err != nil { 501 return err 502 } 503 504 table := result.Table 505 506 d.Set("write_capacity", table.ProvisionedThroughput.WriteCapacityUnits) 507 d.Set("read_capacity", table.ProvisionedThroughput.ReadCapacityUnits) 508 509 attributes := []interface{}{} 510 for _, attrdef := range table.AttributeDefinitions { 511 attribute := map[string]string{ 512 "name": *(attrdef.AttributeName), 513 "type": *(attrdef.AttributeType), 514 } 515 attributes = append(attributes, attribute) 516 log.Printf("[DEBUG] Added Attribute: %s", attribute["name"]) 517 } 518 519 d.Set("attribute", attributes) 520 521 gsiList := make([]map[string]interface{}, 0, len(table.GlobalSecondaryIndexes)) 522 for _, gsiObject := range table.GlobalSecondaryIndexes { 523 gsi := map[string]interface{}{ 524 "write_capacity": *(gsiObject.ProvisionedThroughput.WriteCapacityUnits), 525 "read_capacity": *(gsiObject.ProvisionedThroughput.ReadCapacityUnits), 526 "name": *(gsiObject.IndexName), 527 } 528 529 for _, attribute := range gsiObject.KeySchema { 530 if *attribute.KeyType == "HASH" { 531 gsi["hash_key"] = *attribute.AttributeName 532 } 533 534 if *attribute.KeyType == "RANGE" { 535 gsi["range_key"] = *attribute.AttributeName 536 } 537 } 538 539 gsi["projection_type"] = *(gsiObject.Projection.ProjectionType) 540 gsi["non_key_attributes"] = gsiObject.Projection.NonKeyAttributes 541 542 gsiList = append(gsiList, gsi) 543 log.Printf("[DEBUG] Added GSI: %s - Read: %d / Write: %d", gsi["name"], gsi["read_capacity"], gsi["write_capacity"]) 544 } 545 546 d.Set("global_secondary_index", gsiList) 547 548 return nil 549 } 550 551 func resourceAwsDynamoDbTableDelete(d *schema.ResourceData, meta interface{}) error { 552 dynamodbconn := meta.(*AWSClient).dynamodbconn 553 554 waitForTableToBeActive(d.Id(), meta) 555 556 log.Printf("[DEBUG] DynamoDB delete table: %s", d.Id()) 557 558 _, err := dynamodbconn.DeleteTable(&dynamodb.DeleteTableInput{ 559 TableName: aws.String(d.Id()), 560 }) 561 if err != nil { 562 return err 563 } 564 return nil 565 } 566 567 func createGSIFromData(data *map[string]interface{}) dynamodb.GlobalSecondaryIndex { 568 569 projection := &dynamodb.Projection{ 570 ProjectionType: aws.String((*data)["projection_type"].(string)), 571 } 572 573 if (*data)["projection_type"] != "ALL" { 574 non_key_attributes := []*string{} 575 for _, attr := range (*data)["non_key_attributes"].([]interface{}) { 576 non_key_attributes = append(non_key_attributes, aws.String(attr.(string))) 577 } 578 projection.NonKeyAttributes = non_key_attributes 579 } 580 581 writeCapacity := (*data)["write_capacity"].(int) 582 readCapacity := (*data)["read_capacity"].(int) 583 584 key_schema := []*dynamodb.KeySchemaElement{ 585 &dynamodb.KeySchemaElement{ 586 AttributeName: aws.String((*data)["hash_key"].(string)), 587 KeyType: aws.String("HASH"), 588 }, 589 } 590 591 range_key_name := (*data)["range_key"] 592 if range_key_name != "" { 593 range_key_element := &dynamodb.KeySchemaElement{ 594 AttributeName: aws.String(range_key_name.(string)), 595 KeyType: aws.String("RANGE"), 596 } 597 598 key_schema = append(key_schema, range_key_element) 599 } 600 601 return dynamodb.GlobalSecondaryIndex{ 602 IndexName: aws.String((*data)["name"].(string)), 603 KeySchema: key_schema, 604 Projection: projection, 605 ProvisionedThroughput: &dynamodb.ProvisionedThroughput{ 606 WriteCapacityUnits: aws.Long(int64(writeCapacity)), 607 ReadCapacityUnits: aws.Long(int64(readCapacity)), 608 }, 609 } 610 } 611 612 func getGlobalSecondaryIndex(indexName string, indexList []*dynamodb.GlobalSecondaryIndexDescription) (*dynamodb.GlobalSecondaryIndexDescription, error) { 613 for _, gsi := range indexList { 614 if *(gsi.IndexName) == indexName { 615 return gsi, nil 616 } 617 } 618 619 return &dynamodb.GlobalSecondaryIndexDescription{}, fmt.Errorf("Can't find a GSI by that name...") 620 } 621 622 func getAttributeType(d *schema.ResourceData, attributeName string) (string, error) { 623 if attributedata, ok := d.GetOk("attribute"); ok { 624 attributeSet := attributedata.(*schema.Set) 625 for _, attribute := range attributeSet.List() { 626 attr := attribute.(map[string]interface{}) 627 if attr["name"] == attributeName { 628 return attr["type"].(string), nil 629 } 630 } 631 } 632 633 return "", fmt.Errorf("Unable to find an attribute named %s", attributeName) 634 } 635 636 func waitForGSIToBeActive(tableName string, gsiName string, meta interface{}) error { 637 dynamodbconn := meta.(*AWSClient).dynamodbconn 638 req := &dynamodb.DescribeTableInput{ 639 TableName: aws.String(tableName), 640 } 641 642 activeIndex := false 643 644 for activeIndex == false { 645 646 result, err := dynamodbconn.DescribeTable(req) 647 648 if err != nil { 649 return err 650 } 651 652 table := result.Table 653 var targetGSI *dynamodb.GlobalSecondaryIndexDescription = nil 654 655 for _, gsi := range table.GlobalSecondaryIndexes { 656 if *gsi.IndexName == gsiName { 657 targetGSI = gsi 658 } 659 } 660 661 if targetGSI != nil { 662 activeIndex = *targetGSI.IndexStatus == "ACTIVE" 663 664 if !activeIndex { 665 log.Printf("[DEBUG] Sleeping for 5 seconds for %s GSI to become active", gsiName) 666 time.Sleep(5 * time.Second) 667 } 668 } else { 669 log.Printf("[DEBUG] GSI %s did not exist, giving up", gsiName) 670 break 671 } 672 } 673 674 return nil 675 676 } 677 678 func waitForTableToBeActive(tableName string, meta interface{}) error { 679 dynamodbconn := meta.(*AWSClient).dynamodbconn 680 req := &dynamodb.DescribeTableInput{ 681 TableName: aws.String(tableName), 682 } 683 684 activeState := false 685 686 for activeState == false { 687 result, err := dynamodbconn.DescribeTable(req) 688 689 if err != nil { 690 return err 691 } 692 693 activeState = *(result.Table.TableStatus) == "ACTIVE" 694 695 // Wait for a few seconds 696 if !activeState { 697 log.Printf("[DEBUG] Sleeping for 5 seconds for table to become active") 698 time.Sleep(5 * time.Second) 699 } 700 } 701 702 return nil 703 704 }