// Apply creates, updates, and/or deletes a resource. func (r *Resource) Apply( s *terraform.InstanceState, d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { data, err := schemaMap(r.Schema).Data(s, d) if err != nil { return s, err } if s == nil { // The Terraform API dictates that this should never happen, but // it doesn't hurt to be safe in this case. s = new(terraform.InstanceState) } if d.Destroy || d.RequiresNew() { if s.ID != "" { // Destroy the resource since it is created if err := r.Delete(data, meta); err != nil { return data.State(), err } // Make sure the ID is gone. data.SetId("") } // If we're only destroying, and not creating, then return // now since we're done! if !d.RequiresNew() { return nil, nil } // Reset the data to be stateless since we just destroyed data, err = schemaMap(r.Schema).Data(nil, d) if err != nil { return nil, err } } err = nil if data.Id() == "" { // We're creating, it is a new resource. err = r.Create(data, meta) } else { if r.Update == nil { return s, fmt.Errorf("doesn't support update") } err = r.Update(data, meta) } return r.recordCurrentSchemaVersion(data.State()), err }
// Diff returns the diff for a resource given the schema map, // state, and configuration. func (m schemaMap) Diff( s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { result := new(terraform.InstanceDiff) result.Attributes = make(map[string]*terraform.ResourceAttrDiff) d := &ResourceData{ schema: m, state: s, config: c, } for k, schema := range m { err := m.diff(k, schema, result, d, false) if err != nil { return nil, err } } // If the diff requires a new resource, then we recompute the diff // so we have the complete new resource diff, and preserve the // RequiresNew fields where necessary so the user knows exactly what // caused that. if result.RequiresNew() { // Create the new diff result2 := new(terraform.InstanceDiff) result2.Attributes = make(map[string]*terraform.ResourceAttrDiff) // Reset the data to not contain state. We have to call init() // again in order to reset the FieldReaders. d.state = nil d.init() // Perform the diff again for k, schema := range m { err := m.diff(k, schema, result2, d, false) if err != nil { return nil, err } } // Force all the fields to not force a new since we know what we // want to force new. for k, attr := range result2.Attributes { if attr == nil { continue } if attr.RequiresNew { attr.RequiresNew = false } if s != nil { attr.Old = s.Attributes[k] } } // Now copy in all the requires new diffs... for k, attr := range result.Attributes { if attr == nil { continue } newAttr, ok := result2.Attributes[k] if !ok { newAttr = attr } if attr.RequiresNew { newAttr.RequiresNew = true } result2.Attributes[k] = newAttr } // And set the diff! result = result2 } // Remove any nil diffs just to keep things clean for k, v := range result.Attributes { if v == nil { delete(result.Attributes, k) } } // Go through and detect all of the ComputedWhens now that we've // finished the diff. // TODO if result.Empty() { // If we don't have any diff elements, just return nil return nil, nil } return result, nil }