github.com/opentofu/opentofu@v1.7.1/internal/tofu/hook.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package tofu
     7  
     8  import (
     9  	"github.com/zclconf/go-cty/cty"
    10  
    11  	"github.com/opentofu/opentofu/internal/addrs"
    12  	"github.com/opentofu/opentofu/internal/plans"
    13  	"github.com/opentofu/opentofu/internal/providers"
    14  	"github.com/opentofu/opentofu/internal/states"
    15  )
    16  
    17  // HookAction is an enum of actions that can be taken as a result of a hook
    18  // callback. This allows you to modify the behavior of OpenTofu at runtime.
    19  type HookAction byte
    20  
    21  const (
    22  	// HookActionContinue continues with processing as usual.
    23  	HookActionContinue HookAction = iota
    24  
    25  	// HookActionHalt halts immediately: no more hooks are processed
    26  	// and the action that OpenTofu was about to take is cancelled.
    27  	HookActionHalt
    28  )
    29  
    30  // Hook is the interface that must be implemented to hook into various
    31  // parts of OpenTofu, allowing you to inspect or change behavior at runtime.
    32  //
    33  // There are MANY hook points into OpenTofu. If you only want to implement
    34  // some hook points, but not all (which is the likely case), then embed the
    35  // NilHook into your struct, which implements all of the interface but does
    36  // nothing. Then, override only the functions you want to implement.
    37  type Hook interface {
    38  	// PreApply and PostApply are called before and after an action for a
    39  	// single instance is applied. The error argument in PostApply is the
    40  	// error, if any, that was returned from the provider Apply call itself.
    41  	PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error)
    42  	PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error)
    43  
    44  	// PreDiff and PostDiff are called before and after a provider is given
    45  	// the opportunity to customize the proposed new state to produce the
    46  	// planned new state.
    47  	PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error)
    48  	PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error)
    49  
    50  	// The provisioning hooks signal both the overall start end end of
    51  	// provisioning for a particular instance and of each of the individual
    52  	// configured provisioners for each instance. The sequence of these
    53  	// for a given instance might look something like this:
    54  	//
    55  	//          PreProvisionInstance(aws_instance.foo[1], ...)
    56  	//      PreProvisionInstanceStep(aws_instance.foo[1], "file")
    57  	//     PostProvisionInstanceStep(aws_instance.foo[1], "file", nil)
    58  	//      PreProvisionInstanceStep(aws_instance.foo[1], "remote-exec")
    59  	//               ProvisionOutput(aws_instance.foo[1], "remote-exec", "Installing foo...")
    60  	//               ProvisionOutput(aws_instance.foo[1], "remote-exec", "Configuring bar...")
    61  	//     PostProvisionInstanceStep(aws_instance.foo[1], "remote-exec", nil)
    62  	//         PostProvisionInstance(aws_instance.foo[1], ...)
    63  	//
    64  	// ProvisionOutput is called with output sent back by the provisioners.
    65  	// This will be called multiple times as output comes in, with each call
    66  	// representing one line of output. It cannot control whether the
    67  	// provisioner continues running.
    68  	PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error)
    69  	PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error)
    70  	PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error)
    71  	PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error)
    72  	ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string)
    73  
    74  	// PreRefresh and PostRefresh are called before and after a single
    75  	// resource state is refreshed, respectively.
    76  	PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error)
    77  	PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error)
    78  
    79  	// PreImportState and PostImportState are called before and after
    80  	// (respectively) each state import operation for a given resource address when
    81  	// using the legacy import command.
    82  	PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error)
    83  	PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error)
    84  
    85  	// PrePlanImport and PostPlanImport are called during a plan before and after planning to import
    86  	// a new resource using the configuration-driven import workflow.
    87  	PrePlanImport(addr addrs.AbsResourceInstance, importID string) (HookAction, error)
    88  	PostPlanImport(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error)
    89  
    90  	// PreApplyImport and PostApplyImport are called during an apply for each imported resource when
    91  	// using the configuration-driven import workflow.
    92  	PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error)
    93  	PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error)
    94  
    95  	// Stopping is called if an external signal requests that OpenTofu
    96  	// gracefully abort an operation in progress.
    97  	//
    98  	// This notification might suggest that the user wants OpenTofu to exit
    99  	// ASAP and in that case it's possible that if OpenTofu runs for too much
   100  	// longer then it'll get killed un-gracefully, and so this hook could be
   101  	// an opportunity to persist any transient data that would be lost under
   102  	// a subsequent kill signal. However, implementations must take care to do
   103  	// so in a way that won't cause corruption if the process _is_ killed while
   104  	// this hook is still running.
   105  	//
   106  	// This hook cannot control whether OpenTofu continues, because the
   107  	// graceful shutdown process is typically already running by the time this
   108  	// function is called.
   109  	Stopping()
   110  
   111  	// PostStateUpdate is called each time the state is updated. It receives
   112  	// a deep copy of the state, which it may therefore access freely without
   113  	// any need for locks to protect from concurrent writes from the caller.
   114  	PostStateUpdate(new *states.State) (HookAction, error)
   115  }
   116  
   117  // NilHook is a Hook implementation that does nothing. It exists only to
   118  // simplify implementing hooks. You can embed this into your Hook implementation
   119  // and only implement the functions you are interested in.
   120  type NilHook struct{}
   121  
   122  var _ Hook = (*NilHook)(nil)
   123  
   124  func (*NilHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
   125  	return HookActionContinue, nil
   126  }
   127  
   128  func (*NilHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) {
   129  	return HookActionContinue, nil
   130  }
   131  
   132  func (*NilHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) {
   133  	return HookActionContinue, nil
   134  }
   135  
   136  func (*NilHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
   137  	return HookActionContinue, nil
   138  }
   139  
   140  func (*NilHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
   141  	return HookActionContinue, nil
   142  }
   143  
   144  func (*NilHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
   145  	return HookActionContinue, nil
   146  }
   147  
   148  func (*NilHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) {
   149  	return HookActionContinue, nil
   150  }
   151  
   152  func (*NilHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) {
   153  	return HookActionContinue, nil
   154  }
   155  
   156  func (*NilHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) {
   157  }
   158  
   159  func (*NilHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) {
   160  	return HookActionContinue, nil
   161  }
   162  
   163  func (*NilHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) {
   164  	return HookActionContinue, nil
   165  }
   166  
   167  func (*NilHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
   168  	return HookActionContinue, nil
   169  }
   170  
   171  func (*NilHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
   172  	return HookActionContinue, nil
   173  }
   174  
   175  func (h *NilHook) PrePlanImport(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
   176  	return HookActionContinue, nil
   177  }
   178  
   179  func (h *NilHook) PostPlanImport(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
   180  	return HookActionContinue, nil
   181  }
   182  
   183  func (h *NilHook) PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
   184  	return HookActionContinue, nil
   185  }
   186  
   187  func (h *NilHook) PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
   188  	return HookActionContinue, nil
   189  }
   190  
   191  func (*NilHook) Stopping() {
   192  	// Does nothing at all by default
   193  }
   194  
   195  func (*NilHook) PostStateUpdate(new *states.State) (HookAction, error) {
   196  	return HookActionContinue, nil
   197  }