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() {}