예제 #1
0
// 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
}
예제 #2
0
// 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
}