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  }