github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_instance_migrate.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 "strings" 8 9 "github.com/hashicorp/terraform/helper/hashcode" 10 "github.com/hashicorp/terraform/terraform" 11 ) 12 13 func resourceAwsInstanceMigrateState( 14 v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { 15 switch v { 16 case 0: 17 log.Println("[INFO] Found AWS Instance State v0; migrating to v1") 18 return migrateAwsInstanceStateV0toV1(is) 19 default: 20 return is, fmt.Errorf("Unexpected schema version: %d", v) 21 } 22 } 23 24 func migrateAwsInstanceStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) { 25 if is.Empty() || is.Attributes == nil { 26 log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") 27 return is, nil 28 } 29 30 log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) 31 32 // Delete old count 33 delete(is.Attributes, "block_device.#") 34 35 oldBds, err := readV0BlockDevices(is) 36 if err != nil { 37 return is, err 38 } 39 // seed count fields for new types 40 is.Attributes["ebs_block_device.#"] = "0" 41 is.Attributes["ephemeral_block_device.#"] = "0" 42 // depending on if state was v0.3.7 or an earlier version, it might have 43 // root_block_device defined already 44 if _, ok := is.Attributes["root_block_device.#"]; !ok { 45 is.Attributes["root_block_device.#"] = "0" 46 } 47 for _, oldBd := range oldBds { 48 if err := writeV1BlockDevice(is, oldBd); err != nil { 49 return is, err 50 } 51 } 52 log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) 53 return is, nil 54 } 55 56 func readV0BlockDevices(is *terraform.InstanceState) (map[string]map[string]string, error) { 57 oldBds := make(map[string]map[string]string) 58 for k, v := range is.Attributes { 59 if !strings.HasPrefix(k, "block_device.") { 60 continue 61 } 62 path := strings.Split(k, ".") 63 if len(path) != 3 { 64 return oldBds, fmt.Errorf("Found unexpected block_device field: %#v", k) 65 } 66 hashcode, attribute := path[1], path[2] 67 oldBd, ok := oldBds[hashcode] 68 if !ok { 69 oldBd = make(map[string]string) 70 oldBds[hashcode] = oldBd 71 } 72 oldBd[attribute] = v 73 delete(is.Attributes, k) 74 } 75 return oldBds, nil 76 } 77 78 func writeV1BlockDevice( 79 is *terraform.InstanceState, oldBd map[string]string) error { 80 code := hashcode.String(oldBd["device_name"]) 81 bdType := "ebs_block_device" 82 if vn, ok := oldBd["virtual_name"]; ok && strings.HasPrefix(vn, "ephemeral") { 83 bdType = "ephemeral_block_device" 84 } else if dn, ok := oldBd["device_name"]; ok && dn == "/dev/sda1" { 85 bdType = "root_block_device" 86 } 87 88 switch bdType { 89 case "ebs_block_device": 90 delete(oldBd, "virtual_name") 91 case "root_block_device": 92 delete(oldBd, "virtual_name") 93 delete(oldBd, "encrypted") 94 delete(oldBd, "snapshot_id") 95 case "ephemeral_block_device": 96 delete(oldBd, "delete_on_termination") 97 delete(oldBd, "encrypted") 98 delete(oldBd, "iops") 99 delete(oldBd, "volume_size") 100 delete(oldBd, "volume_type") 101 } 102 for attr, val := range oldBd { 103 attrKey := fmt.Sprintf("%s.%d.%s", bdType, code, attr) 104 is.Attributes[attrKey] = val 105 } 106 107 countAttr := fmt.Sprintf("%s.#", bdType) 108 count, _ := strconv.Atoi(is.Attributes[countAttr]) 109 is.Attributes[countAttr] = strconv.Itoa(count + 1) 110 return nil 111 }