github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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 migrateStateV0toV1(is)
    19  	default:
    20  		return is, fmt.Errorf("Unexpected schema version: %d", v)
    21  	}
    22  }
    23  
    24  func migrateStateV0toV1(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  }