github.com/bengesoff/terraform@v0.3.1-0.20141018223233-b25a53629922/helper/schema/resource_data.go (about)

     1  package schema
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strconv"
     7  	"strings"
     8  	"sync"
     9  
    10  	"github.com/hashicorp/terraform/terraform"
    11  	"github.com/mitchellh/mapstructure"
    12  )
    13  
    14  // ResourceData is used to query and set the attributes of a resource.
    15  //
    16  // ResourceData is the primary argument received for CRUD operations on
    17  // a resource as well as configuration of a provider. It is a powerful
    18  // structure that can be used to not only query data, but check for changes,
    19  // define partial state updates, etc.
    20  //
    21  // The most relevant methods to take a look at are Get, Set, and Partial.
    22  type ResourceData struct {
    23  	// Settable (internally)
    24  	schema  map[string]*Schema
    25  	config  *terraform.ResourceConfig
    26  	state   *terraform.InstanceState
    27  	diff    *terraform.InstanceDiff
    28  	diffing bool
    29  
    30  	// Don't set
    31  	setMap     map[string]string
    32  	newState   *terraform.InstanceState
    33  	partial    bool
    34  	partialMap map[string]struct{}
    35  	once       sync.Once
    36  }
    37  
    38  // getSource represents the level we want to get for a value (internally).
    39  // Any source less than or equal to the level will be loaded (whichever
    40  // has a value first).
    41  type getSource byte
    42  
    43  const (
    44  	getSourceState getSource = 1 << iota
    45  	getSourceConfig
    46  	getSourceDiff
    47  	getSourceSet
    48  	getSourceExact
    49  	getSourceMax = getSourceSet
    50  )
    51  
    52  // getResult is the internal structure that is generated when a Get
    53  // is called that contains some extra data that might be used.
    54  type getResult struct {
    55  	Value          interface{}
    56  	ValueProcessed interface{}
    57  	Computed       bool
    58  	Exists         bool
    59  	Schema         *Schema
    60  }
    61  
    62  var getResultEmpty getResult
    63  
    64  // Get returns the data for the given key, or nil if the key doesn't exist
    65  // in the schema.
    66  //
    67  // If the key does exist in the schema but doesn't exist in the configuration,
    68  // then the default value for that type will be returned. For strings, this is
    69  // "", for numbers it is 0, etc.
    70  //
    71  // If you want to test if something is set at all in the configuration,
    72  // use GetOk.
    73  func (d *ResourceData) Get(key string) interface{} {
    74  	v, _ := d.GetOk(key)
    75  	return v
    76  }
    77  
    78  // GetChange returns the old and new value for a given key.
    79  //
    80  // HasChange should be used to check if a change exists. It is possible
    81  // that both the old and new value are the same if the old value was not
    82  // set and the new value is. This is common, for example, for boolean
    83  // fields which have a zero value of false.
    84  func (d *ResourceData) GetChange(key string) (interface{}, interface{}) {
    85  	o, n := d.getChange(key, getSourceConfig, getSourceDiff)
    86  	return o.Value, n.Value
    87  }
    88  
    89  // GetOk returns the data for the given key and whether or not the key
    90  // existed or not in the configuration. The second boolean result will also
    91  // be false if a key is given that isn't in the schema at all.
    92  //
    93  // The first result will not necessarilly be nil if the value doesn't exist.
    94  // The second result should be checked to determine this information.
    95  func (d *ResourceData) GetOk(key string) (interface{}, bool) {
    96  	r := d.getRaw(key, getSourceSet)
    97  	return r.Value, r.Exists
    98  }
    99  
   100  func (d *ResourceData) getRaw(key string, level getSource) getResult {
   101  	var parts []string
   102  	if key != "" {
   103  		parts = strings.Split(key, ".")
   104  	}
   105  
   106  	return d.getObject("", parts, d.schema, level)
   107  }
   108  
   109  // HasChange returns whether or not the given key has been changed.
   110  func (d *ResourceData) HasChange(key string) bool {
   111  	o, n := d.GetChange(key)
   112  	return !reflect.DeepEqual(o, n)
   113  }
   114  
   115  // Partial turns partial state mode on/off.
   116  //
   117  // When partial state mode is enabled, then only key prefixes specified
   118  // by SetPartial will be in the final state. This allows providers to return
   119  // partial states for partially applied resources (when errors occur).
   120  func (d *ResourceData) Partial(on bool) {
   121  	d.partial = on
   122  	if on {
   123  		if d.partialMap == nil {
   124  			d.partialMap = make(map[string]struct{})
   125  		}
   126  	} else {
   127  		d.partialMap = nil
   128  	}
   129  }
   130  
   131  // Set sets the value for the given key.
   132  //
   133  // If the key is invalid or the value is not a correct type, an error
   134  // will be returned.
   135  func (d *ResourceData) Set(key string, value interface{}) error {
   136  	if d.setMap == nil {
   137  		d.setMap = make(map[string]string)
   138  	}
   139  
   140  	parts := strings.Split(key, ".")
   141  	return d.setObject("", parts, d.schema, value)
   142  }
   143  
   144  // SetPartial adds the key prefix to the final state output while
   145  // in partial state mode.
   146  //
   147  // If partial state mode is disabled, then this has no effect. Additionally,
   148  // whenever partial state mode is toggled, the partial data is cleared.
   149  func (d *ResourceData) SetPartial(k string) {
   150  	if d.partial {
   151  		d.partialMap[k] = struct{}{}
   152  	}
   153  }
   154  
   155  // Id returns the ID of the resource.
   156  func (d *ResourceData) Id() string {
   157  	var result string
   158  
   159  	if d.state != nil {
   160  		result = d.state.ID
   161  	}
   162  
   163  	if d.newState != nil {
   164  		result = d.newState.ID
   165  	}
   166  
   167  	return result
   168  }
   169  
   170  // ConnInfo returns the connection info for this resource.
   171  func (d *ResourceData) ConnInfo() map[string]string {
   172  	if d.newState != nil {
   173  		return d.newState.Ephemeral.ConnInfo
   174  	}
   175  
   176  	if d.state != nil {
   177  		return d.state.Ephemeral.ConnInfo
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  // SetId sets the ID of the resource. If the value is blank, then the
   184  // resource is destroyed.
   185  func (d *ResourceData) SetId(v string) {
   186  	d.once.Do(d.init)
   187  	d.newState.ID = v
   188  }
   189  
   190  // SetConnInfo sets the connection info for a resource.
   191  func (d *ResourceData) SetConnInfo(v map[string]string) {
   192  	d.once.Do(d.init)
   193  	d.newState.Ephemeral.ConnInfo = v
   194  }
   195  
   196  // State returns the new InstanceState after the diff and any Set
   197  // calls.
   198  func (d *ResourceData) State() *terraform.InstanceState {
   199  	var result terraform.InstanceState
   200  	result.ID = d.Id()
   201  
   202  	// If we have no ID, then this resource doesn't exist and we just
   203  	// return nil.
   204  	if result.ID == "" {
   205  		return nil
   206  	}
   207  
   208  	result.Attributes = d.stateObject("", d.schema)
   209  	result.Ephemeral.ConnInfo = d.ConnInfo()
   210  
   211  	if v := d.Id(); v != "" {
   212  		result.Attributes["id"] = d.Id()
   213  	}
   214  
   215  	return &result
   216  }
   217  
   218  func (d *ResourceData) init() {
   219  	var copyState terraform.InstanceState
   220  	if d.state != nil {
   221  		copyState = *d.state
   222  	}
   223  
   224  	d.newState = &copyState
   225  }
   226  
   227  func (d *ResourceData) diffChange(
   228  	k string) (interface{}, interface{}, bool, bool) {
   229  	// Get the change between the state and the config.
   230  	o, n := d.getChange(k, getSourceState, getSourceConfig|getSourceExact)
   231  	if !o.Exists {
   232  		o.Value = nil
   233  	}
   234  	if !n.Exists {
   235  		n.Value = nil
   236  	}
   237  
   238  	// Return the old, new, and whether there is a change
   239  	return o.Value, n.Value, !reflect.DeepEqual(o.Value, n.Value), n.Computed
   240  }
   241  
   242  func (d *ResourceData) getChange(
   243  	key string,
   244  	oldLevel getSource,
   245  	newLevel getSource) (getResult, getResult) {
   246  	var parts, parts2 []string
   247  	if key != "" {
   248  		parts = strings.Split(key, ".")
   249  		parts2 = strings.Split(key, ".")
   250  	}
   251  
   252  	o := d.getObject("", parts, d.schema, oldLevel)
   253  	n := d.getObject("", parts2, d.schema, newLevel)
   254  	return o, n
   255  }
   256  
   257  func (d *ResourceData) get(
   258  	k string,
   259  	parts []string,
   260  	schema *Schema,
   261  	source getSource) getResult {
   262  	switch schema.Type {
   263  	case TypeList:
   264  		return d.getList(k, parts, schema, source)
   265  	case TypeMap:
   266  		return d.getMap(k, parts, schema, source)
   267  	case TypeSet:
   268  		return d.getSet(k, parts, schema, source)
   269  	case TypeBool:
   270  		fallthrough
   271  	case TypeInt:
   272  		fallthrough
   273  	case TypeString:
   274  		return d.getPrimitive(k, parts, schema, source)
   275  	default:
   276  		panic(fmt.Sprintf("%s: unknown type %#v", k, schema.Type))
   277  	}
   278  }
   279  
   280  func (d *ResourceData) getSet(
   281  	k string,
   282  	parts []string,
   283  	schema *Schema,
   284  	source getSource) getResult {
   285  	s := &Set{F: schema.Set}
   286  	result := getResult{Schema: schema, Value: s}
   287  
   288  	// Get the list. For sets, the entire source must be exact: the
   289  	// entire set must come from set, diff, state, etc. So we go backwards
   290  	// and once we get a result, we take it. Or, we never get a result.
   291  	var raw getResult
   292  	for listSource := source; listSource > 0; listSource >>= 1 {
   293  		if source&getSourceExact != 0 && listSource != source {
   294  			break
   295  		}
   296  
   297  		raw = d.getList(k, nil, schema, listSource|getSourceExact)
   298  		if raw.Exists {
   299  			break
   300  		}
   301  	}
   302  	if !raw.Exists {
   303  		if len(parts) > 0 {
   304  			return d.getList(k, parts, schema, source)
   305  		}
   306  
   307  		return result
   308  	}
   309  
   310  	// If the entire list is computed, then the entire set is
   311  	// necessarilly computed.
   312  	if raw.Computed {
   313  		result.Computed = true
   314  		return result
   315  	}
   316  
   317  	list := raw.Value.([]interface{})
   318  	if len(list) == 0 {
   319  		if len(parts) > 0 {
   320  			return d.getList(k, parts, schema, source)
   321  		}
   322  
   323  		result.Exists = raw.Exists
   324  		return result
   325  	}
   326  
   327  	// This is a reverse map of hash code => index in config used to
   328  	// resolve direct set item lookup for turning into state. Confused?
   329  	// Read on...
   330  	//
   331  	// To create the state (the state* functions), a Get call is done
   332  	// with a full key such as "ports.0". The index of a set ("0") doesn't
   333  	// make a lot of sense, but we need to deterministically list out
   334  	// elements of the set like this. Luckily, same sets have a deterministic
   335  	// List() output, so we can use that to look things up.
   336  	//
   337  	// This mapping makes it so that we can look up the hash code of an
   338  	// object back to its index in the REAL config.
   339  	var indexMap map[int]int
   340  	if len(parts) > 0 {
   341  		indexMap = make(map[int]int)
   342  	}
   343  
   344  	// Build the set from all the items using the given hash code
   345  	for i, v := range list {
   346  		code := s.add(v)
   347  		if indexMap != nil {
   348  			indexMap[code] = i
   349  		}
   350  	}
   351  
   352  	// If we're trying to get a specific element, then rewrite the
   353  	// index to be just that, then jump direct to getList.
   354  	if len(parts) > 0 {
   355  		index := parts[0]
   356  		indexInt, err := strconv.ParseInt(index, 0, 0)
   357  		if err != nil {
   358  			return getResultEmpty
   359  		}
   360  
   361  		codes := s.listCode()
   362  		if int(indexInt) >= len(codes) {
   363  			return getResultEmpty
   364  		}
   365  		code := codes[indexInt]
   366  		realIndex := indexMap[code]
   367  
   368  		parts[0] = strconv.FormatInt(int64(realIndex), 10)
   369  		return d.getList(k, parts, schema, source)
   370  	}
   371  
   372  	result.Exists = true
   373  	return result
   374  }
   375  
   376  func (d *ResourceData) getMap(
   377  	k string,
   378  	parts []string,
   379  	schema *Schema,
   380  	source getSource) getResult {
   381  	elemSchema := &Schema{Type: TypeString}
   382  
   383  	result := make(map[string]interface{})
   384  	resultSet := false
   385  	prefix := k + "."
   386  
   387  	exact := source&getSourceExact != 0
   388  	source &^= getSourceExact
   389  
   390  	if !exact || source == getSourceState {
   391  		if d.state != nil && source >= getSourceState {
   392  			for k, _ := range d.state.Attributes {
   393  				if !strings.HasPrefix(k, prefix) {
   394  					continue
   395  				}
   396  
   397  				single := k[len(prefix):]
   398  				result[single] = d.getPrimitive(k, nil, elemSchema, source).Value
   399  				resultSet = true
   400  			}
   401  		}
   402  	}
   403  
   404  	if d.config != nil && source == getSourceConfig {
   405  		// For config, we always set the result to exactly what was requested
   406  		if mraw, ok := d.config.Get(k); ok {
   407  			result = make(map[string]interface{})
   408  			switch m := mraw.(type) {
   409  			case []interface{}:
   410  				for _, innerRaw := range m {
   411  					for k, v := range innerRaw.(map[string]interface{}) {
   412  						result[k] = v
   413  					}
   414  				}
   415  
   416  				resultSet = true
   417  			case []map[string]interface{}:
   418  				for _, innerRaw := range m {
   419  					for k, v := range innerRaw {
   420  						result[k] = v
   421  					}
   422  				}
   423  
   424  				resultSet = true
   425  			case map[string]interface{}:
   426  				result = m
   427  				resultSet = true
   428  			default:
   429  				panic(fmt.Sprintf("unknown type: %#v", mraw))
   430  			}
   431  		} else {
   432  			result = nil
   433  		}
   434  	}
   435  
   436  	if !exact || source == getSourceDiff {
   437  		if d.diff != nil && source >= getSourceDiff {
   438  			for k, v := range d.diff.Attributes {
   439  				if !strings.HasPrefix(k, prefix) {
   440  					continue
   441  				}
   442  				resultSet = true
   443  
   444  				single := k[len(prefix):]
   445  
   446  				if v.NewRemoved {
   447  					delete(result, single)
   448  				} else {
   449  					result[single] = d.getPrimitive(k, nil, elemSchema, source).Value
   450  				}
   451  			}
   452  		}
   453  	}
   454  
   455  	if !exact || source == getSourceSet {
   456  		if d.setMap != nil && source >= getSourceSet {
   457  			cleared := false
   458  			for k, _ := range d.setMap {
   459  				if !strings.HasPrefix(k, prefix) {
   460  					continue
   461  				}
   462  				resultSet = true
   463  
   464  				if !cleared {
   465  					// We clear the results if they are in the set map
   466  					result = make(map[string]interface{})
   467  					cleared = true
   468  				}
   469  
   470  				single := k[len(prefix):]
   471  				result[single] = d.getPrimitive(k, nil, elemSchema, source).Value
   472  			}
   473  		}
   474  	}
   475  
   476  	// If we're requesting a specific element, return that
   477  	var resultValue interface{} = result
   478  	if len(parts) > 0 {
   479  		resultValue = result[parts[0]]
   480  	}
   481  
   482  	return getResult{
   483  		Value:  resultValue,
   484  		Exists: resultSet,
   485  		Schema: schema,
   486  	}
   487  }
   488  
   489  func (d *ResourceData) getObject(
   490  	k string,
   491  	parts []string,
   492  	schema map[string]*Schema,
   493  	source getSource) getResult {
   494  	if len(parts) > 0 {
   495  		// We're requesting a specific key in an object
   496  		key := parts[0]
   497  		parts = parts[1:]
   498  		s, ok := schema[key]
   499  		if !ok {
   500  			return getResultEmpty
   501  		}
   502  
   503  		if k != "" {
   504  			// If we're not at the root, then we need to append
   505  			// the key to get the full key path.
   506  			key = fmt.Sprintf("%s.%s", k, key)
   507  		}
   508  
   509  		return d.get(key, parts, s, source)
   510  	}
   511  
   512  	// Get the entire object
   513  	result := make(map[string]interface{})
   514  	for field, _ := range schema {
   515  		result[field] = d.getObject(k, []string{field}, schema, source).Value
   516  	}
   517  
   518  	return getResult{
   519  		Value:  result,
   520  		Exists: true,
   521  		Schema: &Schema{
   522  			Elem: schema,
   523  		},
   524  	}
   525  }
   526  
   527  func (d *ResourceData) getList(
   528  	k string,
   529  	parts []string,
   530  	schema *Schema,
   531  	source getSource) getResult {
   532  	if len(parts) > 0 {
   533  		// We still have parts left over meaning we're accessing an
   534  		// element of this list.
   535  		idx := parts[0]
   536  		parts = parts[1:]
   537  
   538  		// Special case if we're accessing the count of the list
   539  		if idx == "#" {
   540  			schema := &Schema{Type: TypeInt}
   541  			return d.get(k+".#", parts, schema, source)
   542  		}
   543  
   544  		key := fmt.Sprintf("%s.%s", k, idx)
   545  		switch t := schema.Elem.(type) {
   546  		case *Resource:
   547  			return d.getObject(key, parts, t.Schema, source)
   548  		case *Schema:
   549  			return d.get(key, parts, t, source)
   550  		}
   551  	}
   552  
   553  	// Get the entire list.
   554  	var result []interface{}
   555  	count := d.getList(k, []string{"#"}, schema, source)
   556  	if !count.Computed {
   557  		result = make([]interface{}, count.Value.(int))
   558  		for i, _ := range result {
   559  			is := strconv.FormatInt(int64(i), 10)
   560  			result[i] = d.getList(k, []string{is}, schema, source).Value
   561  		}
   562  	}
   563  
   564  	return getResult{
   565  		Value:    result,
   566  		Computed: count.Computed,
   567  		Exists:   count.Exists,
   568  		Schema:   schema,
   569  	}
   570  }
   571  
   572  func (d *ResourceData) getPrimitive(
   573  	k string,
   574  	parts []string,
   575  	schema *Schema,
   576  	source getSource) getResult {
   577  	var result string
   578  	var resultProcessed interface{}
   579  	var resultComputed, resultSet bool
   580  	exact := source&getSourceExact != 0
   581  	source &^= getSourceExact
   582  
   583  	if !exact || source == getSourceState {
   584  		if d.state != nil && source >= getSourceState {
   585  			result, resultSet = d.state.Attributes[k]
   586  		}
   587  	}
   588  
   589  	// No exact check is needed here because config is always exact
   590  	if d.config != nil && source == getSourceConfig {
   591  		// For config, we always return the exact value
   592  		if v, ok := d.config.Get(k); ok {
   593  			if err := mapstructure.WeakDecode(v, &result); err != nil {
   594  				panic(err)
   595  			}
   596  
   597  			resultSet = true
   598  		} else {
   599  			result = ""
   600  			resultSet = false
   601  		}
   602  
   603  		// If it is computed, set that.
   604  		resultComputed = d.config.IsComputed(k)
   605  	}
   606  
   607  	if !exact || source == getSourceDiff {
   608  		if d.diff != nil && source >= getSourceDiff {
   609  			attrD, ok := d.diff.Attributes[k]
   610  			if ok {
   611  				if !attrD.NewComputed {
   612  					result = attrD.New
   613  					if attrD.NewExtra != nil {
   614  						// If NewExtra != nil, then we have processed data as the New,
   615  						// so we store that but decode the unprocessed data into result
   616  						resultProcessed = result
   617  
   618  						err := mapstructure.WeakDecode(attrD.NewExtra, &result)
   619  						if err != nil {
   620  							panic(err)
   621  						}
   622  					}
   623  
   624  					resultSet = true
   625  				} else {
   626  					result = ""
   627  					resultSet = false
   628  				}
   629  			}
   630  		}
   631  	}
   632  
   633  	if !exact || source == getSourceSet {
   634  		if d.setMap != nil && source >= getSourceSet {
   635  			if v, ok := d.setMap[k]; ok {
   636  				result = v
   637  				resultSet = true
   638  			}
   639  		}
   640  	}
   641  
   642  	if !resultSet {
   643  		result = ""
   644  	}
   645  
   646  	var resultValue interface{}
   647  	switch schema.Type {
   648  	case TypeBool:
   649  		if result == "" {
   650  			resultValue = false
   651  			break
   652  		}
   653  
   654  		v, err := strconv.ParseBool(result)
   655  		if err != nil {
   656  			panic(err)
   657  		}
   658  
   659  		resultValue = v
   660  	case TypeString:
   661  		// Use the value as-is. We just put this case here to be explicit.
   662  		resultValue = result
   663  	case TypeInt:
   664  		if result == "" {
   665  			resultValue = 0
   666  			break
   667  		}
   668  
   669  		if resultComputed {
   670  			break
   671  		}
   672  
   673  		v, err := strconv.ParseInt(result, 0, 0)
   674  		if err != nil {
   675  			panic(err)
   676  		}
   677  
   678  		resultValue = int(v)
   679  	default:
   680  		panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
   681  	}
   682  
   683  	return getResult{
   684  		Value:          resultValue,
   685  		ValueProcessed: resultProcessed,
   686  		Computed:       resultComputed,
   687  		Exists:         resultSet,
   688  		Schema:         schema,
   689  	}
   690  }
   691  
   692  func (d *ResourceData) set(
   693  	k string,
   694  	parts []string,
   695  	schema *Schema,
   696  	value interface{}) error {
   697  	switch schema.Type {
   698  	case TypeList:
   699  		return d.setList(k, parts, schema, value)
   700  	case TypeMap:
   701  		return d.setMapValue(k, parts, schema, value)
   702  	case TypeSet:
   703  		return d.setSet(k, parts, schema, value)
   704  	case TypeBool:
   705  		fallthrough
   706  	case TypeInt:
   707  		fallthrough
   708  	case TypeString:
   709  		return d.setPrimitive(k, schema, value)
   710  	default:
   711  		panic(fmt.Sprintf("%s: unknown type %#v", k, schema.Type))
   712  	}
   713  }
   714  
   715  func (d *ResourceData) setList(
   716  	k string,
   717  	parts []string,
   718  	schema *Schema,
   719  	value interface{}) error {
   720  	if len(parts) > 0 {
   721  		// We're setting a specific element
   722  		idx := parts[0]
   723  		parts = parts[1:]
   724  
   725  		// Special case if we're accessing the count of the list
   726  		if idx == "#" {
   727  			return fmt.Errorf("%s: can't set count of list", k)
   728  		}
   729  
   730  		key := fmt.Sprintf("%s.%s", k, idx)
   731  		switch t := schema.Elem.(type) {
   732  		case *Resource:
   733  			return d.setObject(key, parts, t.Schema, value)
   734  		case *Schema:
   735  			return d.set(key, parts, t, value)
   736  		}
   737  	}
   738  
   739  	var vs []interface{}
   740  	if err := mapstructure.Decode(value, &vs); err != nil {
   741  		return fmt.Errorf("%s: %s", k, err)
   742  	}
   743  
   744  	// Set the entire list.
   745  	var err error
   746  	for i, elem := range vs {
   747  		is := strconv.FormatInt(int64(i), 10)
   748  		err = d.setList(k, []string{is}, schema, elem)
   749  		if err != nil {
   750  			break
   751  		}
   752  	}
   753  	if err != nil {
   754  		for i, _ := range vs {
   755  			is := strconv.FormatInt(int64(i), 10)
   756  			d.setList(k, []string{is}, schema, nil)
   757  		}
   758  
   759  		return err
   760  	}
   761  
   762  	d.setMap[k+".#"] = strconv.FormatInt(int64(len(vs)), 10)
   763  	return nil
   764  }
   765  
   766  func (d *ResourceData) setMapValue(
   767  	k string,
   768  	parts []string,
   769  	schema *Schema,
   770  	value interface{}) error {
   771  	elemSchema := &Schema{Type: TypeString}
   772  	if len(parts) > 0 {
   773  		return fmt.Errorf("%s: full map must be set, no a single element", k)
   774  	}
   775  
   776  	// Delete any prior map set
   777  	/*
   778  		v := d.getMap(k, nil, schema, getSourceSet)
   779  		for subKey, _ := range v.(map[string]interface{}) {
   780  			delete(d.setMap, fmt.Sprintf("%s.%s", k, subKey))
   781  		}
   782  	*/
   783  
   784  	v := reflect.ValueOf(value)
   785  	if v.Kind() != reflect.Map {
   786  		return fmt.Errorf("%s: must be a map", k)
   787  	}
   788  	if v.Type().Key().Kind() != reflect.String {
   789  		return fmt.Errorf("%s: keys must strings", k)
   790  	}
   791  	vs := make(map[string]interface{})
   792  	for _, mk := range v.MapKeys() {
   793  		mv := v.MapIndex(mk)
   794  		vs[mk.String()] = mv.Interface()
   795  	}
   796  
   797  	for subKey, v := range vs {
   798  		err := d.set(fmt.Sprintf("%s.%s", k, subKey), nil, elemSchema, v)
   799  		if err != nil {
   800  			return err
   801  		}
   802  	}
   803  
   804  	return nil
   805  }
   806  
   807  func (d *ResourceData) setObject(
   808  	k string,
   809  	parts []string,
   810  	schema map[string]*Schema,
   811  	value interface{}) error {
   812  	if len(parts) > 0 {
   813  		// We're setting a specific key in an object
   814  		key := parts[0]
   815  		parts = parts[1:]
   816  
   817  		s, ok := schema[key]
   818  		if !ok {
   819  			return fmt.Errorf("%s (internal): unknown key to set: %s", k, key)
   820  		}
   821  
   822  		if k != "" {
   823  			// If we're not at the root, then we need to append
   824  			// the key to get the full key path.
   825  			key = fmt.Sprintf("%s.%s", k, key)
   826  		}
   827  
   828  		return d.set(key, parts, s, value)
   829  	}
   830  
   831  	// Set the entire object. First decode into a proper structure
   832  	var v map[string]interface{}
   833  	if err := mapstructure.Decode(value, &v); err != nil {
   834  		return fmt.Errorf("%s: %s", k, err)
   835  	}
   836  
   837  	// Set each element in turn
   838  	var err error
   839  	for k1, v1 := range v {
   840  		err = d.setObject(k, []string{k1}, schema, v1)
   841  		if err != nil {
   842  			break
   843  		}
   844  	}
   845  	if err != nil {
   846  		for k1, _ := range v {
   847  			d.setObject(k, []string{k1}, schema, nil)
   848  		}
   849  	}
   850  
   851  	return err
   852  }
   853  
   854  func (d *ResourceData) setPrimitive(
   855  	k string,
   856  	schema *Schema,
   857  	v interface{}) error {
   858  	if v == nil {
   859  		delete(d.setMap, k)
   860  		return nil
   861  	}
   862  
   863  	var set string
   864  	switch schema.Type {
   865  	case TypeBool:
   866  		var b bool
   867  		if err := mapstructure.Decode(v, &b); err != nil {
   868  			return fmt.Errorf("%s: %s", k, err)
   869  		}
   870  
   871  		set = strconv.FormatBool(b)
   872  	case TypeString:
   873  		if err := mapstructure.Decode(v, &set); err != nil {
   874  			return fmt.Errorf("%s: %s", k, err)
   875  		}
   876  	case TypeInt:
   877  		var n int
   878  		if err := mapstructure.Decode(v, &n); err != nil {
   879  			return fmt.Errorf("%s: %s", k, err)
   880  		}
   881  
   882  		set = strconv.FormatInt(int64(n), 10)
   883  	default:
   884  		return fmt.Errorf("Unknown type: %#v", schema.Type)
   885  	}
   886  
   887  	d.setMap[k] = set
   888  	return nil
   889  }
   890  
   891  func (d *ResourceData) setSet(
   892  	k string,
   893  	parts []string,
   894  	schema *Schema,
   895  	value interface{}) error {
   896  	if len(parts) > 0 {
   897  		return fmt.Errorf("%s: can only set the full set, not elements", k)
   898  	}
   899  
   900  	// If it is a slice, then we have to turn it into a *Set so that
   901  	// we get the proper order back based on the hash code.
   902  	if v := reflect.ValueOf(value); v.Kind() == reflect.Slice {
   903  		// Set the entire list, this lets us get sane values out of it
   904  		if err := d.setList(k, nil, schema, value); err != nil {
   905  			return err
   906  		}
   907  
   908  		// Build the set by going over the list items in order and
   909  		// hashing them into the set. The reason we go over the list and
   910  		// not the `value` directly is because this forces all types
   911  		// to become []interface{} (generic) instead of []string, which
   912  		// most hash functions are expecting.
   913  		s := &Set{F: schema.Set}
   914  		source := getSourceSet | getSourceExact
   915  		for i := 0; i < v.Len(); i++ {
   916  			is := strconv.FormatInt(int64(i), 10)
   917  			result := d.getList(k, []string{is}, schema, source)
   918  			if !result.Exists {
   919  				panic("just set item doesn't exist")
   920  			}
   921  
   922  			s.Add(result.Value)
   923  		}
   924  
   925  		value = s
   926  	}
   927  
   928  	if s, ok := value.(*Set); ok {
   929  		value = s.List()
   930  	}
   931  
   932  	return d.setList(k, nil, schema, value)
   933  }
   934  
   935  func (d *ResourceData) stateList(
   936  	prefix string,
   937  	schema *Schema) map[string]string {
   938  	countRaw := d.get(prefix, []string{"#"}, schema, d.stateSource(prefix))
   939  	if !countRaw.Exists {
   940  		if schema.Computed {
   941  			// If it is computed, then it always _exists_ in the state,
   942  			// it is just empty.
   943  			countRaw.Exists = true
   944  			countRaw.Value = 0
   945  		} else {
   946  			return nil
   947  		}
   948  	}
   949  	count := countRaw.Value.(int)
   950  
   951  	result := make(map[string]string)
   952  	if count > 0 || schema.Computed {
   953  		result[prefix+".#"] = strconv.FormatInt(int64(count), 10)
   954  	}
   955  	for i := 0; i < count; i++ {
   956  		key := fmt.Sprintf("%s.%d", prefix, i)
   957  
   958  		var m map[string]string
   959  		switch t := schema.Elem.(type) {
   960  		case *Resource:
   961  			m = d.stateObject(key, t.Schema)
   962  		case *Schema:
   963  			m = d.stateSingle(key, t)
   964  		}
   965  
   966  		for k, v := range m {
   967  			result[k] = v
   968  		}
   969  	}
   970  
   971  	return result
   972  }
   973  
   974  func (d *ResourceData) stateMap(
   975  	prefix string,
   976  	schema *Schema) map[string]string {
   977  	v := d.getMap(prefix, nil, schema, d.stateSource(prefix))
   978  	if !v.Exists {
   979  		return nil
   980  	}
   981  
   982  	elemSchema := &Schema{Type: TypeString}
   983  	result := make(map[string]string)
   984  	for mk, _ := range v.Value.(map[string]interface{}) {
   985  		mp := fmt.Sprintf("%s.%s", prefix, mk)
   986  		for k, v := range d.stateSingle(mp, elemSchema) {
   987  			result[k] = v
   988  		}
   989  	}
   990  
   991  	return result
   992  }
   993  
   994  func (d *ResourceData) stateObject(
   995  	prefix string,
   996  	schema map[string]*Schema) map[string]string {
   997  	result := make(map[string]string)
   998  	for k, v := range schema {
   999  		key := k
  1000  		if prefix != "" {
  1001  			key = prefix + "." + key
  1002  		}
  1003  
  1004  		for k1, v1 := range d.stateSingle(key, v) {
  1005  			result[k1] = v1
  1006  		}
  1007  	}
  1008  
  1009  	return result
  1010  }
  1011  
  1012  func (d *ResourceData) statePrimitive(
  1013  	prefix string,
  1014  	schema *Schema) map[string]string {
  1015  	raw := d.getRaw(prefix, d.stateSource(prefix))
  1016  	if !raw.Exists {
  1017  		return nil
  1018  	}
  1019  
  1020  	v := raw.Value
  1021  	if raw.ValueProcessed != nil {
  1022  		v = raw.ValueProcessed
  1023  	}
  1024  
  1025  	var vs string
  1026  	switch schema.Type {
  1027  	case TypeBool:
  1028  		vs = strconv.FormatBool(v.(bool))
  1029  	case TypeString:
  1030  		vs = v.(string)
  1031  	case TypeInt:
  1032  		vs = strconv.FormatInt(int64(v.(int)), 10)
  1033  	default:
  1034  		panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
  1035  	}
  1036  
  1037  	return map[string]string{
  1038  		prefix: vs,
  1039  	}
  1040  }
  1041  
  1042  func (d *ResourceData) stateSet(
  1043  	prefix string,
  1044  	schema *Schema) map[string]string {
  1045  	raw := d.get(prefix, nil, schema, d.stateSource(prefix))
  1046  	if !raw.Exists {
  1047  		if schema.Computed {
  1048  			// If it is computed, then it always _exists_ in the state,
  1049  			// it is just empty.
  1050  			raw.Exists = true
  1051  			raw.Value = new(Set)
  1052  		} else {
  1053  			return nil
  1054  		}
  1055  	}
  1056  
  1057  	set := raw.Value.(*Set)
  1058  	list := set.List()
  1059  	result := make(map[string]string)
  1060  	result[prefix+".#"] = strconv.FormatInt(int64(len(list)), 10)
  1061  	for i := 0; i < len(list); i++ {
  1062  		key := fmt.Sprintf("%s.%d", prefix, i)
  1063  
  1064  		var m map[string]string
  1065  		switch t := schema.Elem.(type) {
  1066  		case *Resource:
  1067  			m = d.stateObject(key, t.Schema)
  1068  		case *Schema:
  1069  			m = d.stateSingle(key, t)
  1070  		}
  1071  
  1072  		for k, v := range m {
  1073  			result[k] = v
  1074  		}
  1075  	}
  1076  
  1077  	return result
  1078  }
  1079  
  1080  func (d *ResourceData) stateSingle(
  1081  	prefix string,
  1082  	schema *Schema) map[string]string {
  1083  	switch schema.Type {
  1084  	case TypeList:
  1085  		return d.stateList(prefix, schema)
  1086  	case TypeMap:
  1087  		return d.stateMap(prefix, schema)
  1088  	case TypeSet:
  1089  		return d.stateSet(prefix, schema)
  1090  	case TypeBool:
  1091  		fallthrough
  1092  	case TypeInt:
  1093  		fallthrough
  1094  	case TypeString:
  1095  		return d.statePrimitive(prefix, schema)
  1096  	default:
  1097  		panic(fmt.Sprintf("%s: unknown type %#v", prefix, schema.Type))
  1098  	}
  1099  }
  1100  
  1101  func (d *ResourceData) stateSource(prefix string) getSource {
  1102  	// If we're not doing a partial apply, then get the set level
  1103  	if !d.partial {
  1104  		return getSourceSet
  1105  	}
  1106  
  1107  	// Otherwise, only return getSourceSet if its in the partial map.
  1108  	// Otherwise we use state level only.
  1109  	for k, _ := range d.partialMap {
  1110  		if strings.HasPrefix(prefix, k) {
  1111  			return getSourceSet
  1112  		}
  1113  	}
  1114  
  1115  	return getSourceState
  1116  }