github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/transform_orphan_resource.go (about) 1 package terraform 2 3 import ( 4 "log" 5 6 "github.com/hashicorp/terraform/internal/configs" 7 "github.com/hashicorp/terraform/internal/dag" 8 "github.com/hashicorp/terraform/internal/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 // Do not apply this transformer 31 skip bool 32 } 33 34 func (t *OrphanResourceInstanceTransformer) Transform(g *Graph) error { 35 if t.skip { 36 return nil 37 } 38 39 if t.State == nil { 40 // If the entire state is nil, there can't be any orphans 41 return nil 42 } 43 if t.Config == nil { 44 // Should never happen: we can't be doing any Terraform operations 45 // without at least an empty configuration. 46 panic("OrphanResourceInstanceTransformer used without setting Config") 47 } 48 49 // Go through the modules and for each module transform in order 50 // to add the orphan. 51 for _, ms := range t.State.Modules { 52 if err := t.transform(g, ms); err != nil { 53 return err 54 } 55 } 56 57 return nil 58 } 59 60 func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Module) error { 61 if ms == nil { 62 return nil 63 } 64 65 moduleAddr := ms.Addr 66 67 // Get the configuration for this module. The configuration might be 68 // nil if the module was removed from the configuration. This is okay, 69 // this just means that every resource is an orphan. 70 var m *configs.Module 71 if c := t.Config.DescendentForInstance(moduleAddr); c != nil { 72 m = c.Module 73 } 74 75 // An "orphan" is a resource that is in the state but not the configuration, 76 // so we'll walk the state resources and try to correlate each of them 77 // with a configuration block. Each orphan gets a node in the graph whose 78 // type is decided by t.Concrete. 79 // 80 // We don't handle orphans related to changes in the "count" and "for_each" 81 // pseudo-arguments here. They are handled by OrphanResourceCountTransformer. 82 for _, rs := range ms.Resources { 83 if m != nil { 84 if r := m.ResourceByAddr(rs.Addr.Resource); r != nil { 85 continue 86 } 87 } 88 89 for key, inst := range rs.Instances { 90 // deposed instances will be taken care of separately 91 if inst.Current == nil { 92 continue 93 } 94 95 addr := rs.Addr.Instance(key) 96 abstract := NewNodeAbstractResourceInstance(addr) 97 var node dag.Vertex = abstract 98 if f := t.Concrete; f != nil { 99 node = f(abstract) 100 } 101 log.Printf("[TRACE] OrphanResourceInstanceTransformer: adding single-instance orphan node for %s", addr) 102 g.Add(node) 103 } 104 } 105 106 return nil 107 }