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