func (m schemaMap) diffString(
	k string,
	schema *Schema,
	diff *terraform.InstanceDiff,
	d *ResourceData,
	all bool) error {
	var originalN interface{}
	var os, ns string
	o, n, _, _ := d.diffChange(k)
	if schema.StateFunc != nil {
		originalN = n
		n = schema.StateFunc(n)
	}
	nraw := n
	if nraw == nil && o != nil {
		nraw = schema.Type.Zero()
	}
	if err := mapstructure.WeakDecode(o, &os); err != nil {
		return fmt.Errorf("%s: %s", k, err)
	}
	if err := mapstructure.WeakDecode(nraw, &ns); err != nil {
		return fmt.Errorf("%s: %s", k, err)
	}

	if os == ns && !all {
		// They're the same value. If there old value is not blank or we
		// have an ID, then return right away since we're already setup.
		if os != "" || d.Id() != "" {
			return nil
		}

		// Otherwise, only continue if we're computed
		if !schema.Computed {
			return nil
		}
	}

	removed := false
	if o != nil && n == nil {
		removed = true
	}
	if removed && schema.Computed {
		return nil
	}

	diff.Attributes[k] = schema.finalizeDiff(&terraform.ResourceAttrDiff{
		Old:        os,
		New:        ns,
		NewExtra:   originalN,
		NewRemoved: removed,
	})

	return nil
}
func (r *DiffFieldReader) readPrimitive(
	address []string, schema *Schema) (FieldReadResult, error) {
	result, err := r.Source.ReadField(address)
	if err != nil {
		return FieldReadResult{}, err
	}

	attrD, ok := r.Diff.Attributes[strings.Join(address, ".")]
	if !ok {
		return result, nil
	}

	var resultVal string
	if !attrD.NewComputed {
		resultVal = attrD.New
		if attrD.NewExtra != nil {
			result.ValueProcessed = resultVal
			if err := mapstructure.WeakDecode(attrD.NewExtra, &resultVal); err != nil {
				return FieldReadResult{}, err
			}
		}
	}

	result.Computed = attrD.NewComputed
	result.Exists = true
	result.Value, err = stringToPrimitive(resultVal, false, schema)
	if err != nil {
		return FieldReadResult{}, err
	}

	return result, nil
}
func (r *ConfigFieldReader) readPrimitive(
	k string, schema *Schema) (FieldReadResult, error) {
	raw, ok := r.Config.Get(k)
	if !ok {
		// Nothing in config, but we might still have a default from the schema
		var err error
		raw, err = schema.DefaultValue()
		if err != nil {
			return FieldReadResult{}, fmt.Errorf("%s, error loading default: %s", k, err)
		}

		if raw == nil {
			return FieldReadResult{}, nil
		}
	}

	var result string
	if err := mapstructure.WeakDecode(raw, &result); err != nil {
		return FieldReadResult{}, err
	}

	computed := r.Config.IsComputed(k)
	returnVal, err := stringToPrimitive(result, computed, schema)
	if err != nil {
		return FieldReadResult{}, err
	}

	return FieldReadResult{
		Value:    returnVal,
		Exists:   true,
		Computed: computed,
	}, nil
}
// Type returns the type of varialbe this is.
func (v *Variable) Type() VariableType {
	if v.Default == nil {
		return VariableTypeString
	}

	var strVal string
	if err := mapstructure.WeakDecode(v.Default, &strVal); err == nil {
		v.Default = strVal
		return VariableTypeString
	}

	var m map[string]string
	if err := mapstructure.WeakDecode(v.Default, &m); err == nil {
		v.Default = m
		return VariableTypeMap
	}

	return VariableTypeUnknown
}
func (m schemaMap) validatePrimitive(
	k string,
	raw interface{},
	schema *Schema,
	c *terraform.ResourceConfig) ([]string, []error) {
	if c.IsComputed(k) {
		// If the key is being computed, then it is not an error
		return nil, nil
	}

	switch schema.Type {
	case TypeBool:
		// Verify that we can parse this as the correct type
		var n bool
		if err := mapstructure.WeakDecode(raw, &n); err != nil {
			return nil, []error{err}
		}
	case TypeInt:
		// Verify that we can parse this as an int
		var n int
		if err := mapstructure.WeakDecode(raw, &n); err != nil {
			return nil, []error{err}
		}
	case TypeFloat:
		// Verify that we can parse this as an int
		var n float64
		if err := mapstructure.WeakDecode(raw, &n); err != nil {
			return nil, []error{err}
		}
	case TypeString:
		// Verify that we can parse this as a string
		var n string
		if err := mapstructure.WeakDecode(raw, &n); err != nil {
			return nil, []error{err}
		}
	default:
		panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type))
	}

	return nil, nil
}
func (m schemaMap) diffMap(
	k string,
	schema *Schema,
	diff *terraform.InstanceDiff,
	d *ResourceData,
	all bool) error {
	prefix := k + "."

	// First get all the values from the state
	var stateMap, configMap map[string]string
	o, n, _, nComputed := d.diffChange(k)
	if err := mapstructure.WeakDecode(o, &stateMap); err != nil {
		return fmt.Errorf("%s: %s", k, err)
	}
	if err := mapstructure.WeakDecode(n, &configMap); err != nil {
		return fmt.Errorf("%s: %s", k, err)
	}

	// Keep track of whether the state _exists_ at all prior to clearing it
	stateExists := o != nil

	// Delete any count values, since we don't use those
	delete(configMap, "#")
	delete(stateMap, "#")

	// Check if the number of elements has changed.
	oldLen, newLen := len(stateMap), len(configMap)
	changed := oldLen != newLen
	if oldLen != 0 && newLen == 0 && schema.Computed {
		changed = false
	}

	// It is computed if we have no old value, no new value, the schema
	// says it is computed, and it didn't exist in the state before. The
	// last point means: if it existed in the state, even empty, then it
	// has already been computed.
	computed := oldLen == 0 && newLen == 0 && schema.Computed && !stateExists

	// If the count has changed or we're computed, then add a diff for the
	// count. "nComputed" means that the new value _contains_ a value that
	// is computed. We don't do granular diffs for this yet, so we mark the
	// whole map as computed.
	if changed || computed || nComputed {
		countSchema := &Schema{
			Type:     TypeInt,
			Computed: schema.Computed || nComputed,
			ForceNew: schema.ForceNew,
		}

		oldStr := strconv.FormatInt(int64(oldLen), 10)
		newStr := ""
		if !computed && !nComputed {
			newStr = strconv.FormatInt(int64(newLen), 10)
		} else {
			oldStr = ""
		}

		diff.Attributes[k+".#"] = countSchema.finalizeDiff(
			&terraform.ResourceAttrDiff{
				Old: oldStr,
				New: newStr,
			},
		)
	}

	// If the new map is nil and we're computed, then ignore it.
	if n == nil && schema.Computed {
		return nil
	}

	// Now we compare, preferring values from the config map
	for k, v := range configMap {
		old, ok := stateMap[k]
		delete(stateMap, k)

		if old == v && ok && !all {
			continue
		}

		diff.Attributes[prefix+k] = schema.finalizeDiff(&terraform.ResourceAttrDiff{
			Old: old,
			New: v,
		})
	}
	for k, v := range stateMap {
		diff.Attributes[prefix+k] = schema.finalizeDiff(&terraform.ResourceAttrDiff{
			Old:        v,
			NewRemoved: true,
		})
	}

	return nil
}
// Validate does some basic semantic checking of the configuration.
func (c *Config) Validate() error {
	if c == nil {
		return nil
	}

	var errs []error

	for _, k := range c.unknownKeys {
		errs = append(errs, fmt.Errorf(
			"Unknown root level key: %s", k))
	}

	vars := c.InterpolatedVariables()
	varMap := make(map[string]*Variable)
	for _, v := range c.Variables {
		varMap[v.Name] = v
	}

	for _, v := range c.Variables {
		if v.Type() == VariableTypeUnknown {
			errs = append(errs, fmt.Errorf(
				"Variable '%s': must be string or mapping",
				v.Name))
			continue
		}

		interp := false
		fn := func(ast.Node) (string, error) {
			interp = true
			return "", nil
		}

		w := &interpolationWalker{F: fn}
		if v.Default != nil {
			if err := reflectwalk.Walk(v.Default, w); err == nil {
				if interp {
					errs = append(errs, fmt.Errorf(
						"Variable '%s': cannot contain interpolations",
						v.Name))
				}
			}
		}
	}

	// Check for references to user variables that do not actually
	// exist and record those errors.
	for source, vs := range vars {
		for _, v := range vs {
			uv, ok := v.(*UserVariable)
			if !ok {
				continue
			}

			if _, ok := varMap[uv.Name]; !ok {
				errs = append(errs, fmt.Errorf(
					"%s: unknown variable referenced: '%s'. define it with 'variable' blocks",
					source,
					uv.Name))
			}
		}
	}

	// Check that all count variables are valid.
	for source, vs := range vars {
		for _, rawV := range vs {
			switch v := rawV.(type) {
			case *CountVariable:
				if v.Type == CountValueInvalid {
					errs = append(errs, fmt.Errorf(
						"%s: invalid count variable: %s",
						source,
						v.FullKey()))
				}
			case *PathVariable:
				if v.Type == PathValueInvalid {
					errs = append(errs, fmt.Errorf(
						"%s: invalid path variable: %s",
						source,
						v.FullKey()))
				}
			}
		}
	}

	// Check that providers aren't declared multiple times.
	providerSet := make(map[string]struct{})
	for _, p := range c.ProviderConfigs {
		name := p.FullName()
		if _, ok := providerSet[name]; ok {
			errs = append(errs, fmt.Errorf(
				"provider.%s: declared multiple times, you can only declare a provider once",
				name))
			continue
		}

		providerSet[name] = struct{}{}
	}

	// Check that all references to modules are valid
	modules := make(map[string]*Module)
	dupped := make(map[string]struct{})
	for _, m := range c.Modules {
		// Check for duplicates
		if _, ok := modules[m.Id()]; ok {
			if _, ok := dupped[m.Id()]; !ok {
				dupped[m.Id()] = struct{}{}

				errs = append(errs, fmt.Errorf(
					"%s: module repeated multiple times",
					m.Id()))
			}

			// Already seen this module, just skip it
			continue
		}

		modules[m.Id()] = m

		// Check that the source has no interpolations
		rc, err := NewRawConfig(map[string]interface{}{
			"root": m.Source,
		})
		if err != nil {
			errs = append(errs, fmt.Errorf(
				"%s: module source error: %s",
				m.Id(), err))
		} else if len(rc.Interpolations) > 0 {
			errs = append(errs, fmt.Errorf(
				"%s: module source cannot contain interpolations",
				m.Id()))
		}

		// Check that the name matches our regexp
		if !NameRegexp.Match([]byte(m.Name)) {
			errs = append(errs, fmt.Errorf(
				"%s: module name can only contain letters, numbers, "+
					"dashes, and underscores",
				m.Id()))
		}

		// Check that the configuration can all be strings
		raw := make(map[string]interface{})
		for k, v := range m.RawConfig.Raw {
			var strVal string
			if err := mapstructure.WeakDecode(v, &strVal); err != nil {
				errs = append(errs, fmt.Errorf(
					"%s: variable %s must be a string value",
					m.Id(), k))
			}
			raw[k] = strVal
		}

		// Check for invalid count variables
		for _, v := range m.RawConfig.Variables {
			switch v.(type) {
			case *CountVariable:
				errs = append(errs, fmt.Errorf(
					"%s: count variables are only valid within resources", m.Name))
			case *SelfVariable:
				errs = append(errs, fmt.Errorf(
					"%s: self variables are only valid within resources", m.Name))
			}
		}

		// Update the raw configuration to only contain the string values
		m.RawConfig, err = NewRawConfig(raw)
		if err != nil {
			errs = append(errs, fmt.Errorf(
				"%s: can't initialize configuration: %s",
				m.Id(), err))
		}
	}
	dupped = nil

	// Check that all variables for modules reference modules that
	// exist.
	for source, vs := range vars {
		for _, v := range vs {
			mv, ok := v.(*ModuleVariable)
			if !ok {
				continue
			}

			if _, ok := modules[mv.Name]; !ok {
				errs = append(errs, fmt.Errorf(
					"%s: unknown module referenced: %s",
					source,
					mv.Name))
			}
		}
	}

	// Check that all references to resources are valid
	resources := make(map[string]*Resource)
	dupped = make(map[string]struct{})
	for _, r := range c.Resources {
		if _, ok := resources[r.Id()]; ok {
			if _, ok := dupped[r.Id()]; !ok {
				dupped[r.Id()] = struct{}{}

				errs = append(errs, fmt.Errorf(
					"%s: resource repeated multiple times",
					r.Id()))
			}
		}

		resources[r.Id()] = r
	}
	dupped = nil

	// Validate resources
	for n, r := range resources {
		// Verify count variables
		for _, v := range r.RawCount.Variables {
			switch v.(type) {
			case *CountVariable:
				errs = append(errs, fmt.Errorf(
					"%s: resource count can't reference count variable: %s",
					n,
					v.FullKey()))
			case *ModuleVariable:
				errs = append(errs, fmt.Errorf(
					"%s: resource count can't reference module variable: %s",
					n,
					v.FullKey()))
			case *ResourceVariable:
				errs = append(errs, fmt.Errorf(
					"%s: resource count can't reference resource variable: %s",
					n,
					v.FullKey()))
			case *UserVariable:
				// Good
			default:
				panic("Unknown type in count var: " + n)
			}
		}

		// Interpolate with a fixed number to verify that its a number.
		r.RawCount.interpolate(func(root ast.Node) (string, error) {
			// Execute the node but transform the AST so that it returns
			// a fixed value of "5" for all interpolations.
			out, _, err := lang.Eval(
				lang.FixedValueTransform(
					root, &ast.LiteralNode{Value: "5", Typex: ast.TypeString}),
				nil)
			if err != nil {
				return "", err
			}

			return out.(string), nil
		})
		_, err := strconv.ParseInt(r.RawCount.Value().(string), 0, 0)
		if err != nil {
			errs = append(errs, fmt.Errorf(
				"%s: resource count must be an integer",
				n))
		}
		r.RawCount.init()

		// Verify depends on points to resources that all exist
		for _, d := range r.DependsOn {
			// Check if we contain interpolations
			rc, err := NewRawConfig(map[string]interface{}{
				"value": d,
			})
			if err == nil && len(rc.Variables) > 0 {
				errs = append(errs, fmt.Errorf(
					"%s: depends on value cannot contain interpolations: %s",
					n, d))
				continue
			}

			if _, ok := resources[d]; !ok {
				errs = append(errs, fmt.Errorf(
					"%s: resource depends on non-existent resource '%s'",
					n, d))
			}
		}

		// Verify provider points to a provider that is configured
		if r.Provider != "" {
			if _, ok := providerSet[r.Provider]; !ok {
				errs = append(errs, fmt.Errorf(
					"%s: resource depends on non-configured provider '%s'",
					n, r.Provider))
			}
		}

		// Verify provisioners don't contain any splats
		for _, p := range r.Provisioners {
			// This validation checks that there are now splat variables
			// referencing ourself. This currently is not allowed.

			for _, v := range p.ConnInfo.Variables {
				rv, ok := v.(*ResourceVariable)
				if !ok {
					continue
				}

				if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
					errs = append(errs, fmt.Errorf(
						"%s: connection info cannot contain splat variable "+
							"referencing itself", n))
					break
				}
			}

			for _, v := range p.RawConfig.Variables {
				rv, ok := v.(*ResourceVariable)
				if !ok {
					continue
				}

				if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
					errs = append(errs, fmt.Errorf(
						"%s: connection info cannot contain splat variable "+
							"referencing itself", n))
					break
				}
			}
		}
	}

	for source, vs := range vars {
		for _, v := range vs {
			rv, ok := v.(*ResourceVariable)
			if !ok {
				continue
			}

			id := fmt.Sprintf("%s.%s", rv.Type, rv.Name)
			if _, ok := resources[id]; !ok {
				errs = append(errs, fmt.Errorf(
					"%s: unknown resource '%s' referenced in variable %s",
					source,
					id,
					rv.FullKey()))
				continue
			}
		}
	}

	// Check that all outputs are valid
	for _, o := range c.Outputs {
		invalid := false
		for k, _ := range o.RawConfig.Raw {
			if k != "value" {
				invalid = true
				break
			}
		}
		if invalid {
			errs = append(errs, fmt.Errorf(
				"%s: output should only have 'value' field", o.Name))
		}

		for _, v := range o.RawConfig.Variables {
			if _, ok := v.(*CountVariable); ok {
				errs = append(errs, fmt.Errorf(
					"%s: count variables are only valid within resources", o.Name))
			}
		}
	}

	// Check that all variables are in the proper context
	for source, rc := range c.rawConfigs() {
		walker := &interpolationWalker{
			ContextF: c.validateVarContextFn(source, &errs),
		}
		if err := reflectwalk.Walk(rc.Raw, walker); err != nil {
			errs = append(errs, fmt.Errorf(
				"%s: error reading config: %s", source, err))
		}
	}

	// Validate the self variable
	for source, rc := range c.rawConfigs() {
		// Ignore provisioners. This is a pretty brittle way to do this,
		// but better than also repeating all the resources.
		if strings.Contains(source, "provision") {
			continue
		}

		for _, v := range rc.Variables {
			if _, ok := v.(*SelfVariable); ok {
				errs = append(errs, fmt.Errorf(
					"%s: cannot contain self-reference %s", source, v.FullKey()))
			}
		}
	}

	if len(errs) > 0 {
		return &multierror.Error{Errors: errs}
	}

	return nil
}