github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/google/resource_compute_instance_migrate.go (about) 1 package google 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 resourceComputeInstanceMigrateState( 14 v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { 15 if is.Empty() { 16 log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") 17 return is, nil 18 } 19 20 switch v { 21 case 0: 22 log.Println("[INFO] Found Compute Instance State v0; migrating to v1") 23 is, err := migrateStateV0toV1(is) 24 if err != nil { 25 return is, err 26 } 27 fallthrough 28 case 1: 29 log.Println("[INFO] Found Compute Instance State v1; migrating to v2") 30 is, err := migrateStateV1toV2(is) 31 if err != nil { 32 return is, err 33 } 34 return is, nil 35 case 2: 36 log.Println("[INFO] Found Compute Instance State v2; migrating to v3") 37 is, err := migrateStateV2toV3(is) 38 if err != nil { 39 return is, err 40 } 41 return is, nil 42 default: 43 return is, fmt.Errorf("Unexpected schema version: %d", v) 44 } 45 } 46 47 func migrateStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) { 48 log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) 49 50 // Delete old count 51 delete(is.Attributes, "metadata.#") 52 53 newMetadata := make(map[string]string) 54 55 for k, v := range is.Attributes { 56 if !strings.HasPrefix(k, "metadata.") { 57 continue 58 } 59 60 // We have a key that looks like "metadata.*" and we know it's not 61 // metadata.# because we deleted it above, so it must be metadata.<N>.<key> 62 // from the List of Maps. Just need to convert it to a single Map by 63 // ditching the '<N>' field. 64 kParts := strings.SplitN(k, ".", 3) 65 66 // Sanity check: all three parts should be there and <N> should be a number 67 badFormat := false 68 if len(kParts) != 3 { 69 badFormat = true 70 } else if _, err := strconv.Atoi(kParts[1]); err != nil { 71 badFormat = true 72 } 73 74 if badFormat { 75 return is, fmt.Errorf( 76 "migration error: found metadata key in unexpected format: %s", k) 77 } 78 79 // Rejoin as "metadata.<key>" 80 newK := strings.Join([]string{kParts[0], kParts[2]}, ".") 81 newMetadata[newK] = v 82 delete(is.Attributes, k) 83 } 84 85 for k, v := range newMetadata { 86 is.Attributes[k] = v 87 } 88 89 log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) 90 return is, nil 91 } 92 93 func migrateStateV1toV2(is *terraform.InstanceState) (*terraform.InstanceState, error) { 94 log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) 95 96 // Maps service account index to list of scopes for that sccount 97 newScopesMap := make(map[string][]string) 98 99 for k, v := range is.Attributes { 100 if !strings.HasPrefix(k, "service_account.") { 101 continue 102 } 103 104 if k == "service_account.#" { 105 continue 106 } 107 108 if strings.HasSuffix(k, ".scopes.#") { 109 continue 110 } 111 112 if strings.HasSuffix(k, ".email") { 113 continue 114 } 115 116 // Key is now of the form service_account.%d.scopes.%d 117 kParts := strings.Split(k, ".") 118 119 // Sanity check: all three parts should be there and <N> should be a number 120 badFormat := false 121 if len(kParts) != 4 { 122 badFormat = true 123 } else if _, err := strconv.Atoi(kParts[1]); err != nil { 124 badFormat = true 125 } 126 127 if badFormat { 128 return is, fmt.Errorf( 129 "migration error: found scope key in unexpected format: %s", k) 130 } 131 132 newScopesMap[kParts[1]] = append(newScopesMap[kParts[1]], v) 133 134 delete(is.Attributes, k) 135 } 136 137 for service_acct_index, newScopes := range newScopesMap { 138 for _, newScope := range newScopes { 139 hash := hashcode.String(canonicalizeServiceScope(newScope)) 140 newKey := fmt.Sprintf("service_account.%s.scopes.%d", service_acct_index, hash) 141 is.Attributes[newKey] = newScope 142 } 143 } 144 145 log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) 146 return is, nil 147 } 148 149 func migrateStateV2toV3(is *terraform.InstanceState) (*terraform.InstanceState, error) { 150 log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) 151 is.Attributes["create_timeout"] = "4" 152 log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) 153 return is, nil 154 }