github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/terraform/transform_orphan_resource.go (about) 1 package terraform 2 3 import ( 4 "log" 5 6 "github.com/cycloidio/terraform/configs" 7 "github.com/cycloidio/terraform/dag" 8 "github.com/cycloidio/terraform/states" 9 ) 10 11 // OrphanResourceInstanceTransformer is a GraphTransformer that adds orphaned 12 // resource instances to the graph. An "orphan" is an instance that is present 13 // in the state but belongs to a resource that is no longer present in the 14 // configuration. 15 // 16 // This is not the transformer that deals with "count orphans" (instances that 17 // are no longer covered by a resource's "count" or "for_each" setting); that's 18 // handled instead by OrphanResourceCountTransformer. 19 type OrphanResourceInstanceTransformer struct { 20 Concrete ConcreteResourceInstanceNodeFunc 21 22 // State is the global state. We require the global state to 23 // properly find module orphans at our path. 24 State *states.State 25 26 // Config is the root node in the configuration tree. We'll look up 27 // the appropriate note in this tree using the path in each node. 28 Config *configs.Config 29 } 30 31 func (t *OrphanResourceInstanceTransformer) Transform(g *Graph) error { 32 if t.State == nil { 33 // If the entire state is nil, there can't be any orphans 34 return nil 35 } 36 if t.Config == nil { 37 // Should never happen: we can't be doing any Terraform operations 38 // without at least an empty configuration. 39 panic("OrphanResourceInstanceTransformer used without setting Config") 40 } 41 42 // Go through the modules and for each module transform in order 43 // to add the orphan. 44 for _, ms := range t.State.Modules { 45 if err := t.transform(g, ms); err != nil { 46 return err 47 } 48 } 49 50 return nil 51 } 52 53 func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Module) error { 54 if ms == nil { 55 return nil 56 } 57 58 moduleAddr := ms.Addr 59 60 // Get the configuration for this module. The configuration might be 61 // nil if the module was removed from the configuration. This is okay, 62 // this just means that every resource is an orphan. 63 var m *configs.Module 64 if c := t.Config.DescendentForInstance(moduleAddr); c != nil { 65 m = c.Module 66 } 67 68 // An "orphan" is a resource that is in the state but not the configuration, 69 // so we'll walk the state resources and try to correlate each of them 70 // with a configuration block. Each orphan gets a node in the graph whose 71 // type is decided by t.Concrete. 72 // 73 // We don't handle orphans related to changes in the "count" and "for_each" 74 // pseudo-arguments here. They are handled by OrphanResourceCountTransformer. 75 for _, rs := range ms.Resources { 76 if m != nil { 77 if r := m.ResourceByAddr(rs.Addr.Resource); r != nil { 78 continue 79 } 80 } 81 82 for key, inst := range rs.Instances { 83 // deposed instances will be taken care of separately 84 if inst.Current == nil { 85 continue 86 } 87 88 addr := rs.Addr.Instance(key) 89 abstract := NewNodeAbstractResourceInstance(addr) 90 var node dag.Vertex = abstract 91 if f := t.Concrete; f != nil { 92 node = f(abstract) 93 } 94 log.Printf("[TRACE] OrphanResourceInstanceTransformer: adding single-instance orphan node for %s", addr) 95 g.Add(node) 96 } 97 } 98 99 return nil 100 }