func resourceComputeInstanceMigrateState( v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { if is.Empty() { log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") return is, nil } switch v { case 0: log.Println("[INFO] Found Compute Instance State v0; migrating to v1") is, err := migrateStateV0toV1(is) if err != nil { return is, err } fallthrough case 1: log.Println("[INFO] Found Compute Instance State v1; migrating to v2") is, err := migrateStateV1toV2(is) if err != nil { return is, err } return is, nil default: return is, fmt.Errorf("Unexpected schema version: %d", v) } }
// Apply executes the remote exec provisioner func (p *ResourceProvisioner) Apply( o terraform.UIOutput, s *terraform.InstanceState, c *terraform.ResourceConfig) error { // Get a new communicator comm, err := communicator.New(s) if err != nil { return err } // Collect the scripts scripts, err := p.collectScripts(c) if err != nil { return err } for _, s := range scripts { defer s.Close() } // Copy and execute each script if err := p.runScripts(o, comm, scripts); err != nil { return err } return nil }
func migrateStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) { if is.Empty() || is.Attributes == nil { log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") return is, nil } log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) // Delete old count delete(is.Attributes, "block_device.#") oldBds, err := readV0BlockDevices(is) if err != nil { return is, err } // seed count fields for new types is.Attributes["ebs_block_device.#"] = "0" is.Attributes["ephemeral_block_device.#"] = "0" // depending on if state was v0.3.7 or an earlier version, it might have // root_block_device defined already if _, ok := is.Attributes["root_block_device.#"]; !ok { is.Attributes["root_block_device.#"] = "0" } for _, oldBd := range oldBds { if err := writeV1BlockDevice(is, oldBd); err != nil { return is, err } } log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) return is, nil }
// State returns the new InstanceState after the diff and any Set // calls. func (d *ResourceData) State() *terraform.InstanceState { var result terraform.InstanceState result.ID = d.Id() // If we have no ID, then this resource doesn't exist and we just // return nil. if result.ID == "" { return nil } // In order to build the final state attributes, we read the full // attribute set as a map[string]interface{}, write it to a MapFieldWriter, // and then use that map. rawMap := make(map[string]interface{}) for k := range d.schema { source := getSourceSet if d.partial { source = getSourceState if _, ok := d.partialMap[k]; ok { source = getSourceSet } } raw := d.get([]string{k}, source) if raw.Exists && !raw.Computed { rawMap[k] = raw.Value if raw.ValueProcessed != nil { rawMap[k] = raw.ValueProcessed } } } mapW := &MapFieldWriter{Schema: d.schema} if err := mapW.WriteField(nil, rawMap); err != nil { return nil } result.Attributes = mapW.Map() result.Ephemeral.ConnInfo = d.ConnInfo() // TODO: This is hacky and we can remove this when we have a proper // state writer. We should instead have a proper StateFieldWriter // and use that. for k, schema := range d.schema { if schema.Type != TypeMap { continue } if result.Attributes[k] == "" { delete(result.Attributes, k) } } if v := d.Id(); v != "" { result.Attributes["id"] = d.Id() } return &result }
// Apply performs a create or update depending on the diff, and calls // the proper function on the matching Resource. func (m *Map) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { r, ok := m.Mapping[info.Type] if !ok { return nil, fmt.Errorf("Unknown resource type: %s", info.Type) } if d.Destroy || d.RequiresNew() { if s.ID != "" { // Destroy the resource if it is created err := r.Destroy(s, meta) if err != nil { return s, err } s.ID = "" } // If we're only destroying, and not creating, then return now. // Otherwise, we continue so that we can create a new resource. if !d.RequiresNew() { return nil, nil } } var result *terraform.InstanceState var err error if s.ID == "" { result, err = r.Create(s, d, meta) } else { if r.Update == nil { return s, fmt.Errorf( "Resource type '%s' doesn't support update", info.Type) } result, err = r.Update(s, d, meta) } if result != nil { if result.Attributes == nil { result.Attributes = make(map[string]string) } result.Attributes["id"] = result.ID } return result, err }
func migrateKeyPairStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) { if is.Empty() { log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") return is, nil } log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) // replace public_key with a stripped version, removing `\n` from the end // see https://github.com/hashicorp/terraform/issues/3455 is.Attributes["public_key"] = strings.TrimSpace(is.Attributes["public_key"]) log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) return is, nil }
func migrateSGRuleStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) { if is.Empty() { log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") return is, nil } perm, err := migrateExpandIPPerm(is.Attributes) if err != nil { return nil, fmt.Errorf("[WARN] Error making new IP Permission in Security Group migration") } log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) newID := ipPermissionIDHash(is.Attributes["security_group_id"], is.Attributes["type"], perm) is.Attributes["id"] = newID is.ID = newID log.Printf("[DEBUG] Attributes after migration: %#v, new id: %s", is.Attributes, newID) return is, nil }
func (r *Resource) recordCurrentSchemaVersion( state *terraform.InstanceState) *terraform.InstanceState { if state != nil && r.SchemaVersion > 0 { if state.Meta == nil { state.Meta = make(map[string]string) } state.Meta["schema_version"] = strconv.Itoa(r.SchemaVersion) } return state }