github.com/hashicorp/packer@v1.14.3/hcl2template/types.refstring.go (about) 1 package hcl2template 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/hcl/v2" 8 ) 9 10 // A refstring is any reference string that can point to a component of a config 11 // 12 // This includes anything in the following format: 13 // 14 // * data.<type>.<name> 15 // * var.<name> 16 // * local.<name> 17 type refString struct { 18 // RefMType is the top-level label, that is used to know which type of 19 // component we are to look for (i.e. data for Datasource, local for 20 // Locals, etc.) 21 MType string 22 // RefType is the type of component, as in the name of the plugin that 23 // will handle evaluation for the component. 24 // 25 // Only for Datasources now as var/local do not have a component type 26 // (they're always evaluated by Packer itself, not a plugin). 27 Type string 28 // RefName is the name of the component to get. 29 // For locals/vars this is the name of the variable to look for, while 30 // for datasources this is the name of the block, which coupled with the 31 // type is the identity of the datasource's execution. 32 Name string 33 } 34 35 func NewRefStringFromDep(t hcl.Traversal) (refString, error) { 36 root := t.RootName() 37 38 switch root { 39 case "local", "var": 40 return NewRefString(fmt.Sprintf("%s.%s", root, t[1].(hcl.TraverseAttr).Name)) 41 case "data": 42 return NewRefString(fmt.Sprintf("%s.%s.%s", root, 43 t[1].(hcl.TraverseAttr).Name, 44 t[2].(hcl.TraverseAttr).Name)) 45 } 46 47 return refString{}, fmt.Errorf("unsupported refstring %q, must be of 'data', 'local' or 'var' type", t) 48 } 49 50 func NewRefString(rs string) (refString, error) { 51 parts := strings.Split(rs, ".") 52 53 switch parts[0] { 54 case "local", "var": 55 return refString{ 56 MType: parts[0], 57 Name: parts[1], 58 }, nil 59 case "data": 60 return newDataSourceRefString(parts) 61 } 62 63 return refString{}, fmt.Errorf("unsupported reftype %q, must be either 'data', 'local' or 'var'", parts[0]) 64 } 65 66 func (rs refString) String() string { 67 if rs.Type == "" { 68 return fmt.Sprintf("%s.%s", rs.MType, rs.Name) 69 } 70 71 return fmt.Sprintf("%s.%s.%s", rs.MType, rs.Type, rs.Name) 72 } 73 74 func newDataSourceRefString(parts []string) (refString, error) { 75 if len(parts) != 3 { 76 return refString{}, fmt.Errorf("malformed datasource reference %q, data sources must be composed of 3 parts", 77 strings.Join(parts, ".")) 78 } 79 80 return refString{ 81 MType: "data", 82 Type: parts[1], 83 Name: parts[2], 84 }, nil 85 } 86 87 // getComponentByRef gets a registered component from the configuration from a refString 88 func (cfg *PackerConfig) getComponentByRef(rs refString) (interface{}, error) { 89 switch rs.MType { 90 case "data": 91 for _, ds := range cfg.Datasources { 92 if ds.Type != rs.Type { 93 continue 94 } 95 if ds.DSName != rs.Name { 96 continue 97 } 98 return ds, nil 99 } 100 return nil, fmt.Errorf("failed to get datasource '%s.%s': component unknown", rs.Type, rs.Name) 101 case "local": 102 for _, loc := range cfg.LocalBlocks { 103 if loc.LocalName != rs.Name { 104 continue 105 } 106 return loc, nil 107 } 108 case "var": 109 for _, val := range cfg.InputVariables { 110 if val.Name != rs.Name { 111 continue 112 } 113 return val, nil 114 } 115 } 116 117 return nil, fmt.Errorf("Unsupported component: %q, only vars, locals and datasources can be fetched by their refString", rs) 118 } 119 120 func (ds *DatasourceBlock) RegisterDependency(rs refString) error { 121 switch rs.MType { 122 case "data", "local": 123 ds.Dependencies = append(ds.Dependencies, rs) 124 // NOOP: vars are always evaluated beforehand for datasources 125 case "var": 126 default: 127 return fmt.Errorf("unsupported dependency type %q; datasources can only depend on local, var or data.", rs.MType) 128 } 129 130 return nil 131 } 132 133 func (loc *LocalBlock) RegisterDependency(rs refString) error { 134 switch rs.MType { 135 case "data", "local": 136 loc.dependencies = append(loc.dependencies, rs) 137 // NOOP: vars are always evaluated beforehand for locals 138 case "var": 139 default: 140 return fmt.Errorf("unsupported dependency type %q; locals can only depend on local, var or data.", rs.MType) 141 } 142 143 return nil 144 }