kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/terraform/node_resource_plan_orphan.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"kubeform.dev/terraform-backend-sdk/addrs"
     8  	"kubeform.dev/terraform-backend-sdk/plans"
     9  	"kubeform.dev/terraform-backend-sdk/states"
    10  	"kubeform.dev/terraform-backend-sdk/tfdiags"
    11  )
    12  
    13  // NodePlannableResourceInstanceOrphan represents a resource that is "applyable":
    14  // it is ready to be applied and is represented by a diff.
    15  type NodePlannableResourceInstanceOrphan struct {
    16  	*NodeAbstractResourceInstance
    17  
    18  	// skipRefresh indicates that we should skip refreshing individual instances
    19  	skipRefresh bool
    20  
    21  	// skipPlanChanges indicates we should skip trying to plan change actions
    22  	// for any instances.
    23  	skipPlanChanges bool
    24  }
    25  
    26  var (
    27  	_ GraphNodeModuleInstance       = (*NodePlannableResourceInstanceOrphan)(nil)
    28  	_ GraphNodeReferenceable        = (*NodePlannableResourceInstanceOrphan)(nil)
    29  	_ GraphNodeReferencer           = (*NodePlannableResourceInstanceOrphan)(nil)
    30  	_ GraphNodeConfigResource       = (*NodePlannableResourceInstanceOrphan)(nil)
    31  	_ GraphNodeResourceInstance     = (*NodePlannableResourceInstanceOrphan)(nil)
    32  	_ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstanceOrphan)(nil)
    33  	_ GraphNodeAttachResourceState  = (*NodePlannableResourceInstanceOrphan)(nil)
    34  	_ GraphNodeExecutable           = (*NodePlannableResourceInstanceOrphan)(nil)
    35  	_ GraphNodeProviderConsumer     = (*NodePlannableResourceInstanceOrphan)(nil)
    36  )
    37  
    38  func (n *NodePlannableResourceInstanceOrphan) Name() string {
    39  	return n.ResourceInstanceAddr().String() + " (orphan)"
    40  }
    41  
    42  // GraphNodeExecutable
    43  func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
    44  	addr := n.ResourceInstanceAddr()
    45  
    46  	// Eval info is different depending on what kind of resource this is
    47  	switch addr.Resource.Resource.Mode {
    48  	case addrs.ManagedResourceMode:
    49  		return n.managedResourceExecute(ctx)
    50  	case addrs.DataResourceMode:
    51  		return n.dataResourceExecute(ctx)
    52  	default:
    53  		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
    54  	}
    55  }
    56  
    57  func (n *NodePlannableResourceInstanceOrphan) ProvidedBy() (addr addrs.ProviderConfig, exact bool) {
    58  	if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
    59  		// indicate that this node does not require a configured provider
    60  		return nil, true
    61  	}
    62  	return n.NodeAbstractResourceInstance.ProvidedBy()
    63  }
    64  
    65  func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContext) tfdiags.Diagnostics {
    66  	// A data source that is no longer in the config is removed from the state
    67  	log.Printf("[TRACE] NodePlannableResourceInstanceOrphan: removing state object for %s", n.Addr)
    68  
    69  	// we need to update both the refresh state to refresh the current data
    70  	// source, and the working state for plan-time evaluations.
    71  	refreshState := ctx.RefreshState()
    72  	refreshState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
    73  
    74  	workingState := ctx.State()
    75  	workingState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
    76  	return nil
    77  }
    78  
    79  func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
    80  	addr := n.ResourceInstanceAddr()
    81  
    82  	oldState, readDiags := n.readResourceInstanceState(ctx, addr)
    83  	diags = diags.Append(readDiags)
    84  	if diags.HasErrors() {
    85  		return diags
    86  	}
    87  
    88  	// Note any upgrades that readResourceInstanceState might've done in the
    89  	// prevRunState, so that it'll conform to current schema.
    90  	diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, prevRunState))
    91  	if diags.HasErrors() {
    92  		return diags
    93  	}
    94  	// Also the refreshState, because that should still reflect schema upgrades
    95  	// even if not refreshing.
    96  	diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, refreshState))
    97  	if diags.HasErrors() {
    98  		return diags
    99  	}
   100  
   101  	if !n.skipRefresh {
   102  		// Refresh this instance even though it is going to be destroyed, in
   103  		// order to catch missing resources. If this is a normal plan,
   104  		// providers expect a Read request to remove missing resources from the
   105  		// plan before apply, and may not handle a missing resource during
   106  		// Delete correctly.  If this is a simple refresh, Terraform is
   107  		// expected to remove the missing resource from the state entirely
   108  		refreshedState, refreshDiags := n.refresh(ctx, states.NotDeposed, oldState)
   109  		diags = diags.Append(refreshDiags)
   110  		if diags.HasErrors() {
   111  			return diags
   112  		}
   113  
   114  		diags = diags.Append(n.writeResourceInstanceState(ctx, refreshedState, refreshState))
   115  		if diags.HasErrors() {
   116  			return diags
   117  		}
   118  
   119  		// If we refreshed then our subsequent planning should be in terms of
   120  		// the new object, not the original object.
   121  		oldState = refreshedState
   122  	}
   123  
   124  	if !n.skipPlanChanges {
   125  		var change *plans.ResourceInstanceChange
   126  		change, destroyPlanDiags := n.planDestroy(ctx, oldState, "")
   127  		diags = diags.Append(destroyPlanDiags)
   128  		if diags.HasErrors() {
   129  			return diags
   130  		}
   131  
   132  		diags = diags.Append(n.checkPreventDestroy(change))
   133  		if diags.HasErrors() {
   134  			return diags
   135  		}
   136  
   137  		diags = diags.Append(n.writeChange(ctx, change, ""))
   138  		if diags.HasErrors() {
   139  			return diags
   140  		}
   141  
   142  		diags = diags.Append(n.writeResourceInstanceState(ctx, nil, workingState))
   143  	} else {
   144  		// The working state should at least be updated with the result
   145  		// of upgrading and refreshing from above.
   146  		diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, workingState))
   147  	}
   148  
   149  	return diags
   150  }