github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/addrs/resource.go (about) 1 package addrs 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // Resource is an address for a resource block within configuration, which 9 // contains potentially-multiple resource instances if that configuration 10 // block uses "count" or "for_each". 11 type Resource struct { 12 referenceable 13 Mode ResourceMode 14 Type string 15 Name string 16 } 17 18 func (r Resource) String() string { 19 switch r.Mode { 20 case ManagedResourceMode: 21 return fmt.Sprintf("%s.%s", r.Type, r.Name) 22 case DataResourceMode: 23 return fmt.Sprintf("data.%s.%s", r.Type, r.Name) 24 default: 25 // Should never happen, but we'll return a string here rather than 26 // crashing just in case it does. 27 return fmt.Sprintf("<invalid>.%s.%s", r.Type, r.Name) 28 } 29 } 30 31 func (r Resource) Equal(o Resource) bool { 32 return r.Mode == o.Mode && r.Name == o.Name && r.Type == o.Type 33 } 34 35 func (r Resource) UniqueKey() UniqueKey { 36 return r // A Resource is its own UniqueKey 37 } 38 39 func (r Resource) uniqueKeySigil() {} 40 41 // Instance produces the address for a specific instance of the receiver 42 // that is idenfied by the given key. 43 func (r Resource) Instance(key InstanceKey) ResourceInstance { 44 return ResourceInstance{ 45 Resource: r, 46 Key: key, 47 } 48 } 49 50 // Absolute returns an AbsResource from the receiver and the given module 51 // instance address. 52 func (r Resource) Absolute(module ModuleInstance) AbsResource { 53 return AbsResource{ 54 Module: module, 55 Resource: r, 56 } 57 } 58 59 // InModule returns a ConfigResource from the receiver and the given module 60 // address. 61 func (r Resource) InModule(module Module) ConfigResource { 62 return ConfigResource{ 63 Module: module, 64 Resource: r, 65 } 66 } 67 68 // ImpliedProvider returns the implied provider type name, for e.g. the "aws" in 69 // "aws_instance" 70 func (r Resource) ImpliedProvider() string { 71 typeName := r.Type 72 if under := strings.Index(typeName, "_"); under != -1 { 73 typeName = typeName[:under] 74 } 75 76 return typeName 77 } 78 79 // ResourceInstance is an address for a specific instance of a resource. 80 // When a resource is defined in configuration with "count" or "for_each" it 81 // produces zero or more instances, which can be addressed using this type. 82 type ResourceInstance struct { 83 referenceable 84 Resource Resource 85 Key InstanceKey 86 } 87 88 func (r ResourceInstance) ContainingResource() Resource { 89 return r.Resource 90 } 91 92 func (r ResourceInstance) String() string { 93 if r.Key == NoKey { 94 return r.Resource.String() 95 } 96 return r.Resource.String() + r.Key.String() 97 } 98 99 func (r ResourceInstance) Equal(o ResourceInstance) bool { 100 return r.Key == o.Key && r.Resource.Equal(o.Resource) 101 } 102 103 func (r ResourceInstance) UniqueKey() UniqueKey { 104 return r // A ResourceInstance is its own UniqueKey 105 } 106 107 func (r ResourceInstance) uniqueKeySigil() {} 108 109 // Absolute returns an AbsResourceInstance from the receiver and the given module 110 // instance address. 111 func (r ResourceInstance) Absolute(module ModuleInstance) AbsResourceInstance { 112 return AbsResourceInstance{ 113 Module: module, 114 Resource: r, 115 } 116 } 117 118 // AbsResource is an absolute address for a resource under a given module path. 119 type AbsResource struct { 120 targetable 121 Module ModuleInstance 122 Resource Resource 123 } 124 125 // Resource returns the address of a particular resource within the receiver. 126 func (m ModuleInstance) Resource(mode ResourceMode, typeName string, name string) AbsResource { 127 return AbsResource{ 128 Module: m, 129 Resource: Resource{ 130 Mode: mode, 131 Type: typeName, 132 Name: name, 133 }, 134 } 135 } 136 137 // Instance produces the address for a specific instance of the receiver 138 // that is idenfied by the given key. 139 func (r AbsResource) Instance(key InstanceKey) AbsResourceInstance { 140 return AbsResourceInstance{ 141 Module: r.Module, 142 Resource: r.Resource.Instance(key), 143 } 144 } 145 146 // Config returns the unexpanded ConfigResource for this AbsResource. 147 func (r AbsResource) Config() ConfigResource { 148 return ConfigResource{ 149 Module: r.Module.Module(), 150 Resource: r.Resource, 151 } 152 } 153 154 // TargetContains implements Targetable by returning true if the given other 155 // address is either equal to the receiver or is an instance of the 156 // receiver. 157 func (r AbsResource) TargetContains(other Targetable) bool { 158 switch to := other.(type) { 159 160 case AbsResource: 161 // We'll use our stringification as a cheat-ish way to test for equality. 162 return to.String() == r.String() 163 164 case ConfigResource: 165 // if an absolute resource from parsing a target address contains a 166 // ConfigResource, the string representation will match 167 return to.String() == r.String() 168 169 case AbsResourceInstance: 170 return r.TargetContains(to.ContainingResource()) 171 172 default: 173 return false 174 175 } 176 } 177 178 func (r AbsResource) AddrType() TargetableAddrType { 179 return AbsResourceAddrType 180 } 181 182 func (r AbsResource) String() string { 183 if len(r.Module) == 0 { 184 return r.Resource.String() 185 } 186 return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) 187 } 188 189 // AffectedAbsResource returns the AbsResource. 190 func (r AbsResource) AffectedAbsResource() AbsResource { 191 return r 192 } 193 194 func (r AbsResource) Equal(o AbsResource) bool { 195 return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) 196 } 197 198 func (r AbsResource) absMoveableSigil() { 199 // AbsResource is moveable 200 } 201 202 type absResourceKey string 203 204 func (r absResourceKey) uniqueKeySigil() {} 205 206 func (r AbsResource) UniqueKey() UniqueKey { 207 return absResourceKey(r.String()) 208 } 209 210 // AbsResourceInstance is an absolute address for a resource instance under a 211 // given module path. 212 type AbsResourceInstance struct { 213 targetable 214 Module ModuleInstance 215 Resource ResourceInstance 216 } 217 218 // ResourceInstance returns the address of a particular resource instance within the receiver. 219 func (m ModuleInstance) ResourceInstance(mode ResourceMode, typeName string, name string, key InstanceKey) AbsResourceInstance { 220 return AbsResourceInstance{ 221 Module: m, 222 Resource: ResourceInstance{ 223 Resource: Resource{ 224 Mode: mode, 225 Type: typeName, 226 Name: name, 227 }, 228 Key: key, 229 }, 230 } 231 } 232 233 // ContainingResource returns the address of the resource that contains the 234 // receving resource instance. In other words, it discards the key portion 235 // of the address to produce an AbsResource value. 236 func (r AbsResourceInstance) ContainingResource() AbsResource { 237 return AbsResource{ 238 Module: r.Module, 239 Resource: r.Resource.ContainingResource(), 240 } 241 } 242 243 // TargetContains implements Targetable by returning true if the given other 244 // address is equal to the receiver. 245 func (r AbsResourceInstance) TargetContains(other Targetable) bool { 246 switch to := other.(type) { 247 248 // while we currently don't start with an AbsResourceInstance as a target 249 // address, check all resource types for consistency. 250 case AbsResourceInstance: 251 // We'll use our stringification as a cheat-ish way to test for equality. 252 return to.String() == r.String() 253 case ConfigResource: 254 return to.String() == r.String() 255 case AbsResource: 256 return to.String() == r.String() 257 258 default: 259 return false 260 261 } 262 } 263 264 func (r AbsResourceInstance) AddrType() TargetableAddrType { 265 return AbsResourceInstanceAddrType 266 } 267 268 func (r AbsResourceInstance) String() string { 269 if len(r.Module) == 0 { 270 return r.Resource.String() 271 } 272 return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) 273 } 274 275 // AffectedAbsResource returns the AbsResource for the instance. 276 func (r AbsResourceInstance) AffectedAbsResource() AbsResource { 277 return AbsResource{ 278 Module: r.Module, 279 Resource: r.Resource.Resource, 280 } 281 } 282 283 func (r AbsResourceInstance) Equal(o AbsResourceInstance) bool { 284 return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) 285 } 286 287 // Less returns true if the receiver should sort before the given other value 288 // in a sorted list of addresses. 289 func (r AbsResourceInstance) Less(o AbsResourceInstance) bool { 290 switch { 291 292 case len(r.Module) != len(o.Module): 293 return len(r.Module) < len(o.Module) 294 295 case r.Module.String() != o.Module.String(): 296 return r.Module.Less(o.Module) 297 298 case r.Resource.Resource.Mode != o.Resource.Resource.Mode: 299 return r.Resource.Resource.Mode == DataResourceMode 300 301 case r.Resource.Resource.Type != o.Resource.Resource.Type: 302 return r.Resource.Resource.Type < o.Resource.Resource.Type 303 304 case r.Resource.Resource.Name != o.Resource.Resource.Name: 305 return r.Resource.Resource.Name < o.Resource.Resource.Name 306 307 case r.Resource.Key != o.Resource.Key: 308 return InstanceKeyLess(r.Resource.Key, o.Resource.Key) 309 310 default: 311 return false 312 313 } 314 } 315 316 type absResourceInstanceKey string 317 318 func (r AbsResourceInstance) UniqueKey() UniqueKey { 319 return absResourceInstanceKey(r.String()) 320 } 321 322 func (r absResourceInstanceKey) uniqueKeySigil() {} 323 324 func (r AbsResourceInstance) absMoveableSigil() { 325 // AbsResourceInstance is moveable 326 } 327 328 // ConfigResource is an address for a resource within a configuration. 329 type ConfigResource struct { 330 targetable 331 Module Module 332 Resource Resource 333 } 334 335 // Resource returns the address of a particular resource within the module. 336 func (m Module) Resource(mode ResourceMode, typeName string, name string) ConfigResource { 337 return ConfigResource{ 338 Module: m, 339 Resource: Resource{ 340 Mode: mode, 341 Type: typeName, 342 Name: name, 343 }, 344 } 345 } 346 347 // Absolute produces the address for the receiver within a specific module instance. 348 func (r ConfigResource) Absolute(module ModuleInstance) AbsResource { 349 return AbsResource{ 350 Module: module, 351 Resource: r.Resource, 352 } 353 } 354 355 // TargetContains implements Targetable by returning true if the given other 356 // address is either equal to the receiver or is an instance of the 357 // receiver. 358 func (r ConfigResource) TargetContains(other Targetable) bool { 359 switch to := other.(type) { 360 case ConfigResource: 361 // We'll use our stringification as a cheat-ish way to test for equality. 362 return to.String() == r.String() 363 case AbsResource: 364 return r.TargetContains(to.Config()) 365 case AbsResourceInstance: 366 return r.TargetContains(to.ContainingResource()) 367 default: 368 return false 369 } 370 } 371 372 func (r ConfigResource) AddrType() TargetableAddrType { 373 return ConfigResourceAddrType 374 } 375 376 func (r ConfigResource) String() string { 377 if len(r.Module) == 0 { 378 return r.Resource.String() 379 } 380 return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) 381 } 382 383 func (r ConfigResource) Equal(o ConfigResource) bool { 384 return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) 385 } 386 387 func (r ConfigResource) configMoveableSigil() { 388 // AbsResource is moveable 389 } 390 391 // ResourceMode defines which lifecycle applies to a given resource. Each 392 // resource lifecycle has a slightly different address format. 393 type ResourceMode rune 394 395 //go:generate go run golang.org/x/tools/cmd/stringer -type ResourceMode 396 397 const ( 398 // InvalidResourceMode is the zero value of ResourceMode and is not 399 // a valid resource mode. 400 InvalidResourceMode ResourceMode = 0 401 402 // ManagedResourceMode indicates a managed resource, as defined by 403 // "resource" blocks in configuration. 404 ManagedResourceMode ResourceMode = 'M' 405 406 // DataResourceMode indicates a data resource, as defined by 407 // "data" blocks in configuration. 408 DataResourceMode ResourceMode = 'D' 409 )