github.com/magodo/terraform@v0.11.12-beta1/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  	// ContinueOnErr allows interpolation to fail during Input
    45  	ContinueOnErr bool
    46  }
    47  
    48  // TODO: test
    49  func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
    50  	// This has to run before we have a state lock, since interpolation also
    51  	// reads the state
    52  	cfg, err := ctx.Interpolate(n.Value, nil)
    53  	// handle the error after we have the module from the state
    54  
    55  	state, lock := ctx.State()
    56  	if state == nil {
    57  		return nil, fmt.Errorf("cannot write state to nil state")
    58  	}
    59  
    60  	// Get a write lock so we can access this instance
    61  	lock.Lock()
    62  	defer lock.Unlock()
    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  	// handling the interpolation error
    70  	if err != nil {
    71  		if n.ContinueOnErr || flagWarnOutputErrors {
    72  			log.Printf("[ERROR] Output interpolation %q failed: %s", n.Name, err)
    73  			// if we're continuing, make sure the output is included, and
    74  			// marked as unknown
    75  			mod.Outputs[n.Name] = &OutputState{
    76  				Type:  "string",
    77  				Value: config.UnknownVariableValue,
    78  			}
    79  			return nil, EvalEarlyExitError{}
    80  		}
    81  		return nil, err
    82  	}
    83  
    84  	// Get the value from the config
    85  	var valueRaw interface{} = config.UnknownVariableValue
    86  	if cfg != nil {
    87  		var ok bool
    88  		valueRaw, ok = cfg.Get("value")
    89  		if !ok {
    90  			valueRaw = ""
    91  		}
    92  		if cfg.IsComputed("value") {
    93  			valueRaw = config.UnknownVariableValue
    94  		}
    95  	}
    96  
    97  	switch valueTyped := valueRaw.(type) {
    98  	case string:
    99  		mod.Outputs[n.Name] = &OutputState{
   100  			Type:      "string",
   101  			Sensitive: n.Sensitive,
   102  			Value:     valueTyped,
   103  		}
   104  	case []interface{}:
   105  		mod.Outputs[n.Name] = &OutputState{
   106  			Type:      "list",
   107  			Sensitive: n.Sensitive,
   108  			Value:     valueTyped,
   109  		}
   110  	case map[string]interface{}:
   111  		mod.Outputs[n.Name] = &OutputState{
   112  			Type:      "map",
   113  			Sensitive: n.Sensitive,
   114  			Value:     valueTyped,
   115  		}
   116  	case []map[string]interface{}:
   117  		// an HCL map is multi-valued, so if this was read out of a config the
   118  		// map may still be in a slice.
   119  		if len(valueTyped) == 1 {
   120  			mod.Outputs[n.Name] = &OutputState{
   121  				Type:      "map",
   122  				Sensitive: n.Sensitive,
   123  				Value:     valueTyped[0],
   124  			}
   125  			break
   126  		}
   127  		return nil, fmt.Errorf("output %s type (%T) with %d values not valid for type map",
   128  			n.Name, valueTyped, len(valueTyped))
   129  	default:
   130  		return nil, fmt.Errorf("output %s is not a valid type (%T)\n", n.Name, valueTyped)
   131  	}
   132  
   133  	return nil, nil
   134  }