github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/states/remote/state.go (about)

     1  package remote
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"sync"
     8  
     9  	uuid "github.com/hashicorp/go-uuid"
    10  
    11  	"github.com/hashicorp/terraform/internal/states"
    12  	"github.com/hashicorp/terraform/internal/states/statefile"
    13  	"github.com/hashicorp/terraform/internal/states/statemgr"
    14  	"github.com/hashicorp/terraform/internal/terraform"
    15  )
    16  
    17  // State implements the State interfaces in the state package to handle
    18  // reading and writing the remote state. This State on its own does no
    19  // local caching so every persist will go to the remote storage and local
    20  // writes will go to memory.
    21  type State struct {
    22  	mu sync.Mutex
    23  
    24  	Client Client
    25  
    26  	// We track two pieces of meta data in addition to the state itself:
    27  	//
    28  	// lineage - the state's unique ID
    29  	// serial  - the monotonic counter of "versions" of the state
    30  	//
    31  	// Both of these (along with state) have a sister field
    32  	// that represents the values read in from an existing source.
    33  	// All three of these values are used to determine if the new
    34  	// state has changed from an existing state we read in.
    35  	lineage, readLineage string
    36  	serial, readSerial   uint64
    37  	state, readState     *states.State
    38  	disableLocks         bool
    39  }
    40  
    41  var _ statemgr.Full = (*State)(nil)
    42  var _ statemgr.Migrator = (*State)(nil)
    43  
    44  // statemgr.Reader impl.
    45  func (s *State) State() *states.State {
    46  	s.mu.Lock()
    47  	defer s.mu.Unlock()
    48  
    49  	return s.state.DeepCopy()
    50  }
    51  
    52  func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
    53  	if err := s.RefreshState(); err != nil {
    54  		return nil, fmt.Errorf("Failed to load state: %s", err)
    55  	}
    56  
    57  	state := s.State()
    58  	if state == nil {
    59  		state = states.NewState()
    60  	}
    61  
    62  	return state.RootModule().OutputValues, nil
    63  }
    64  
    65  // StateForMigration is part of our implementation of statemgr.Migrator.
    66  func (s *State) StateForMigration() *statefile.File {
    67  	s.mu.Lock()
    68  	defer s.mu.Unlock()
    69  
    70  	return statefile.New(s.state.DeepCopy(), s.lineage, s.serial)
    71  }
    72  
    73  // statemgr.Writer impl.
    74  func (s *State) WriteState(state *states.State) error {
    75  	s.mu.Lock()
    76  	defer s.mu.Unlock()
    77  
    78  	// We create a deep copy of the state here, because the caller also has
    79  	// a reference to the given object and can potentially go on to mutate
    80  	// it after we return, but we want the snapshot at this point in time.
    81  	s.state = state.DeepCopy()
    82  
    83  	return nil
    84  }
    85  
    86  // WriteStateForMigration is part of our implementation of statemgr.Migrator.
    87  func (s *State) WriteStateForMigration(f *statefile.File, force bool) error {
    88  	s.mu.Lock()
    89  	defer s.mu.Unlock()
    90  
    91  	if !force {
    92  		checkFile := statefile.New(s.state, s.lineage, s.serial)
    93  		if err := statemgr.CheckValidImport(f, checkFile); err != nil {
    94  			return err
    95  		}
    96  	}
    97  
    98  	// The remote backend needs to pass the `force` flag through to its client.
    99  	// For backends that support such operations, inform the client
   100  	// that a force push has been requested
   101  	c, isForcePusher := s.Client.(ClientForcePusher)
   102  	if force && isForcePusher {
   103  		c.EnableForcePush()
   104  	}
   105  
   106  	// We create a deep copy of the state here, because the caller also has
   107  	// a reference to the given object and can potentially go on to mutate
   108  	// it after we return, but we want the snapshot at this point in time.
   109  	s.state = f.State.DeepCopy()
   110  	s.lineage = f.Lineage
   111  	s.serial = f.Serial
   112  
   113  	return nil
   114  }
   115  
   116  // statemgr.Refresher impl.
   117  func (s *State) RefreshState() error {
   118  	s.mu.Lock()
   119  	defer s.mu.Unlock()
   120  	return s.refreshState()
   121  }
   122  
   123  // refreshState is the main implementation of RefreshState, but split out so
   124  // that we can make internal calls to it from methods that are already holding
   125  // the s.mu lock.
   126  func (s *State) refreshState() error {
   127  	payload, err := s.Client.Get()
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	// no remote state is OK
   133  	if payload == nil {
   134  		s.readState = nil
   135  		s.lineage = ""
   136  		s.serial = 0
   137  		return nil
   138  	}
   139  
   140  	stateFile, err := statefile.Read(bytes.NewReader(payload.Data))
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	s.lineage = stateFile.Lineage
   146  	s.serial = stateFile.Serial
   147  	s.state = stateFile.State
   148  
   149  	// Properties from the remote must be separate so we can
   150  	// track changes as lineage, serial and/or state are mutated
   151  	s.readLineage = stateFile.Lineage
   152  	s.readSerial = stateFile.Serial
   153  	s.readState = s.state.DeepCopy()
   154  	return nil
   155  }
   156  
   157  // statemgr.Persister impl.
   158  func (s *State) PersistState(schemas *terraform.Schemas) error {
   159  	s.mu.Lock()
   160  	defer s.mu.Unlock()
   161  
   162  	log.Printf("[DEBUG] states/remote: state read serial is: %d; serial is: %d", s.readSerial, s.serial)
   163  	log.Printf("[DEBUG] states/remote: state read lineage is: %s; lineage is: %s", s.readLineage, s.lineage)
   164  
   165  	if s.readState != nil {
   166  		lineageUnchanged := s.readLineage != "" && s.lineage == s.readLineage
   167  		serialUnchanged := s.readSerial != 0 && s.serial == s.readSerial
   168  		stateUnchanged := statefile.StatesMarshalEqual(s.state, s.readState)
   169  		if stateUnchanged && lineageUnchanged && serialUnchanged {
   170  			// If the state, lineage or serial haven't changed at all then we have nothing to do.
   171  			return nil
   172  		}
   173  		s.serial++
   174  	} else {
   175  		// We might be writing a new state altogether, but before we do that
   176  		// we'll check to make sure there isn't already a snapshot present
   177  		// that we ought to be updating.
   178  		err := s.refreshState()
   179  		if err != nil {
   180  			return fmt.Errorf("failed checking for existing remote state: %s", err)
   181  		}
   182  		log.Printf("[DEBUG] states/remote: after refresh, state read serial is: %d; serial is: %d", s.readSerial, s.serial)
   183  		log.Printf("[DEBUG] states/remote: after refresh, state read lineage is: %s; lineage is: %s", s.readLineage, s.lineage)
   184  		if s.lineage == "" { // indicates that no state snapshot is present yet
   185  			lineage, err := uuid.GenerateUUID()
   186  			if err != nil {
   187  				return fmt.Errorf("failed to generate initial lineage: %v", err)
   188  			}
   189  			s.lineage = lineage
   190  			s.serial++
   191  		}
   192  	}
   193  
   194  	f := statefile.New(s.state, s.lineage, s.serial)
   195  
   196  	var buf bytes.Buffer
   197  	err := statefile.Write(f, &buf)
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	err = s.Client.Put(buf.Bytes())
   203  	if err != nil {
   204  		return err
   205  	}
   206  
   207  	// After we've successfully persisted, what we just wrote is our new
   208  	// reference state until someone calls RefreshState again.
   209  	// We've potentially overwritten (via force) the state, lineage
   210  	// and / or serial (and serial was incremented) so we copy over all
   211  	// three fields so everything matches the new state and a subsequent
   212  	// operation would correctly detect no changes to the lineage, serial or state.
   213  	s.readState = s.state.DeepCopy()
   214  	s.readLineage = s.lineage
   215  	s.readSerial = s.serial
   216  	return nil
   217  }
   218  
   219  // Lock calls the Client's Lock method if it's implemented.
   220  func (s *State) Lock(info *statemgr.LockInfo) (string, error) {
   221  	s.mu.Lock()
   222  	defer s.mu.Unlock()
   223  
   224  	if s.disableLocks {
   225  		return "", nil
   226  	}
   227  
   228  	if c, ok := s.Client.(ClientLocker); ok {
   229  		return c.Lock(info)
   230  	}
   231  	return "", nil
   232  }
   233  
   234  // Unlock calls the Client's Unlock method if it's implemented.
   235  func (s *State) Unlock(id string) error {
   236  	s.mu.Lock()
   237  	defer s.mu.Unlock()
   238  
   239  	if s.disableLocks {
   240  		return nil
   241  	}
   242  
   243  	if c, ok := s.Client.(ClientLocker); ok {
   244  		return c.Unlock(id)
   245  	}
   246  	return nil
   247  }
   248  
   249  // DisableLocks turns the Lock and Unlock methods into no-ops. This is intended
   250  // to be called during initialization of a state manager and should not be
   251  // called after any of the statemgr.Full interface methods have been called.
   252  func (s *State) DisableLocks() {
   253  	s.disableLocks = true
   254  }
   255  
   256  // StateSnapshotMeta returns the metadata from the most recently persisted
   257  // or refreshed persistent state snapshot.
   258  //
   259  // This is an implementation of statemgr.PersistentMeta.
   260  func (s *State) StateSnapshotMeta() statemgr.SnapshotMeta {
   261  	return statemgr.SnapshotMeta{
   262  		Lineage: s.lineage,
   263  		Serial:  s.serial,
   264  	}
   265  }