github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/terraform/eval_output.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/terraform/config"
     8  )
     9  
    10  // EvalDeleteOutput is an EvalNode implementation that deletes an output
    11  // from the state.
    12  type EvalDeleteOutput struct {
    13  	Name string
    14  }
    15  
    16  // TODO: test
    17  func (n *EvalDeleteOutput) Eval(ctx EvalContext) (interface{}, error) {
    18  	state, lock := ctx.State()
    19  	if state == nil {
    20  		return nil, nil
    21  	}
    22  
    23  	// Get a write lock so we can access this instance
    24  	lock.Lock()
    25  	defer lock.Unlock()
    26  
    27  	// Look for the module state. If we don't have one, create it.
    28  	mod := state.ModuleByPath(ctx.Path())
    29  	if mod == nil {
    30  		return nil, nil
    31  	}
    32  
    33  	delete(mod.Outputs, n.Name)
    34  
    35  	return nil, nil
    36  }
    37  
    38  // EvalWriteOutput is an EvalNode implementation that writes the output
    39  // for the given name to the current state.
    40  type EvalWriteOutput struct {
    41  	Name      string
    42  	Sensitive bool
    43  	Value     *config.RawConfig
    44  }
    45  
    46  // TODO: test
    47  func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
    48  	cfg, err := ctx.Interpolate(n.Value, nil)
    49  	if err != nil {
    50  		// Log error but continue anyway
    51  		log.Printf("[WARN] Output interpolation %q failed: %s", n.Name, err)
    52  	}
    53  
    54  	state, lock := ctx.State()
    55  	if state == nil {
    56  		return nil, fmt.Errorf("cannot write state to nil state")
    57  	}
    58  
    59  	// Get a write lock so we can access this instance
    60  	lock.Lock()
    61  	defer lock.Unlock()
    62  
    63  	// Look for the module state. If we don't have one, create it.
    64  	mod := state.ModuleByPath(ctx.Path())
    65  	if mod == nil {
    66  		mod = state.AddModule(ctx.Path())
    67  	}
    68  
    69  	// Get the value from the config
    70  	var valueRaw interface{} = config.UnknownVariableValue
    71  	if cfg != nil {
    72  		var ok bool
    73  		valueRaw, ok = cfg.Get("value")
    74  		if !ok {
    75  			valueRaw = ""
    76  		}
    77  		if cfg.IsComputed("value") {
    78  			valueRaw = config.UnknownVariableValue
    79  		}
    80  	}
    81  
    82  	switch valueTyped := valueRaw.(type) {
    83  	case string:
    84  		mod.Outputs[n.Name] = &OutputState{
    85  			Type:      "string",
    86  			Sensitive: n.Sensitive,
    87  			Value:     valueTyped,
    88  		}
    89  	case []interface{}:
    90  		mod.Outputs[n.Name] = &OutputState{
    91  			Type:      "list",
    92  			Sensitive: n.Sensitive,
    93  			Value:     valueTyped,
    94  		}
    95  	case map[string]interface{}:
    96  		mod.Outputs[n.Name] = &OutputState{
    97  			Type:      "map",
    98  			Sensitive: n.Sensitive,
    99  			Value:     valueTyped,
   100  		}
   101  	case []map[string]interface{}:
   102  		// an HCL map is multi-valued, so if this was read out of a config the
   103  		// map may still be in a slice.
   104  		if len(valueTyped) == 1 {
   105  			mod.Outputs[n.Name] = &OutputState{
   106  				Type:      "map",
   107  				Sensitive: n.Sensitive,
   108  				Value:     valueTyped[0],
   109  			}
   110  			break
   111  		}
   112  		return nil, fmt.Errorf("output %s type (%T) with %d values not valid for type map",
   113  			n.Name, valueTyped, len(valueTyped))
   114  	default:
   115  		return nil, fmt.Errorf("output %s is not a valid type (%T)\n", n.Name, valueTyped)
   116  	}
   117  
   118  	return nil, nil
   119  }