github.com/pulumi/terraform@v1.4.0/pkg/addrs/output_value.go (about) 1 package addrs 2 3 import ( 4 "fmt" 5 6 "github.com/hashicorp/hcl/v2" 7 "github.com/hashicorp/hcl/v2/hclsyntax" 8 "github.com/pulumi/terraform/pkg/tfdiags" 9 ) 10 11 // OutputValue is the address of an output value, in the context of the module 12 // that is defining it. 13 // 14 // This is related to but separate from ModuleCallOutput, which represents 15 // a module output from the perspective of its parent module. Since output 16 // values cannot be represented from the module where they are defined, 17 // OutputValue is not Referenceable, while ModuleCallOutput is. 18 type OutputValue struct { 19 Name string 20 } 21 22 func (v OutputValue) String() string { 23 return "output." + v.Name 24 } 25 26 // Absolute converts the receiver into an absolute address within the given 27 // module instance. 28 func (v OutputValue) Absolute(m ModuleInstance) AbsOutputValue { 29 return AbsOutputValue{ 30 Module: m, 31 OutputValue: v, 32 } 33 } 34 35 // InModule converts the receiver into a config address within the given 36 // module. 37 func (v OutputValue) InModule(m Module) ConfigOutputValue { 38 return ConfigOutputValue{ 39 Module: m, 40 OutputValue: v, 41 } 42 } 43 44 // AbsOutputValue is the absolute address of an output value within a module instance. 45 // 46 // This represents an output globally within the namespace of a particular 47 // configuration. It is related to but separate from ModuleCallOutput, which 48 // represents a module output from the perspective of its parent module. 49 type AbsOutputValue struct { 50 Module ModuleInstance 51 OutputValue OutputValue 52 } 53 54 // OutputValue returns the absolute address of an output value of the given 55 // name within the receiving module instance. 56 func (m ModuleInstance) OutputValue(name string) AbsOutputValue { 57 return AbsOutputValue{ 58 Module: m, 59 OutputValue: OutputValue{ 60 Name: name, 61 }, 62 } 63 } 64 65 func (v AbsOutputValue) Check(t CheckType, i int) Check { 66 return Check{ 67 Container: v, 68 Type: t, 69 Index: i, 70 } 71 } 72 73 func (v AbsOutputValue) String() string { 74 if v.Module.IsRoot() { 75 return v.OutputValue.String() 76 } 77 return fmt.Sprintf("%s.%s", v.Module.String(), v.OutputValue.String()) 78 } 79 80 func (v AbsOutputValue) Equal(o AbsOutputValue) bool { 81 return v.OutputValue == o.OutputValue && v.Module.Equal(o.Module) 82 } 83 84 func (v AbsOutputValue) ConfigOutputValue() ConfigOutputValue { 85 return ConfigOutputValue{ 86 Module: v.Module.Module(), 87 OutputValue: v.OutputValue, 88 } 89 } 90 91 func (v AbsOutputValue) checkableSigil() { 92 // Output values are checkable 93 } 94 95 func (v AbsOutputValue) ConfigCheckable() ConfigCheckable { 96 // Output values are declared by "output" blocks in the configuration, 97 // represented as ConfigOutputValue. 98 return v.ConfigOutputValue() 99 } 100 101 func (v AbsOutputValue) CheckableKind() CheckableKind { 102 return CheckableOutputValue 103 } 104 105 func (v AbsOutputValue) UniqueKey() UniqueKey { 106 return absOutputValueUniqueKey(v.String()) 107 } 108 109 type absOutputValueUniqueKey string 110 111 func (k absOutputValueUniqueKey) uniqueKeySigil() {} 112 113 func ParseAbsOutputValue(traversal hcl.Traversal) (AbsOutputValue, tfdiags.Diagnostics) { 114 path, remain, diags := parseModuleInstancePrefix(traversal) 115 if diags.HasErrors() { 116 return AbsOutputValue{}, diags 117 } 118 119 if len(remain) != 2 { 120 diags = diags.Append(&hcl.Diagnostic{ 121 Severity: hcl.DiagError, 122 Summary: "Invalid address", 123 Detail: "An output name is required.", 124 Subject: traversal.SourceRange().Ptr(), 125 }) 126 return AbsOutputValue{}, diags 127 } 128 129 if remain.RootName() != "output" { 130 diags = diags.Append(&hcl.Diagnostic{ 131 Severity: hcl.DiagError, 132 Summary: "Invalid address", 133 Detail: "Output address must start with \"output.\".", 134 Subject: remain[0].SourceRange().Ptr(), 135 }) 136 return AbsOutputValue{}, diags 137 } 138 139 var name string 140 switch tt := remain[1].(type) { 141 case hcl.TraverseAttr: 142 name = tt.Name 143 default: 144 diags = diags.Append(&hcl.Diagnostic{ 145 Severity: hcl.DiagError, 146 Summary: "Invalid address", 147 Detail: "An output name is required.", 148 Subject: remain[1].SourceRange().Ptr(), 149 }) 150 return AbsOutputValue{}, diags 151 } 152 153 return AbsOutputValue{ 154 Module: path, 155 OutputValue: OutputValue{ 156 Name: name, 157 }, 158 }, diags 159 } 160 161 func ParseAbsOutputValueStr(str string) (AbsOutputValue, tfdiags.Diagnostics) { 162 var diags tfdiags.Diagnostics 163 164 traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1}) 165 diags = diags.Append(parseDiags) 166 if parseDiags.HasErrors() { 167 return AbsOutputValue{}, diags 168 } 169 170 addr, addrDiags := ParseAbsOutputValue(traversal) 171 diags = diags.Append(addrDiags) 172 return addr, diags 173 } 174 175 // ModuleCallOutput converts an AbsModuleOutput into a ModuleCallOutput, 176 // returning also the module instance that the ModuleCallOutput is relative 177 // to. 178 // 179 // The root module does not have a call, and so this method cannot be used 180 // with outputs in the root module, and will panic in that case. 181 func (v AbsOutputValue) ModuleCallOutput() (ModuleInstance, ModuleCallInstanceOutput) { 182 if v.Module.IsRoot() { 183 panic("ReferenceFromCall used with root module output") 184 } 185 186 caller, call := v.Module.CallInstance() 187 return caller, ModuleCallInstanceOutput{ 188 Call: call, 189 Name: v.OutputValue.Name, 190 } 191 } 192 193 // ConfigOutputValue represents a particular "output" block in the 194 // configuration, which might have many AbsOutputValue addresses associated 195 // with it at runtime if it belongs to a module that was called using 196 // "count" or "for_each". 197 type ConfigOutputValue struct { 198 Module Module 199 OutputValue OutputValue 200 } 201 202 func (v ConfigOutputValue) String() string { 203 if v.Module.IsRoot() { 204 return v.OutputValue.String() 205 } 206 return fmt.Sprintf("%s.%s", v.Module.String(), v.OutputValue.String()) 207 } 208 209 func (v ConfigOutputValue) configCheckableSigil() { 210 // ConfigOutputValue is the ConfigCheckable for AbsOutputValue. 211 } 212 213 func (v ConfigOutputValue) CheckableKind() CheckableKind { 214 return CheckableOutputValue 215 } 216 217 func (v ConfigOutputValue) UniqueKey() UniqueKey { 218 return configOutputValueUniqueKey(v.String()) 219 } 220 221 type configOutputValueUniqueKey string 222 223 func (k configOutputValueUniqueKey) uniqueKeySigil() {}