func (m schemaMap) diff( k string, schema *Schema, diff *terraform.InstanceDiff, d *ResourceData, all bool) error { unsupressedDiff := new(terraform.InstanceDiff) unsupressedDiff.Attributes = make(map[string]*terraform.ResourceAttrDiff) var err error switch schema.Type { case TypeBool, TypeInt, TypeFloat, TypeString: err = m.diffString(k, schema, unsupressedDiff, d, all) case TypeList: err = m.diffList(k, schema, unsupressedDiff, d, all) case TypeMap: err = m.diffMap(k, schema, unsupressedDiff, d, all) case TypeSet: err = m.diffSet(k, schema, unsupressedDiff, d, all) default: err = fmt.Errorf("%s: unknown type %#v", k, schema.Type) } for attrK, attrV := range unsupressedDiff.Attributes { if schema.DiffSuppressFunc != nil && schema.DiffSuppressFunc(attrK, attrV.Old, attrV.New, d) { continue } diff.Attributes[attrK] = attrV } return err }
func (m schemaMap) diffSet( k string, schema *Schema, diff *terraform.InstanceDiff, d *ResourceData, all bool) error { if !all { // This is a bit strange, but we expect the entire set to be in the diff, // so we first diff the set normally but with a new diff. Then, if // there IS any change, we just set the change to the entire list. tempD := new(terraform.InstanceDiff) tempD.Attributes = make(map[string]*terraform.ResourceAttrDiff) if err := m.diffList(k, schema, tempD, d, false); err != nil { return err } // If we had no changes, then we're done if tempD.Empty() { return nil } } // We have changes, so re-run the diff, but set a flag to force // getting all diffs, even if there is no change. return m.diffList(k, schema, diff, d, true) }
// 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 }