github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/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 }