github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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 default: 36 return is, fmt.Errorf("Unexpected schema version: %d", v) 37 } 38 } 39 40 func migrateStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) { 41 log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) 42 43 // Delete old count 44 delete(is.Attributes, "metadata.#") 45 46 newMetadata := make(map[string]string) 47 48 for k, v := range is.Attributes { 49 if !strings.HasPrefix(k, "metadata.") { 50 continue 51 } 52 53 // We have a key that looks like "metadata.*" and we know it's not 54 // metadata.# because we deleted it above, so it must be metadata.<N>.<key> 55 // from the List of Maps. Just need to convert it to a single Map by 56 // ditching the '<N>' field. 57 kParts := strings.SplitN(k, ".", 3) 58 59 // Sanity check: all three parts should be there and <N> should be a number 60 badFormat := false 61 if len(kParts) != 3 { 62 badFormat = true 63 } else if _, err := strconv.Atoi(kParts[1]); err != nil { 64 badFormat = true 65 } 66 67 if badFormat { 68 return is, fmt.Errorf( 69 "migration error: found metadata key in unexpected format: %s", k) 70 } 71 72 // Rejoin as "metadata.<key>" 73 newK := strings.Join([]string{kParts[0], kParts[2]}, ".") 74 newMetadata[newK] = v 75 delete(is.Attributes, k) 76 } 77 78 for k, v := range newMetadata { 79 is.Attributes[k] = v 80 } 81 82 log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) 83 return is, nil 84 } 85 86 func migrateStateV1toV2(is *terraform.InstanceState) (*terraform.InstanceState, error) { 87 log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) 88 89 // Maps service account index to list of scopes for that sccount 90 newScopesMap := make(map[string][]string) 91 92 for k, v := range is.Attributes { 93 if !strings.HasPrefix(k, "service_account.") { 94 continue 95 } 96 97 if k == "service_account.#" { 98 continue 99 } 100 101 if strings.HasSuffix(k, ".scopes.#") { 102 continue 103 } 104 105 if strings.HasSuffix(k, ".email") { 106 continue 107 } 108 109 // Key is now of the form service_account.%d.scopes.%d 110 kParts := strings.Split(k, ".") 111 112 // Sanity check: all three parts should be there and <N> should be a number 113 badFormat := false 114 if len(kParts) != 4 { 115 badFormat = true 116 } else if _, err := strconv.Atoi(kParts[1]); err != nil { 117 badFormat = true 118 } 119 120 if badFormat { 121 return is, fmt.Errorf( 122 "migration error: found scope key in unexpected format: %s", k) 123 } 124 125 newScopesMap[kParts[1]] = append(newScopesMap[kParts[1]], v) 126 127 delete(is.Attributes, k) 128 } 129 130 for service_acct_index, newScopes := range newScopesMap { 131 for _, newScope := range newScopes { 132 hash := hashcode.String(canonicalizeServiceScope(newScope)) 133 newKey := fmt.Sprintf("service_account.%s.scopes.%d", service_acct_index, hash) 134 is.Attributes[newKey] = newScope 135 } 136 } 137 138 log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) 139 return is, nil 140 }