kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/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 func (r AbsResource) Equal(o AbsResource) bool { 190 return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) 191 } 192 193 func (r AbsResource) absMoveableSigil() { 194 // AbsResource is moveable 195 } 196 197 func (r AbsResource) UniqueKey() UniqueKey { 198 return absResourceInstanceKey(r.String()) 199 } 200 201 // AbsResourceInstance is an absolute address for a resource instance under a 202 // given module path. 203 type AbsResourceInstance struct { 204 targetable 205 Module ModuleInstance 206 Resource ResourceInstance 207 } 208 209 // ResourceInstance returns the address of a particular resource instance within the receiver. 210 func (m ModuleInstance) ResourceInstance(mode ResourceMode, typeName string, name string, key InstanceKey) AbsResourceInstance { 211 return AbsResourceInstance{ 212 Module: m, 213 Resource: ResourceInstance{ 214 Resource: Resource{ 215 Mode: mode, 216 Type: typeName, 217 Name: name, 218 }, 219 Key: key, 220 }, 221 } 222 } 223 224 // ContainingResource returns the address of the resource that contains the 225 // receving resource instance. In other words, it discards the key portion 226 // of the address to produce an AbsResource value. 227 func (r AbsResourceInstance) ContainingResource() AbsResource { 228 return AbsResource{ 229 Module: r.Module, 230 Resource: r.Resource.ContainingResource(), 231 } 232 } 233 234 // TargetContains implements Targetable by returning true if the given other 235 // address is equal to the receiver. 236 func (r AbsResourceInstance) TargetContains(other Targetable) bool { 237 switch to := other.(type) { 238 239 // while we currently don't start with an AbsResourceInstance as a target 240 // address, check all resource types for consistency. 241 case AbsResourceInstance: 242 // We'll use our stringification as a cheat-ish way to test for equality. 243 return to.String() == r.String() 244 case ConfigResource: 245 return to.String() == r.String() 246 case AbsResource: 247 return to.String() == r.String() 248 249 default: 250 return false 251 252 } 253 } 254 255 func (r AbsResourceInstance) AddrType() TargetableAddrType { 256 return AbsResourceInstanceAddrType 257 } 258 259 func (r AbsResourceInstance) String() string { 260 if len(r.Module) == 0 { 261 return r.Resource.String() 262 } 263 return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) 264 } 265 266 func (r AbsResourceInstance) Equal(o AbsResourceInstance) bool { 267 return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) 268 } 269 270 // Less returns true if the receiver should sort before the given other value 271 // in a sorted list of addresses. 272 func (r AbsResourceInstance) Less(o AbsResourceInstance) bool { 273 switch { 274 275 case len(r.Module) != len(o.Module): 276 return len(r.Module) < len(o.Module) 277 278 case r.Module.String() != o.Module.String(): 279 return r.Module.Less(o.Module) 280 281 case r.Resource.Resource.Mode != o.Resource.Resource.Mode: 282 return r.Resource.Resource.Mode == DataResourceMode 283 284 case r.Resource.Resource.Type != o.Resource.Resource.Type: 285 return r.Resource.Resource.Type < o.Resource.Resource.Type 286 287 case r.Resource.Resource.Name != o.Resource.Resource.Name: 288 return r.Resource.Resource.Name < o.Resource.Resource.Name 289 290 case r.Resource.Key != o.Resource.Key: 291 return InstanceKeyLess(r.Resource.Key, o.Resource.Key) 292 293 default: 294 return false 295 296 } 297 } 298 299 type absResourceInstanceKey string 300 301 func (r AbsResourceInstance) UniqueKey() UniqueKey { 302 return absResourceInstanceKey(r.String()) 303 } 304 305 func (r absResourceInstanceKey) uniqueKeySigil() {} 306 307 func (r AbsResourceInstance) absMoveableSigil() { 308 // AbsResourceInstance is moveable 309 } 310 311 // ConfigResource is an address for a resource within a configuration. 312 type ConfigResource struct { 313 targetable 314 Module Module 315 Resource Resource 316 } 317 318 // Resource returns the address of a particular resource within the module. 319 func (m Module) Resource(mode ResourceMode, typeName string, name string) ConfigResource { 320 return ConfigResource{ 321 Module: m, 322 Resource: Resource{ 323 Mode: mode, 324 Type: typeName, 325 Name: name, 326 }, 327 } 328 } 329 330 // Absolute produces the address for the receiver within a specific module instance. 331 func (r ConfigResource) Absolute(module ModuleInstance) AbsResource { 332 return AbsResource{ 333 Module: module, 334 Resource: r.Resource, 335 } 336 } 337 338 // TargetContains implements Targetable by returning true if the given other 339 // address is either equal to the receiver or is an instance of the 340 // receiver. 341 func (r ConfigResource) TargetContains(other Targetable) bool { 342 switch to := other.(type) { 343 case ConfigResource: 344 // We'll use our stringification as a cheat-ish way to test for equality. 345 return to.String() == r.String() 346 case AbsResource: 347 return r.TargetContains(to.Config()) 348 case AbsResourceInstance: 349 return r.TargetContains(to.ContainingResource()) 350 default: 351 return false 352 } 353 } 354 355 func (r ConfigResource) AddrType() TargetableAddrType { 356 return ConfigResourceAddrType 357 } 358 359 func (r ConfigResource) String() string { 360 if len(r.Module) == 0 { 361 return r.Resource.String() 362 } 363 return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) 364 } 365 366 func (r ConfigResource) Equal(o ConfigResource) bool { 367 return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) 368 } 369 370 func (r ConfigResource) configMoveableSigil() { 371 // AbsResource is moveable 372 } 373 374 // ResourceMode defines which lifecycle applies to a given resource. Each 375 // resource lifecycle has a slightly different address format. 376 type ResourceMode rune 377 378 //go:generate go run golang.org/x/tools/cmd/stringer -type ResourceMode 379 380 const ( 381 // InvalidResourceMode is the zero value of ResourceMode and is not 382 // a valid resource mode. 383 InvalidResourceMode ResourceMode = 0 384 385 // ManagedResourceMode indicates a managed resource, as defined by 386 // "resource" blocks in configuration. 387 ManagedResourceMode ResourceMode = 'M' 388 389 // DataResourceMode indicates a data resource, as defined by 390 // "data" blocks in configuration. 391 DataResourceMode ResourceMode = 'D' 392 )