mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
statemgr+remote: context.Context parameters
This extends statemgr.Persistent, statemgr.Locker and remote.Client to all expect context.Context parameters, and then updates all of the existing implementations of those interfaces to support them. All of the calls to statemgr.Persistent and statemgr.Locker methods outside of tests are consistently context.TODO() for now, because the caller landscape of these interfaces has some complications: 1. statemgr.Locker is also used by the clistate package for its state implementation that was derived from statemgr.Filesystem's predecessor, even though what clistate manages is not actually "state" in the sense of package statemgr. The callers of that are not yet ready to provide real contexts. In a future commit we'll either need to plumb context through to all of the clistate callers, or continue the effort to separate statemgr from clistate by introducing a clistate-specific "locker" API for it to use instead. 2. We call statemgr.Persistent and statemgr.Locker methods in situations where the active context might have already been cancelled, and so we'll need to make sure to ignore cancellation when calling those. This is mainly limited to PersistState and Unlock, since both need to be able to complete after a cancellation, but there are various codepaths that perform a Lock, Refresh, Persist, Unlock sequence and so it isn't yet clear where is the best place to enforce the invariant that Persist and Unlock must not be called with a cancelable context. We'll deal with that more in subsequent commits. Within the various state manager and remote client implementations the contexts _are_ wired together as best as possible with how these subsystems are already laid out, and so once we deal with the problems above and make callers provide suitable contexts they should be able to reach all of the leaf API clients that might want to generate OpenTelemetry traces. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
@@ -365,7 +365,7 @@ func (b *Local) opWait(
|
|||||||
|
|
||||||
// try to force a PersistState just in case the process is terminated
|
// try to force a PersistState just in case the process is terminated
|
||||||
// before we can complete.
|
// before we can complete.
|
||||||
if err := opStateMgr.PersistState(nil); err != nil {
|
if err := opStateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
// We can't error out from here, but warn the user if there was an error.
|
// We can't error out from here, but warn the user if there was an error.
|
||||||
// If this isn't transient, we will catch it again below, and
|
// If this isn't transient, we will catch it again below, and
|
||||||
// attempt to save the state another way.
|
// attempt to save the state another way.
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ func (b *Local) opApply(
|
|||||||
|
|
||||||
// Store the final state
|
// Store the final state
|
||||||
runningOp.State = applyState
|
runningOp.State = applyState
|
||||||
err := statemgr.WriteAndPersist(opState, applyState, schemas)
|
err := statemgr.WriteAndPersist(context.TODO(), opState, applyState, schemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Export the state file from the state manager and assign the new
|
// Export the state file from the state manager and assign the new
|
||||||
// state. This is needed to preserve the existing serial and lineage.
|
// state. This is needed to preserve the existing serial and lineage.
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ func (b *Local) localRun(ctx context.Context, op *backend.Operation) (*backend.L
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
log.Printf("[TRACE] backend/local: reading remote state for workspace %q", op.Workspace)
|
log.Printf("[TRACE] backend/local: reading remote state for workspace %q", op.Workspace)
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf("error loading state: %w", err))
|
diags = diags.Append(fmt.Errorf("error loading state: %w", err))
|
||||||
return nil, nil, nil, diags
|
return nil, nil, nil, diags
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ func TestLocalRun_stalePlan(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := sm.RefreshState(); err != nil {
|
if err := sm.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error refreshing state: %s", err)
|
t.Fatalf("unexpected error refreshing state: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ type stateStorageThatFailsRefresh struct {
|
|||||||
|
|
||||||
var _ statemgr.Full = (*stateStorageThatFailsRefresh)(nil)
|
var _ statemgr.Full = (*stateStorageThatFailsRefresh)(nil)
|
||||||
|
|
||||||
func (s *stateStorageThatFailsRefresh) Lock(info *statemgr.LockInfo) (string, error) {
|
func (s *stateStorageThatFailsRefresh) Lock(_ context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
if s.locked {
|
if s.locked {
|
||||||
return "", fmt.Errorf("already locked")
|
return "", fmt.Errorf("already locked")
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ func (s *stateStorageThatFailsRefresh) Lock(info *statemgr.LockInfo) (string, er
|
|||||||
return "locked", nil
|
return "locked", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateStorageThatFailsRefresh) Unlock(id string) error {
|
func (s *stateStorageThatFailsRefresh) Unlock(_ context.Context, id string) error {
|
||||||
if !s.locked {
|
if !s.locked {
|
||||||
return fmt.Errorf("not locked")
|
return fmt.Errorf("not locked")
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ func (s *stateStorageThatFailsRefresh) State() *states.State {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateStorageThatFailsRefresh) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
func (s *stateStorageThatFailsRefresh) GetRootOutputValues(_ context.Context) (map[string]*states.OutputValue, error) {
|
||||||
return nil, fmt.Errorf("unimplemented")
|
return nil, fmt.Errorf("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,10 +270,10 @@ func (s *stateStorageThatFailsRefresh) WriteState(*states.State) error {
|
|||||||
return fmt.Errorf("unimplemented")
|
return fmt.Errorf("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateStorageThatFailsRefresh) RefreshState() error {
|
func (s *stateStorageThatFailsRefresh) RefreshState(_ context.Context) error {
|
||||||
return fmt.Errorf("intentionally failing for testing purposes")
|
return fmt.Errorf("intentionally failing for testing purposes")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateStorageThatFailsRefresh) PersistState(schemas *tofu.Schemas) error {
|
func (s *stateStorageThatFailsRefresh) PersistState(_ context.Context, schemas *tofu.Schemas) error {
|
||||||
return fmt.Errorf("unimplemented")
|
return fmt.Errorf("unimplemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func (b *Local) opRefresh(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := statemgr.WriteAndPersist(opState, newState, schemas)
|
err := statemgr.WriteAndPersist(context.TODO(), opState, newState, schemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = diags.Append(fmt.Errorf("failed to write state: %w", err))
|
diags = diags.Append(fmt.Errorf("failed to write state: %w", err))
|
||||||
op.ReportResult(runningOp, diags)
|
op.ReportResult(runningOp, diags)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -81,7 +82,7 @@ func (h *StateHook) PostStateUpdate(new *states.State) (tofu.HookAction, error)
|
|||||||
}
|
}
|
||||||
if mgrPersist, ok := h.StateMgr.(statemgr.Persister); ok && h.PersistInterval != 0 && h.Schemas != nil {
|
if mgrPersist, ok := h.StateMgr.(statemgr.Persister); ok && h.PersistInterval != 0 && h.Schemas != nil {
|
||||||
if h.shouldPersist() {
|
if h.shouldPersist() {
|
||||||
err := mgrPersist.PersistState(h.Schemas)
|
err := mgrPersist.PersistState(context.TODO(), h.Schemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tofu.HookActionHalt, err
|
return tofu.HookActionHalt, err
|
||||||
}
|
}
|
||||||
@@ -115,7 +116,7 @@ func (h *StateHook) Stopping() {
|
|||||||
h.intermediatePersist.ForcePersist = true
|
h.intermediatePersist.ForcePersist = true
|
||||||
|
|
||||||
if h.shouldPersist() {
|
if h.shouldPersist() {
|
||||||
err := mgrPersist.PersistState(h.Schemas)
|
err := mgrPersist.PersistState(context.TODO(), h.Schemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// This hook can't affect OpenTofu Core's ongoing behavior,
|
// This hook can't affect OpenTofu Core's ongoing behavior,
|
||||||
// but it's a best effort thing anyway, so we'll just emit a
|
// but it's a best effort thing anyway, so we'll just emit a
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -281,7 +282,7 @@ func (sm *testPersistentState) WriteState(state *states.State) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *testPersistentState) PersistState(schemas *tofu.Schemas) error {
|
func (sm *testPersistentState) PersistState(_ context.Context, schemas *tofu.Schemas) error {
|
||||||
if schemas == nil {
|
if schemas == nil {
|
||||||
return fmt.Errorf("no schemas")
|
return fmt.Errorf("no schemas")
|
||||||
}
|
}
|
||||||
@@ -307,7 +308,7 @@ func (sm *testPersistentStateThatRefusesToPersist) WriteState(state *states.Stat
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *testPersistentStateThatRefusesToPersist) PersistState(schemas *tofu.Schemas) error {
|
func (sm *testPersistentStateThatRefusesToPersist) PersistState(_ context.Context, schemas *tofu.Schemas) error {
|
||||||
if schemas == nil {
|
if schemas == nil {
|
||||||
return fmt.Errorf("no schemas")
|
return fmt.Errorf("no schemas")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ func (b *TestLocalNoDefaultState) StateMgr(ctx context.Context, name string) (st
|
|||||||
func testStateFile(t *testing.T, path string, s *states.State) {
|
func testStateFile(t *testing.T, path string, s *states.State) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
if err := statemgr.WriteAndPersist(statemgr.NewFilesystem(path, encryption.StateEncryptionDisabled()), s, nil); err != nil {
|
if err := statemgr.WriteAndPersist(t.Context(), statemgr.NewFilesystem(path, encryption.StateEncryptionDisabled()), s, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ func mustResourceInstanceAddr(s string) addrs.AbsResourceInstance {
|
|||||||
func assertBackendStateUnlocked(t *testing.T, b *Local) bool {
|
func assertBackendStateUnlocked(t *testing.T, b *Local) bool {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Errorf("state is already locked: %s", err.Error())
|
t.Errorf("state is already locked: %s", err.Error())
|
||||||
// lock was obtained
|
// lock was obtained
|
||||||
return false
|
return false
|
||||||
@@ -226,7 +226,7 @@ func assertBackendStateUnlocked(t *testing.T, b *Local) bool {
|
|||||||
func assertBackendStateLocked(t *testing.T, b *Local) bool {
|
func assertBackendStateLocked(t *testing.T, b *Local) bool {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
// lock was not obtained
|
// lock was not obtained
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
stateMgr := remote.NewState(client, b.encryption)
|
stateMgr := remote.NewState(client, b.encryption)
|
||||||
|
|
||||||
// Grab the value
|
// Grab the value
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
//if this isn't the default state name, we need to create the object so
|
//if this isn't the default state name, we need to create the object so
|
||||||
@@ -101,21 +101,21 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
// take a lock on this state while we write it
|
// take a lock on this state while we write it
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockId, err := client.Lock(lockInfo)
|
lockId, err := client.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to lock azure state: %w", err)
|
return nil, fmt.Errorf("failed to lock azure state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(parent error) error {
|
lockUnlock := func(parent error) error {
|
||||||
if err := stateMgr.Unlock(lockId); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockId); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
|
return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
|
||||||
}
|
}
|
||||||
return parent
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the value
|
// Grab the value
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ type RemoteClient struct {
|
|||||||
timeoutSeconds int
|
timeoutSeconds int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Get() (*remote.Payload, error) {
|
func (c *RemoteClient) Get(ctx context.Context) (*remote.Payload, error) {
|
||||||
// Get should time out after the timeoutSeconds
|
// Get should time out after the timeoutSeconds
|
||||||
ctx, ctxCancel := c.getContextWithTimeout()
|
ctx, ctxCancel := c.getContextWithTimeout(ctx)
|
||||||
defer ctxCancel()
|
defer ctxCancel()
|
||||||
blob, err := c.giovanniBlobClient.Get(ctx, c.accountName, c.containerName, c.keyName, blobs.GetInput{LeaseID: c.leaseID})
|
blob, err := c.giovanniBlobClient.Get(ctx, c.accountName, c.containerName, c.keyName, blobs.GetInput{LeaseID: c.leaseID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -60,8 +60,7 @@ func (c *RemoteClient) Get() (*remote.Payload, error) {
|
|||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Put(data []byte) error {
|
func (c *RemoteClient) Put(ctx context.Context, data []byte) error {
|
||||||
ctx := context.TODO()
|
|
||||||
if c.snapshot {
|
if c.snapshot {
|
||||||
snapshotInput := blobs.SnapshotInput{LeaseID: c.leaseID}
|
snapshotInput := blobs.SnapshotInput{LeaseID: c.leaseID}
|
||||||
log.Printf("[DEBUG] Snapshotting existing Blob %q (Container %q / Account %q)", c.keyName, c.containerName, c.accountName)
|
log.Printf("[DEBUG] Snapshotting existing Blob %q (Container %q / Account %q)", c.keyName, c.containerName, c.accountName)
|
||||||
@@ -72,7 +71,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
log.Print("[DEBUG] Created blob snapshot")
|
log.Print("[DEBUG] Created blob snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
properties, err := c.getBlobProperties()
|
properties, err := c.getBlobProperties(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if properties.StatusCode != http.StatusNotFound {
|
if properties.StatusCode != http.StatusNotFound {
|
||||||
return err
|
return err
|
||||||
@@ -91,8 +90,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(ctx context.Context) error {
|
||||||
ctx := context.TODO()
|
|
||||||
resp, err := c.giovanniBlobClient.Delete(ctx, c.accountName, c.containerName, c.keyName, blobs.DeleteInput{LeaseID: c.leaseID})
|
resp, err := c.giovanniBlobClient.Delete(ctx, c.accountName, c.containerName, c.keyName, blobs.DeleteInput{LeaseID: c.leaseID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !resp.IsHTTPStatus(http.StatusNotFound) {
|
if !resp.IsHTTPStatus(http.StatusNotFound) {
|
||||||
@@ -102,7 +100,7 @@ func (c *RemoteClient) Delete() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
stateName := fmt.Sprintf("%s/%s", c.containerName, c.keyName)
|
stateName := fmt.Sprintf("%s/%s", c.containerName, c.keyName)
|
||||||
info.Path = stateName
|
info.Path = stateName
|
||||||
|
|
||||||
@@ -116,7 +114,7 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getLockInfoErr := func(err error) error {
|
getLockInfoErr := func(err error) error {
|
||||||
lockInfo, infoErr := c.getLockInfo()
|
lockInfo, infoErr := c.getLockInfo(ctx)
|
||||||
if infoErr != nil {
|
if infoErr != nil {
|
||||||
err = multierror.Append(err, infoErr)
|
err = multierror.Append(err, infoErr)
|
||||||
}
|
}
|
||||||
@@ -131,10 +129,9 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
ProposedLeaseID: &info.ID,
|
ProposedLeaseID: &info.ID,
|
||||||
LeaseDuration: -1,
|
LeaseDuration: -1,
|
||||||
}
|
}
|
||||||
ctx := context.TODO()
|
|
||||||
|
|
||||||
// obtain properties to see if the blob lease is already in use. If the blob doesn't exist, create it
|
// obtain properties to see if the blob lease is already in use. If the blob doesn't exist, create it
|
||||||
properties, err := c.getBlobProperties()
|
properties, err := c.getBlobProperties(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// error if we had issues getting the blob
|
// error if we had issues getting the blob
|
||||||
if !properties.Response.IsHTTPStatus(http.StatusNotFound) {
|
if !properties.Response.IsHTTPStatus(http.StatusNotFound) {
|
||||||
@@ -165,15 +162,15 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
info.ID = leaseID.LeaseID
|
info.ID = leaseID.LeaseID
|
||||||
c.setLeaseID(leaseID.LeaseID)
|
c.setLeaseID(leaseID.LeaseID)
|
||||||
|
|
||||||
if err := c.writeLockInfo(info); err != nil {
|
if err := c.writeLockInfo(ctx, info); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return info.ID, nil
|
return info.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
|
func (c *RemoteClient) getLockInfo(ctx context.Context) (*statemgr.LockInfo, error) {
|
||||||
properties, err := c.getBlobProperties()
|
properties, err := c.getBlobProperties(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -198,9 +195,8 @@ func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// writes info to blob meta data, deletes metadata entry if info is nil
|
// writes info to blob meta data, deletes metadata entry if info is nil
|
||||||
func (c *RemoteClient) writeLockInfo(info *statemgr.LockInfo) error {
|
func (c *RemoteClient) writeLockInfo(ctx context.Context, info *statemgr.LockInfo) error {
|
||||||
ctx := context.TODO()
|
properties, err := c.getBlobProperties(ctx)
|
||||||
properties, err := c.getBlobProperties()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -221,10 +217,10 @@ func (c *RemoteClient) writeLockInfo(info *statemgr.LockInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(ctx context.Context, id string) error {
|
||||||
lockErr := &statemgr.LockError{}
|
lockErr := &statemgr.LockError{}
|
||||||
|
|
||||||
lockInfo, err := c.getLockInfo()
|
lockInfo, err := c.getLockInfo(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %w", err)
|
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %w", err)
|
||||||
return lockErr
|
return lockErr
|
||||||
@@ -237,12 +233,11 @@ func (c *RemoteClient) Unlock(id string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.setLeaseID(lockInfo.ID)
|
c.setLeaseID(lockInfo.ID)
|
||||||
if err := c.writeLockInfo(nil); err != nil {
|
if err := c.writeLockInfo(ctx, nil); err != nil {
|
||||||
lockErr.Err = fmt.Errorf("failed to delete lock info from metadata: %w", err)
|
lockErr.Err = fmt.Errorf("failed to delete lock info from metadata: %w", err)
|
||||||
return lockErr
|
return lockErr
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.TODO()
|
|
||||||
_, err = c.giovanniBlobClient.ReleaseLease(ctx, c.accountName, c.containerName, c.keyName, id)
|
_, err = c.giovanniBlobClient.ReleaseLease(ctx, c.accountName, c.containerName, c.keyName, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lockErr.Err = err
|
lockErr.Err = err
|
||||||
@@ -255,15 +250,15 @@ func (c *RemoteClient) Unlock(id string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getBlobProperties wraps the GetProperties method of the giovanniBlobClient with timeout
|
// getBlobProperties wraps the GetProperties method of the giovanniBlobClient with timeout
|
||||||
func (c *RemoteClient) getBlobProperties() (blobs.GetPropertiesResult, error) {
|
func (c *RemoteClient) getBlobProperties(ctx context.Context) (blobs.GetPropertiesResult, error) {
|
||||||
ctx, ctxCancel := c.getContextWithTimeout()
|
ctx, ctxCancel := c.getContextWithTimeout(ctx)
|
||||||
defer ctxCancel()
|
defer ctxCancel()
|
||||||
return c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, blobs.GetPropertiesInput{LeaseID: c.leaseID})
|
return c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, blobs.GetPropertiesInput{LeaseID: c.leaseID})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getContextWithTimeout returns a context with timeout based on the timeoutSeconds
|
// getContextWithTimeout returns a context with timeout based on the timeoutSeconds
|
||||||
func (c *RemoteClient) getContextWithTimeout() (context.Context, context.CancelFunc) {
|
func (c *RemoteClient) getContextWithTimeout(parent context.Context) (context.Context, context.CancelFunc) {
|
||||||
return context.WithTimeout(context.Background(), time.Duration(c.timeoutSeconds)*time.Second)
|
return context.WithTimeout(parent, time.Duration(c.timeoutSeconds)*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setLeaseID takes a string leaseID and sets the leaseID field of the RemoteClient
|
// setLeaseID takes a string leaseID and sets the leaseID field of the RemoteClient
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ func TestPutMaintainsMetaData(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bytes := []byte(acctest.RandString(20))
|
bytes := []byte(acctest.RandString(20))
|
||||||
err = remoteClient.Put(bytes)
|
err = remoteClient.Put(t.Context(), bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error putting data: %+v", err)
|
t.Fatalf("Error putting data: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,14 +101,14 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
// so States() knows it exists.
|
// so States() knows it exists.
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockId, err := stateMgr.Lock(lockInfo)
|
lockId, err := stateMgr.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to lock state in Consul: %w", err)
|
return nil, fmt.Errorf("failed to lock state in Consul: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(parent error) error {
|
lockUnlock := func(parent error) error {
|
||||||
if err := stateMgr.Unlock(lockId); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockId); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
|
return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Grab the value
|
// Grab the value
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ type RemoteClient struct {
|
|||||||
sessionCancel context.CancelFunc
|
sessionCancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Get() (*remote.Payload, error) {
|
func (c *RemoteClient) Get(_ context.Context) (*remote.Payload, error) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ func (c *RemoteClient) Get() (*remote.Payload, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Put(data []byte) error {
|
func (c *RemoteClient) Put(_ context.Context, data []byte) error {
|
||||||
// The state can be stored in 4 different ways, based on the payload size
|
// The state can be stored in 4 different ways, based on the payload size
|
||||||
// and whether the user enabled gzip:
|
// and whether the user enabled gzip:
|
||||||
// - single entry mode with plain JSON: a single JSON is stored at
|
// - single entry mode with plain JSON: a single JSON is stored at
|
||||||
@@ -295,7 +295,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return store(payload)
|
return store(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(_ context.Context) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
@@ -361,7 +361,7 @@ func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
|
|||||||
return li, nil
|
return li, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(_ context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
@@ -551,7 +551,7 @@ func (c *RemoteClient) createSession() (string, error) {
|
|||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(_ context.Context, id string) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -141,12 +141,12 @@ func TestConsul_largeState(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = c.Put(payload)
|
err = c.Put(t.Context(), payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("could not put payload", err)
|
t.Fatal("could not put payload", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
remote, err := c.Get()
|
remote, err := c.Get(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ func TestConsul_largeState(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Deleting the state should remove all chunks
|
// Deleting the state should remove all chunks
|
||||||
err = c.Delete()
|
err = c.Delete(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -312,14 +312,14 @@ func TestConsul_destroyLock(t *testing.T) {
|
|||||||
clientA := s.(*remote.State).Client.(*RemoteClient)
|
clientA := s.(*remote.State).Client.(*RemoteClient)
|
||||||
|
|
||||||
info := statemgr.NewLockInfo()
|
info := statemgr.NewLockInfo()
|
||||||
id, err := clientA.Lock(info)
|
id, err := clientA.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockPath := clientA.Path + lockSuffix
|
lockPath := clientA.Path + lockSuffix
|
||||||
|
|
||||||
if err := clientA.Unlock(id); err != nil {
|
if err := clientA.Unlock(t.Context(), id); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,18 +335,18 @@ func TestConsul_destroyLock(t *testing.T) {
|
|||||||
clientB := s.(*remote.State).Client.(*RemoteClient)
|
clientB := s.(*remote.State).Client.(*RemoteClient)
|
||||||
|
|
||||||
info = statemgr.NewLockInfo()
|
info = statemgr.NewLockInfo()
|
||||||
id, err = clientA.Lock(info)
|
id, err = clientA.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := clientB.Unlock(id); err != nil {
|
if err := clientB.Unlock(t.Context(), id); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
testLock(clientA, lockPath)
|
testLock(clientA, lockPath)
|
||||||
|
|
||||||
err = clientA.Unlock(id)
|
err = clientA.Unlock(t.Context(), id)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("consul lock should have been lost")
|
t.Fatal("consul lock should have been lost")
|
||||||
@@ -383,7 +383,7 @@ func TestConsul_lostLock(t *testing.T) {
|
|||||||
|
|
||||||
info := statemgr.NewLockInfo()
|
info := statemgr.NewLockInfo()
|
||||||
info.Operation = "test-lost-lock"
|
info.Operation = "test-lost-lock"
|
||||||
id, err := sA.Lock(info)
|
id, err := sA.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -403,7 +403,7 @@ func TestConsul_lostLock(t *testing.T) {
|
|||||||
|
|
||||||
<-reLocked
|
<-reLocked
|
||||||
|
|
||||||
if err := sA.Unlock(id); err != nil {
|
if err := sA.Unlock(t.Context(), id); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,7 +435,7 @@ func TestConsul_lostLockConnection(t *testing.T) {
|
|||||||
|
|
||||||
info := statemgr.NewLockInfo()
|
info := statemgr.NewLockInfo()
|
||||||
info.Operation = "test-lost-lock-connection"
|
info.Operation = "test-lost-lock-connection"
|
||||||
id, err := s.Lock(info)
|
id, err := s.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -449,7 +449,7 @@ func TestConsul_lostLockConnection(t *testing.T) {
|
|||||||
<-dialed
|
<-dialed
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Unlock(id); err != nil {
|
if err := s.Unlock(t.Context(), id); err != nil {
|
||||||
t.Fatal("unlock error:", err)
|
t.Fatal("unlock error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ type Backend struct {
|
|||||||
encryption encryption.StateEncryption
|
encryption encryption.StateEncryption
|
||||||
credential *common.Credential
|
credential *common.Credential
|
||||||
|
|
||||||
cosContext context.Context
|
|
||||||
cosClient *cos.Client
|
cosClient *cos.Client
|
||||||
tagClient *tag.Client
|
tagClient *tag.Client
|
||||||
stsClient *sts.Client
|
stsClient *sts.Client
|
||||||
@@ -211,8 +210,7 @@ func (b *Backend) configure(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
b.cosContext = ctx
|
data := schema.FromContextBackendConfig(ctx)
|
||||||
data := schema.FromContextBackendConfig(b.cosContext)
|
|
||||||
|
|
||||||
b.region = data.Get("region").(string)
|
b.region = data.Get("region").(string)
|
||||||
b.bucket = data.Get("bucket").(string)
|
b.bucket = data.Get("bucket").(string)
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Workspaces returns a list of names for the workspaces
|
// Workspaces returns a list of names for the workspaces
|
||||||
func (b *Backend) Workspaces(context.Context) ([]string, error) {
|
func (b *Backend) Workspaces(ctx context.Context) ([]string, error) {
|
||||||
c, err := b.client("tencentcloud")
|
c, err := b.client("tencentcloud")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
obs, err := c.getBucket(b.prefix)
|
obs, err := c.getBucket(ctx, b.prefix)
|
||||||
log.Printf("[DEBUG] list all workspaces, objects: %v, error: %v", obs, err)
|
log.Printf("[DEBUG] list all workspaces, objects: %v, error: %v", obs, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -63,7 +63,7 @@ func (b *Backend) Workspaces(context.Context) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
|
// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
|
||||||
func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
func (b *Backend) DeleteWorkspace(ctx context.Context, name string, _ bool) error {
|
||||||
log.Printf("[DEBUG] delete workspace, workspace: %v", name)
|
log.Printf("[DEBUG] delete workspace, workspace: %v", name)
|
||||||
|
|
||||||
if name == backend.DefaultStateName || name == "" {
|
if name == backend.DefaultStateName || name == "" {
|
||||||
@@ -75,7 +75,7 @@ func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Delete()
|
return c.Delete(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateMgr manage the state, if the named state not exists, a new file will created
|
// StateMgr manage the state, if the named state not exists, a new file will created
|
||||||
@@ -107,21 +107,21 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
// take a lock on this state while we write it
|
// take a lock on this state while we write it
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockId, err := c.Lock(lockInfo)
|
lockId, err := c.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to lock cos state: %w", err)
|
return nil, fmt.Errorf("Failed to lock cos state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(e error) error {
|
lockUnlock := func(e error) error {
|
||||||
if err := stateMgr.Unlock(lockId); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockId); err != nil {
|
||||||
return fmt.Errorf(unlockErrMsg, err, lockId)
|
return fmt.Errorf(unlockErrMsg, err, lockId)
|
||||||
}
|
}
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the value
|
// Grab the value
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,6 @@ func (b *Backend) client(name string) (*remoteClient, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &remoteClient{
|
return &remoteClient{
|
||||||
cosContext: b.cosContext,
|
|
||||||
cosClient: b.cosClient,
|
cosClient: b.cosClient,
|
||||||
tagClient: b.tagClient,
|
tagClient: b.tagClient,
|
||||||
bucket: b.bucket,
|
bucket: b.bucket,
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ func setupBackend(t *testing.T, bucket, prefix, key string, encrypt bool) backen
|
|||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.putBucket()
|
err = c.putBucket(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ func teardownBackend(t *testing.T, b backend.Backend) {
|
|||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.deleteBucket(true)
|
err = c.deleteBucket(t.Context(), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ const (
|
|||||||
|
|
||||||
// RemoteClient implements the client of remote state
|
// RemoteClient implements the client of remote state
|
||||||
type remoteClient struct {
|
type remoteClient struct {
|
||||||
cosContext context.Context
|
|
||||||
cosClient *cos.Client
|
cosClient *cos.Client
|
||||||
tagClient *tag.Client
|
tagClient *tag.Client
|
||||||
|
|
||||||
@@ -43,10 +42,10 @@ type remoteClient struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get returns remote state file
|
// Get returns remote state file
|
||||||
func (c *remoteClient) Get() (*remote.Payload, error) {
|
func (c *remoteClient) Get(ctx context.Context) (*remote.Payload, error) {
|
||||||
log.Printf("[DEBUG] get remote state file %s", c.stateFile)
|
log.Printf("[DEBUG] get remote state file %s", c.stateFile)
|
||||||
|
|
||||||
exists, data, checksum, err := c.getObject(c.stateFile)
|
exists, data, checksum, err := c.getObject(ctx, c.stateFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -64,97 +63,97 @@ func (c *remoteClient) Get() (*remote.Payload, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put put state file to remote
|
// Put put state file to remote
|
||||||
func (c *remoteClient) Put(data []byte) error {
|
func (c *remoteClient) Put(ctx context.Context, data []byte) error {
|
||||||
log.Printf("[DEBUG] put remote state file %s", c.stateFile)
|
log.Printf("[DEBUG] put remote state file %s", c.stateFile)
|
||||||
|
|
||||||
return c.putObject(c.stateFile, data)
|
return c.putObject(ctx, c.stateFile, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete remote state file
|
// Delete delete remote state file
|
||||||
func (c *remoteClient) Delete() error {
|
func (c *remoteClient) Delete(ctx context.Context) error {
|
||||||
log.Printf("[DEBUG] delete remote state file %s", c.stateFile)
|
log.Printf("[DEBUG] delete remote state file %s", c.stateFile)
|
||||||
|
|
||||||
return c.deleteObject(c.stateFile)
|
return c.deleteObject(ctx, c.stateFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock lock remote state file for writing
|
// Lock lock remote state file for writing
|
||||||
func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *remoteClient) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
log.Printf("[DEBUG] lock remote state file %s", c.lockFile)
|
log.Printf("[DEBUG] lock remote state file %s", c.lockFile)
|
||||||
|
|
||||||
err := c.cosLock(c.bucket, c.lockFile)
|
err := c.cosLock(c.bucket, c.lockFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", c.lockError(err)
|
return "", c.lockError(ctx, err)
|
||||||
}
|
}
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(parent error) error {
|
lockUnlock := func(parent error) error {
|
||||||
if err := c.cosUnlock(c.bucket, c.lockFile); err != nil {
|
if err := c.cosUnlock(c.bucket, c.lockFile); err != nil {
|
||||||
return errors.Join(
|
return errors.Join(
|
||||||
fmt.Errorf("error unlocking cos state: %w", c.lockError(err)),
|
fmt.Errorf("error unlocking cos state: %w", c.lockError(ctx, err)),
|
||||||
parent,
|
parent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return parent
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
exists, _, _, err := c.getObject(c.lockFile)
|
exists, _, _, err := c.getObject(ctx, c.lockFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", lockUnlock(c.lockError(err))
|
return "", lockUnlock(c.lockError(ctx, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
return "", lockUnlock(c.lockError(fmt.Errorf("lock file %s exists", c.lockFile)))
|
return "", lockUnlock(c.lockError(ctx, fmt.Errorf("lock file %s exists", c.lockFile)))
|
||||||
}
|
}
|
||||||
|
|
||||||
info.Path = c.lockFile
|
info.Path = c.lockFile
|
||||||
data, err := json.Marshal(info)
|
data, err := json.Marshal(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", lockUnlock(c.lockError(err))
|
return "", lockUnlock(c.lockError(ctx, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
check := fmt.Sprintf("%x", md5.Sum(data))
|
check := fmt.Sprintf("%x", md5.Sum(data))
|
||||||
err = c.putObject(c.lockFile, data)
|
err = c.putObject(ctx, c.lockFile, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", lockUnlock(c.lockError(err))
|
return "", lockUnlock(c.lockError(ctx, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return check, lockUnlock(nil)
|
return check, lockUnlock(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock unlock remote state file
|
// Unlock unlock remote state file
|
||||||
func (c *remoteClient) Unlock(check string) error {
|
func (c *remoteClient) Unlock(ctx context.Context, check string) error {
|
||||||
log.Printf("[DEBUG] unlock remote state file %s", c.lockFile)
|
log.Printf("[DEBUG] unlock remote state file %s", c.lockFile)
|
||||||
|
|
||||||
info, err := c.lockInfo()
|
info, err := c.lockInfo(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.lockError(err)
|
return c.lockError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.ID != check {
|
if info.ID != check {
|
||||||
return c.lockError(fmt.Errorf("lock id mismatch, %v != %v", info.ID, check))
|
return c.lockError(ctx, fmt.Errorf("lock id mismatch, %v != %v", info.ID, check))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.deleteObject(c.lockFile)
|
err = c.deleteObject(ctx, c.lockFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.lockError(err)
|
return c.lockError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.cosUnlock(c.bucket, c.lockFile)
|
err = c.cosUnlock(c.bucket, c.lockFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.lockError(err)
|
return c.lockError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// lockError returns statemgr.LockError
|
// lockError returns statemgr.LockError
|
||||||
func (c *remoteClient) lockError(err error) *statemgr.LockError {
|
func (c *remoteClient) lockError(ctx context.Context, err error) *statemgr.LockError {
|
||||||
log.Printf("[DEBUG] failed to lock or unlock %s: %v", c.lockFile, err)
|
log.Printf("[DEBUG] failed to lock or unlock %s: %v", c.lockFile, err)
|
||||||
|
|
||||||
lockErr := &statemgr.LockError{
|
lockErr := &statemgr.LockError{
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
|
|
||||||
info, infoErr := c.lockInfo()
|
info, infoErr := c.lockInfo(ctx)
|
||||||
if infoErr != nil {
|
if infoErr != nil {
|
||||||
lockErr.Err = multierror.Append(lockErr.Err, infoErr)
|
lockErr.Err = multierror.Append(lockErr.Err, infoErr)
|
||||||
} else {
|
} else {
|
||||||
@@ -165,8 +164,8 @@ func (c *remoteClient) lockError(err error) *statemgr.LockError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// lockInfo returns LockInfo from lock file
|
// lockInfo returns LockInfo from lock file
|
||||||
func (c *remoteClient) lockInfo() (*statemgr.LockInfo, error) {
|
func (c *remoteClient) lockInfo(ctx context.Context) (*statemgr.LockInfo, error) {
|
||||||
exists, data, checksum, err := c.getObject(c.lockFile)
|
exists, data, checksum, err := c.getObject(ctx, c.lockFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -186,8 +185,8 @@ func (c *remoteClient) lockInfo() (*statemgr.LockInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getObject get remote object
|
// getObject get remote object
|
||||||
func (c *remoteClient) getObject(cosFile string) (exists bool, data []byte, checksum string, err error) {
|
func (c *remoteClient) getObject(ctx context.Context, cosFile string) (exists bool, data []byte, checksum string, err error) {
|
||||||
rsp, err := c.cosClient.Object.Get(c.cosContext, cosFile, nil)
|
rsp, err := c.cosClient.Object.Get(ctx, cosFile, nil)
|
||||||
if rsp == nil {
|
if rsp == nil {
|
||||||
log.Printf("[DEBUG] getObject %s: error: %v", cosFile, err)
|
log.Printf("[DEBUG] getObject %s: error: %v", cosFile, err)
|
||||||
err = fmt.Errorf("failed to open file at %v: %w", cosFile, err)
|
err = fmt.Errorf("failed to open file at %v: %w", cosFile, err)
|
||||||
@@ -231,7 +230,7 @@ func (c *remoteClient) getObject(cosFile string) (exists bool, data []byte, chec
|
|||||||
}
|
}
|
||||||
|
|
||||||
// putObject put object to remote
|
// putObject put object to remote
|
||||||
func (c *remoteClient) putObject(cosFile string, data []byte) error {
|
func (c *remoteClient) putObject(ctx context.Context, cosFile string, data []byte) error {
|
||||||
opt := &cos.ObjectPutOptions{
|
opt := &cos.ObjectPutOptions{
|
||||||
ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
|
ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
|
||||||
XCosMetaXXX: &http.Header{
|
XCosMetaXXX: &http.Header{
|
||||||
@@ -248,7 +247,7 @@ func (c *remoteClient) putObject(cosFile string, data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r := bytes.NewReader(data)
|
r := bytes.NewReader(data)
|
||||||
rsp, err := c.cosClient.Object.Put(c.cosContext, cosFile, r, opt)
|
rsp, err := c.cosClient.Object.Put(ctx, cosFile, r, opt)
|
||||||
if rsp == nil {
|
if rsp == nil {
|
||||||
log.Printf("[DEBUG] putObject %s: error: %v", cosFile, err)
|
log.Printf("[DEBUG] putObject %s: error: %v", cosFile, err)
|
||||||
return fmt.Errorf("failed to save file to %v: %w", cosFile, err)
|
return fmt.Errorf("failed to save file to %v: %w", cosFile, err)
|
||||||
@@ -264,8 +263,8 @@ func (c *remoteClient) putObject(cosFile string, data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deleteObject delete remote object
|
// deleteObject delete remote object
|
||||||
func (c *remoteClient) deleteObject(cosFile string) error {
|
func (c *remoteClient) deleteObject(ctx context.Context, cosFile string) error {
|
||||||
rsp, err := c.cosClient.Object.Delete(c.cosContext, cosFile)
|
rsp, err := c.cosClient.Object.Delete(ctx, cosFile)
|
||||||
if rsp == nil {
|
if rsp == nil {
|
||||||
log.Printf("[DEBUG] deleteObject %s: error: %v", cosFile, err)
|
log.Printf("[DEBUG] deleteObject %s: error: %v", cosFile, err)
|
||||||
return fmt.Errorf("failed to delete file %v: %w", cosFile, err)
|
return fmt.Errorf("failed to delete file %v: %w", cosFile, err)
|
||||||
@@ -285,8 +284,8 @@ func (c *remoteClient) deleteObject(cosFile string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getBucket list bucket by prefix
|
// getBucket list bucket by prefix
|
||||||
func (c *remoteClient) getBucket(prefix string) (obs []cos.Object, err error) {
|
func (c *remoteClient) getBucket(ctx context.Context, prefix string) (obs []cos.Object, err error) {
|
||||||
fs, rsp, err := c.cosClient.Bucket.Get(c.cosContext, &cos.BucketGetOptions{Prefix: prefix})
|
fs, rsp, err := c.cosClient.Bucket.Get(ctx, &cos.BucketGetOptions{Prefix: prefix})
|
||||||
if rsp == nil {
|
if rsp == nil {
|
||||||
log.Printf("[DEBUG] getBucket %s/%s: error: %v", c.bucket, prefix, err)
|
log.Printf("[DEBUG] getBucket %s/%s: error: %v", c.bucket, prefix, err)
|
||||||
err = fmt.Errorf("bucket %s not exists", c.bucket)
|
err = fmt.Errorf("bucket %s not exists", c.bucket)
|
||||||
@@ -308,8 +307,8 @@ func (c *remoteClient) getBucket(prefix string) (obs []cos.Object, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// putBucket create cos bucket
|
// putBucket create cos bucket
|
||||||
func (c *remoteClient) putBucket() error {
|
func (c *remoteClient) putBucket(ctx context.Context) error {
|
||||||
rsp, err := c.cosClient.Bucket.Put(c.cosContext, nil)
|
rsp, err := c.cosClient.Bucket.Put(ctx, nil)
|
||||||
if rsp == nil {
|
if rsp == nil {
|
||||||
log.Printf("[DEBUG] putBucket %s: error: %v", c.bucket, err)
|
log.Printf("[DEBUG] putBucket %s: error: %v", c.bucket, err)
|
||||||
return fmt.Errorf("failed to create bucket %v: %w", c.bucket, err)
|
return fmt.Errorf("failed to create bucket %v: %w", c.bucket, err)
|
||||||
@@ -329,9 +328,9 @@ func (c *remoteClient) putBucket() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deleteBucket delete cos bucket
|
// deleteBucket delete cos bucket
|
||||||
func (c *remoteClient) deleteBucket(recursive bool) error {
|
func (c *remoteClient) deleteBucket(ctx context.Context, recursive bool) error {
|
||||||
if recursive {
|
if recursive {
|
||||||
obs, err := c.getBucket("")
|
obs, err := c.getBucket(ctx, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "not exists") {
|
if strings.Contains(err.Error(), "not exists") {
|
||||||
return nil
|
return nil
|
||||||
@@ -340,14 +339,14 @@ func (c *remoteClient) deleteBucket(recursive bool) error {
|
|||||||
return fmt.Errorf("failed to empty bucket %v: %w", c.bucket, err)
|
return fmt.Errorf("failed to empty bucket %v: %w", c.bucket, err)
|
||||||
}
|
}
|
||||||
for _, v := range obs {
|
for _, v := range obs {
|
||||||
err := c.deleteObject(v.Key)
|
err := c.deleteObject(ctx, v.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to delete object with key %s: %w", v.Key, err)
|
return fmt.Errorf("failed to delete object with key %s: %w", v.Key, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rsp, err := c.cosClient.Bucket.Delete(c.cosContext)
|
rsp, err := c.cosClient.Bucket.Delete(ctx)
|
||||||
if rsp == nil {
|
if rsp == nil {
|
||||||
log.Printf("[DEBUG] deleteBucket %s: error: %v", c.bucket, err)
|
log.Printf("[DEBUG] deleteBucket %s: error: %v", c.bucket, err)
|
||||||
return fmt.Errorf("failed to delete bucket %v: %w", c.bucket, err)
|
return fmt.Errorf("failed to delete bucket %v: %w", c.bucket, err)
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ type Backend struct {
|
|||||||
encryption encryption.StateEncryption
|
encryption encryption.StateEncryption
|
||||||
|
|
||||||
storageClient *storage.Client
|
storageClient *storage.Client
|
||||||
storageContext context.Context
|
|
||||||
|
|
||||||
bucketName string
|
bucketName string
|
||||||
prefix string
|
prefix string
|
||||||
@@ -131,13 +130,7 @@ func (b *Backend) configure(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ctx is a background context with the backend config added.
|
data := schema.FromContextBackendConfig(ctx)
|
||||||
// Since no context is passed to remoteClient.Get(), .Lock(), etc. but
|
|
||||||
// one is required for calling the GCP API, we're holding on to this
|
|
||||||
// context here and re-use it later.
|
|
||||||
b.storageContext = ctx
|
|
||||||
|
|
||||||
data := schema.FromContextBackendConfig(b.storageContext)
|
|
||||||
|
|
||||||
b.bucketName = data.Get("bucket").(string)
|
b.bucketName = data.Get("bucket").(string)
|
||||||
b.prefix = strings.TrimLeft(data.Get("prefix").(string), "/")
|
b.prefix = strings.TrimLeft(data.Get("prefix").(string), "/")
|
||||||
@@ -219,7 +212,7 @@ func (b *Backend) configure(ctx context.Context) error {
|
|||||||
endpoint := option.WithEndpoint(storageEndpoint.(string))
|
endpoint := option.WithEndpoint(storageEndpoint.(string))
|
||||||
opts = append(opts, endpoint)
|
opts = append(opts, endpoint)
|
||||||
}
|
}
|
||||||
client, err := storage.NewClient(b.storageContext, opts...)
|
client, err := storage.NewClient(ctx, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("storage.NewClient() failed: %w", err)
|
return fmt.Errorf("storage.NewClient() failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ const (
|
|||||||
|
|
||||||
// Workspaces returns a list of names for the workspaces found on GCS. The default
|
// Workspaces returns a list of names for the workspaces found on GCS. The default
|
||||||
// state is always returned as the first element in the slice.
|
// state is always returned as the first element in the slice.
|
||||||
func (b *Backend) Workspaces(context.Context) ([]string, error) {
|
func (b *Backend) Workspaces(ctx context.Context) ([]string, error) {
|
||||||
states := []string{backend.DefaultStateName}
|
states := []string{backend.DefaultStateName}
|
||||||
|
|
||||||
bucket := b.storageClient.Bucket(b.bucketName)
|
bucket := b.storageClient.Bucket(b.bucketName)
|
||||||
objs := bucket.Objects(b.storageContext, &storage.Query{
|
objs := bucket.Objects(ctx, &storage.Query{
|
||||||
Delimiter: "/",
|
Delimiter: "/",
|
||||||
Prefix: b.prefix,
|
Prefix: b.prefix,
|
||||||
})
|
})
|
||||||
@@ -61,7 +61,7 @@ func (b *Backend) Workspaces(context.Context) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
|
// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
|
||||||
func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
func (b *Backend) DeleteWorkspace(ctx context.Context, name string, _ bool) error {
|
||||||
if name == backend.DefaultStateName {
|
if name == backend.DefaultStateName {
|
||||||
return fmt.Errorf("cowardly refusing to delete the %q state", name)
|
return fmt.Errorf("cowardly refusing to delete the %q state", name)
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Delete()
|
return c.Delete(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// client returns a remoteClient for the named state.
|
// client returns a remoteClient for the named state.
|
||||||
@@ -81,7 +81,6 @@ func (b *Backend) client(name string) (*remoteClient, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &remoteClient{
|
return &remoteClient{
|
||||||
storageContext: b.storageContext,
|
|
||||||
storageClient: b.storageClient,
|
storageClient: b.storageClient,
|
||||||
bucketName: b.bucketName,
|
bucketName: b.bucketName,
|
||||||
stateFilePath: b.stateFile(name),
|
stateFilePath: b.stateFile(name),
|
||||||
@@ -93,7 +92,7 @@ func (b *Backend) client(name string) (*remoteClient, error) {
|
|||||||
|
|
||||||
// StateMgr reads and returns the named state from GCS. If the named state does
|
// StateMgr reads and returns the named state from GCS. If the named state does
|
||||||
// not yet exist, a new state file is created.
|
// not yet exist, a new state file is created.
|
||||||
func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error) {
|
func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, error) {
|
||||||
c, err := b.client(name)
|
c, err := b.client(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -102,7 +101,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
st := remote.NewState(c, b.encryption)
|
st := remote.NewState(c, b.encryption)
|
||||||
|
|
||||||
// Grab the value
|
// Grab the value
|
||||||
if err := st.RefreshState(); err != nil {
|
if err := st.RefreshState(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,14 +110,14 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
|
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockID, err := st.Lock(lockInfo)
|
lockID, err := st.Lock(ctx, lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
unlock := func(baseErr error) error {
|
unlock := func(baseErr error) error {
|
||||||
if err := st.Unlock(lockID); err != nil {
|
if err := st.Unlock(ctx, lockID); err != nil {
|
||||||
const unlockErrMsg = `%v
|
const unlockErrMsg = `%v
|
||||||
Additionally, unlocking the state file on Google Cloud Storage failed:
|
Additionally, unlocking the state file on Google Cloud Storage failed:
|
||||||
|
|
||||||
@@ -138,7 +137,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
if err := st.WriteState(states.NewState()); err != nil {
|
if err := st.WriteState(states.NewState()); err != nil {
|
||||||
return nil, unlock(err)
|
return nil, unlock(err)
|
||||||
}
|
}
|
||||||
if err := st.PersistState(nil); err != nil {
|
if err := st.PersistState(ctx, nil); err != nil {
|
||||||
return nil, unlock(err)
|
return nil, unlock(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ func setupBackend(t *testing.T, bucket, prefix, key, kmsName string) backend.Bac
|
|||||||
|
|
||||||
// create the bucket if it doesn't exist
|
// create the bucket if it doesn't exist
|
||||||
bkt := be.storageClient.Bucket(bucket)
|
bkt := be.storageClient.Bucket(bucket)
|
||||||
_, err := bkt.Attrs(be.storageContext)
|
_, err := bkt.Attrs(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != storage.ErrBucketNotExist {
|
if err != storage.ErrBucketNotExist {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -253,7 +253,7 @@ func setupBackend(t *testing.T, bucket, prefix, key, kmsName string) backend.Bac
|
|||||||
attrs := &storage.BucketAttrs{
|
attrs := &storage.BucketAttrs{
|
||||||
Location: os.Getenv("GOOGLE_REGION"),
|
Location: os.Getenv("GOOGLE_REGION"),
|
||||||
}
|
}
|
||||||
err := bkt.Create(be.storageContext, projectID, attrs)
|
err := bkt.Create(t.Context(), projectID, attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -383,7 +383,7 @@ func teardownBackend(t *testing.T, be backend.Backend, prefix string) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("be is a %T, want a *gcsBackend", be)
|
t.Fatalf("be is a %T, want a *gcsBackend", be)
|
||||||
}
|
}
|
||||||
ctx := gcsBE.storageContext
|
ctx := t.Context()
|
||||||
|
|
||||||
bucket := gcsBE.storageClient.Bucket(gcsBE.bucketName)
|
bucket := gcsBE.storageClient.Bucket(gcsBE.bucketName)
|
||||||
objs := bucket.Objects(ctx, nil)
|
objs := bucket.Objects(ctx, nil)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package gcs
|
package gcs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -16,14 +17,12 @@ import (
|
|||||||
multierror "github.com/hashicorp/go-multierror"
|
multierror "github.com/hashicorp/go-multierror"
|
||||||
"github.com/opentofu/opentofu/internal/states/remote"
|
"github.com/opentofu/opentofu/internal/states/remote"
|
||||||
"github.com/opentofu/opentofu/internal/states/statemgr"
|
"github.com/opentofu/opentofu/internal/states/statemgr"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// remoteClient is used by "state/remote".State to read and write
|
// remoteClient is used by "state/remote".State to read and write
|
||||||
// blobs representing state.
|
// blobs representing state.
|
||||||
// Implements "state/remote".ClientLocker
|
// Implements "state/remote".ClientLocker
|
||||||
type remoteClient struct {
|
type remoteClient struct {
|
||||||
storageContext context.Context
|
|
||||||
storageClient *storage.Client
|
storageClient *storage.Client
|
||||||
bucketName string
|
bucketName string
|
||||||
stateFilePath string
|
stateFilePath string
|
||||||
@@ -32,8 +31,8 @@ type remoteClient struct {
|
|||||||
kmsKeyName string
|
kmsKeyName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *remoteClient) Get() (payload *remote.Payload, err error) {
|
func (c *remoteClient) Get(ctx context.Context) (payload *remote.Payload, err error) {
|
||||||
stateFileReader, err := c.stateFile().NewReader(c.storageContext)
|
stateFileReader, err := c.stateFile().NewReader(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == storage.ErrObjectNotExist {
|
if err == storage.ErrObjectNotExist {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -48,7 +47,7 @@ func (c *remoteClient) Get() (payload *remote.Payload, err error) {
|
|||||||
return nil, fmt.Errorf("Failed to read state file from %v: %w", c.stateFileURL(), err)
|
return nil, fmt.Errorf("Failed to read state file from %v: %w", c.stateFileURL(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stateFileAttrs, err := c.stateFile().Attrs(c.storageContext)
|
stateFileAttrs, err := c.stateFile().Attrs(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to read state file attrs from %v: %w", c.stateFileURL(), err)
|
return nil, fmt.Errorf("Failed to read state file attrs from %v: %w", c.stateFileURL(), err)
|
||||||
}
|
}
|
||||||
@@ -61,9 +60,9 @@ func (c *remoteClient) Get() (payload *remote.Payload, err error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *remoteClient) Put(data []byte) error {
|
func (c *remoteClient) Put(ctx context.Context, data []byte) error {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
stateFileWriter := c.stateFile().NewWriter(c.storageContext)
|
stateFileWriter := c.stateFile().NewWriter(ctx)
|
||||||
if len(c.kmsKeyName) > 0 {
|
if len(c.kmsKeyName) > 0 {
|
||||||
stateFileWriter.KMSKeyName = c.kmsKeyName
|
stateFileWriter.KMSKeyName = c.kmsKeyName
|
||||||
}
|
}
|
||||||
@@ -79,8 +78,8 @@ func (c *remoteClient) Put(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *remoteClient) Delete() error {
|
func (c *remoteClient) Delete(ctx context.Context) error {
|
||||||
if err := c.stateFile().Delete(c.storageContext); err != nil {
|
if err := c.stateFile().Delete(ctx); err != nil {
|
||||||
return fmt.Errorf("Failed to delete state file %v: %w", c.stateFileURL(), err)
|
return fmt.Errorf("Failed to delete state file %v: %w", c.stateFileURL(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +88,7 @@ func (c *remoteClient) Delete() error {
|
|||||||
|
|
||||||
// Lock writes to a lock file, ensuring file creation. Returns the generation
|
// Lock writes to a lock file, ensuring file creation. Returns the generation
|
||||||
// number, which must be passed to Unlock().
|
// number, which must be passed to Unlock().
|
||||||
func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *remoteClient) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
// update the path we're using
|
// update the path we're using
|
||||||
// we can't set the ID until the info is written
|
// we can't set the ID until the info is written
|
||||||
info.Path = c.lockFileURL()
|
info.Path = c.lockFileURL()
|
||||||
@@ -100,7 +99,7 @@ func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lockFile := c.lockFile()
|
lockFile := c.lockFile()
|
||||||
w := lockFile.If(storage.Conditions{DoesNotExist: true}).NewWriter(c.storageContext)
|
w := lockFile.If(storage.Conditions{DoesNotExist: true}).NewWriter(ctx)
|
||||||
err = func() error {
|
err = func() error {
|
||||||
if _, err := w.Write(infoJson); err != nil {
|
if _, err := w.Write(infoJson); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -109,7 +108,7 @@ func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", c.lockError(fmt.Errorf("writing %q failed: %w", c.lockFileURL(), err))
|
return "", c.lockError(ctx, fmt.Errorf("writing %q failed: %w", c.lockFileURL(), err))
|
||||||
}
|
}
|
||||||
|
|
||||||
info.ID = strconv.FormatInt(w.Attrs().Generation, 10)
|
info.ID = strconv.FormatInt(w.Attrs().Generation, 10)
|
||||||
@@ -117,25 +116,25 @@ func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
return info.ID, nil
|
return info.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *remoteClient) Unlock(id string) error {
|
func (c *remoteClient) Unlock(ctx context.Context, id string) error {
|
||||||
gen, err := strconv.ParseInt(id, 10, 64)
|
gen, err := strconv.ParseInt(id, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Lock ID should be numerical value, got '%s'", id)
|
return fmt.Errorf("Lock ID should be numerical value, got '%s'", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.lockFile().If(storage.Conditions{GenerationMatch: gen}).Delete(c.storageContext); err != nil {
|
if err := c.lockFile().If(storage.Conditions{GenerationMatch: gen}).Delete(ctx); err != nil {
|
||||||
return c.lockError(err)
|
return c.lockError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *remoteClient) lockError(err error) *statemgr.LockError {
|
func (c *remoteClient) lockError(ctx context.Context, err error) *statemgr.LockError {
|
||||||
lockErr := &statemgr.LockError{
|
lockErr := &statemgr.LockError{
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
|
|
||||||
info, infoErr := c.lockInfo()
|
info, infoErr := c.lockInfo(ctx)
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(infoErr, storage.ErrObjectNotExist):
|
case errors.Is(infoErr, storage.ErrObjectNotExist):
|
||||||
// Race condition - file exists initially but then has been deleted by other process
|
// Race condition - file exists initially but then has been deleted by other process
|
||||||
@@ -150,8 +149,8 @@ func (c *remoteClient) lockError(err error) *statemgr.LockError {
|
|||||||
|
|
||||||
// lockInfo reads the lock file, parses its contents and returns the parsed
|
// lockInfo reads the lock file, parses its contents and returns the parsed
|
||||||
// LockInfo struct.
|
// LockInfo struct.
|
||||||
func (c *remoteClient) lockInfo() (*statemgr.LockInfo, error) {
|
func (c *remoteClient) lockInfo(ctx context.Context) (*statemgr.LockInfo, error) {
|
||||||
r, err := c.lockFile().NewReader(c.storageContext)
|
r, err := c.lockFile().NewReader(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -170,7 +169,7 @@ func (c *remoteClient) lockInfo() (*statemgr.LockInfo, error) {
|
|||||||
// We use the Generation as the ID, so overwrite the ID in the json.
|
// We use the Generation as the ID, so overwrite the ID in the json.
|
||||||
// This can't be written into the Info, since the generation isn't known
|
// This can't be written into the Info, since the generation isn't known
|
||||||
// until it's written.
|
// until it's written.
|
||||||
attrs, err := c.lockFile().Attrs(c.storageContext)
|
attrs, err := c.lockFile().Attrs(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -43,7 +44,7 @@ type httpClient struct {
|
|||||||
jsonLockInfo []byte
|
jsonLockInfo []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) httpRequest(method string, url *url.URL, data []byte, what string) (*http.Response, error) {
|
func (c *httpClient) httpRequest(ctx context.Context, method string, url *url.URL, data []byte, what string) (*http.Response, error) {
|
||||||
var body interface{}
|
var body interface{}
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
body = data
|
body = data
|
||||||
@@ -52,7 +53,7 @@ func (c *httpClient) httpRequest(method string, url *url.URL, data []byte, what
|
|||||||
log.Printf("[DEBUG] Executing HTTP remote state request for: %q", what)
|
log.Printf("[DEBUG] Executing HTTP remote state request for: %q", what)
|
||||||
|
|
||||||
// Create the request
|
// Create the request
|
||||||
req, err := retryablehttp.NewRequest(method, url.String(), body)
|
req, err := retryablehttp.NewRequestWithContext(ctx, method, url.String(), body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to make %s HTTP request: %w", what, err)
|
return nil, fmt.Errorf("Failed to make %s HTTP request: %w", what, err)
|
||||||
}
|
}
|
||||||
@@ -89,14 +90,14 @@ func (c *httpClient) httpRequest(method string, url *url.URL, data []byte, what
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *httpClient) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
if c.LockURL == nil {
|
if c.LockURL == nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
c.lockID = ""
|
c.lockID = ""
|
||||||
|
|
||||||
jsonLockInfo := info.Marshal()
|
jsonLockInfo := info.Marshal()
|
||||||
resp, err := c.httpRequest(c.LockMethod, c.LockURL, jsonLockInfo, "lock")
|
resp, err := c.httpRequest(ctx, c.LockMethod, c.LockURL, jsonLockInfo, "lock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -139,7 +140,7 @@ func (c *httpClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Unlock(id string) error {
|
func (c *httpClient) Unlock(ctx context.Context, id string) error {
|
||||||
if c.UnlockURL == nil {
|
if c.UnlockURL == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -162,7 +163,7 @@ func (c *httpClient) Unlock(id string) error {
|
|||||||
|
|
||||||
lockInfo.ID = id
|
lockInfo.ID = id
|
||||||
|
|
||||||
resp, err := c.httpRequest(c.UnlockMethod, c.UnlockURL, lockInfo.Marshal(), "unlock")
|
resp, err := c.httpRequest(ctx, c.UnlockMethod, c.UnlockURL, lockInfo.Marshal(), "unlock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -177,8 +178,8 @@ func (c *httpClient) Unlock(id string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Get() (*remote.Payload, error) {
|
func (c *httpClient) Get(ctx context.Context) (*remote.Payload, error) {
|
||||||
resp, err := c.httpRequest(http.MethodGet, c.URL, nil, "get state")
|
resp, err := c.httpRequest(ctx, http.MethodGet, c.URL, nil, "get state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -240,7 +241,7 @@ func (c *httpClient) Get() (*remote.Payload, error) {
|
|||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Put(data []byte) error {
|
func (c *httpClient) Put(ctx context.Context, data []byte) error {
|
||||||
// Copy the target URL
|
// Copy the target URL
|
||||||
base := *c.URL
|
base := *c.URL
|
||||||
|
|
||||||
@@ -263,7 +264,7 @@ func (c *httpClient) Put(data []byte) error {
|
|||||||
if c.UpdateMethod != "" {
|
if c.UpdateMethod != "" {
|
||||||
method = c.UpdateMethod
|
method = c.UpdateMethod
|
||||||
}
|
}
|
||||||
resp, err := c.httpRequest(method, &base, data, "upload state")
|
resp, err := c.httpRequest(ctx, method, &base, data, "upload state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -279,9 +280,9 @@ func (c *httpClient) Put(data []byte) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Delete() error {
|
func (c *httpClient) Delete(ctx context.Context) error {
|
||||||
// Make the request
|
// Make the request
|
||||||
resp, err := c.httpRequest(http.MethodDelete, c.URL, nil, "delete state")
|
resp, err := c.httpRequest(ctx, http.MethodDelete, c.URL, nil, "delete state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ func TestHttpClient_Unlock(t *testing.T) {
|
|||||||
jsonLockInfo: tt.jsonLockInfo,
|
jsonLockInfo: tt.jsonLockInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.Unlock(tt.lockID)
|
err = client.Unlock(t.Context(), tt.lockID)
|
||||||
if tt.expectedErrorMsg != nil && err == nil {
|
if tt.expectedErrorMsg != nil && err == nil {
|
||||||
// no expected error
|
// no expected error
|
||||||
t.Errorf("UnLock() no expected error = %v", tt.expectedErrorMsg)
|
t.Errorf("UnLock() no expected error = %v", tt.expectedErrorMsg)
|
||||||
@@ -474,7 +474,7 @@ func TestHttpClient_lock(t *testing.T) {
|
|||||||
Client: retryablehttp.NewClient(),
|
Client: retryablehttp.NewClient(),
|
||||||
}
|
}
|
||||||
|
|
||||||
lockID, err := client.Lock(tt.lockInfo)
|
lockID, err := client.Lock(t.Context(), tt.lockInfo)
|
||||||
if tt.expectedErrorMsg != nil && err == nil {
|
if tt.expectedErrorMsg != nil && err == nil {
|
||||||
// no expected error
|
// no expected error
|
||||||
t.Errorf("Lock() no expected error = %v", tt.expectedErrorMsg)
|
t.Errorf("Lock() no expected error = %v", tt.expectedErrorMsg)
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ func TestMTLSServer_NoCertFails(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opErr := new(net.OpError)
|
opErr := new(net.OpError)
|
||||||
err = sm.RefreshState()
|
err = sm.RefreshState(t.Context())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected error when refreshing state without a client cert")
|
t.Fatal("expected error when refreshing state without a client cert")
|
||||||
}
|
}
|
||||||
@@ -358,7 +358,7 @@ func TestMTLSServer_WithCertPasses(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error fetching StateMgr with %s: %v", backend.DefaultStateName, err)
|
t.Fatalf("unexpected error fetching StateMgr with %s: %v", backend.DefaultStateName, err)
|
||||||
}
|
}
|
||||||
if err = sm.RefreshState(); err != nil {
|
if err = sm.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error calling RefreshState: %v", err)
|
t.Fatalf("unexpected error calling RefreshState: %v", err)
|
||||||
}
|
}
|
||||||
state := sm.State()
|
state := sm.State()
|
||||||
@@ -399,10 +399,10 @@ func TestMTLSServer_WithCertPasses(t *testing.T) {
|
|||||||
if err = sm.WriteState(state); err != nil {
|
if err = sm.WriteState(state); err != nil {
|
||||||
t.Errorf("error writing state: %v", err)
|
t.Errorf("error writing state: %v", err)
|
||||||
}
|
}
|
||||||
if err = sm.PersistState(nil); err != nil {
|
if err = sm.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Errorf("error persisting state: %v", err)
|
t.Errorf("error persisting state: %v", err)
|
||||||
}
|
}
|
||||||
if err = sm.RefreshState(); err != nil {
|
if err = sm.RefreshState(t.Context()); err != nil {
|
||||||
t.Errorf("error refreshing state: %v", err)
|
t.Errorf("error refreshing state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,14 +139,14 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
// take a lock and create a new state if it doesn't exist.
|
// take a lock and create a new state if it doesn't exist.
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockID, err := s.Lock(lockInfo)
|
lockID, err := s.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to lock inmem state: %w", err)
|
return nil, fmt.Errorf("failed to lock inmem state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(parent error) error {
|
lockUnlock := func(parent error) error {
|
||||||
if err := s.Unlock(lockID); err != nil {
|
if err := s.Unlock(context.TODO(), lockID); err != nil {
|
||||||
return errors.Join(
|
return errors.Join(
|
||||||
fmt.Errorf("error unlocking inmem state: %w", err),
|
fmt.Errorf("error unlocking inmem state: %w", err),
|
||||||
parent,
|
parent,
|
||||||
@@ -161,7 +161,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(context.TODO(), nil); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,11 +88,11 @@ func TestRemoteState(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package inmem
|
package inmem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/states/remote"
|
"github.com/opentofu/opentofu/internal/states/remote"
|
||||||
@@ -19,7 +20,7 @@ type RemoteClient struct {
|
|||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Get() (*remote.Payload, error) {
|
func (c *RemoteClient) Get(_ context.Context) (*remote.Payload, error) {
|
||||||
if c.Data == nil {
|
if c.Data == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -30,7 +31,7 @@ func (c *RemoteClient) Get() (*remote.Payload, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Put(data []byte) error {
|
func (c *RemoteClient) Put(_ context.Context, data []byte) error {
|
||||||
md5 := md5.Sum(data)
|
md5 := md5.Sum(data)
|
||||||
|
|
||||||
c.Data = data
|
c.Data = data
|
||||||
@@ -38,15 +39,15 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(_ context.Context) error {
|
||||||
c.Data = nil
|
c.Data = nil
|
||||||
c.MD5 = nil
|
c.MD5 = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(_ context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
return locks.lock(c.Name, info)
|
return locks.lock(c.Name, info)
|
||||||
}
|
}
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(_ context.Context, id string) error {
|
||||||
return locks.unlock(c.Name, id)
|
return locks.unlock(c.Name, id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func (b *Backend) Workspaces(ctx context.Context) ([]string, error) {
|
|||||||
return states, nil
|
return states, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
func (b *Backend) DeleteWorkspace(ctx context.Context, name string, _ bool) error {
|
||||||
if name == backend.DefaultStateName || name == "" {
|
if name == backend.DefaultStateName || name == "" {
|
||||||
return fmt.Errorf("can't delete default state")
|
return fmt.Errorf("can't delete default state")
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.Delete()
|
return client.Delete(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error) {
|
func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error) {
|
||||||
@@ -87,7 +87,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
stateMgr := remote.NewState(c, b.encryption)
|
stateMgr := remote.NewState(c, b.encryption)
|
||||||
|
|
||||||
// Grab the value
|
// Grab the value
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
|
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockID, err := stateMgr.Lock(lockInfo)
|
lockID, err := stateMgr.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
unlock := func(baseErr error) error {
|
unlock := func(baseErr error) error {
|
||||||
if err := stateMgr.Unlock(lockID); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockID); err != nil {
|
||||||
const unlockErrMsg = `%v
|
const unlockErrMsg = `%v
|
||||||
Additionally, unlocking the state in Kubernetes failed:
|
Additionally, unlocking the state in Kubernetes failed:
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ func (b *Backend) StateMgr(_ context.Context, name string) (statemgr.Full, error
|
|||||||
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
||||||
return nil, unlock(err)
|
return nil, unlock(err)
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
return nil, unlock(err)
|
return nil, unlock(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ func TestBackendLocksSoak(t *testing.T) {
|
|||||||
li.Who = fmt.Sprintf("client-%v", n)
|
li.Who = fmt.Sprintf("client-%v", n)
|
||||||
|
|
||||||
for i := 0; i < lockAttempts; i++ {
|
for i := 0; i < lockAttempts; i++ {
|
||||||
id, err := locker.Lock(li)
|
id, err := locker.Lock(t.Context(), li)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ func TestBackendLocksSoak(t *testing.T) {
|
|||||||
// hold onto the lock for a little bit
|
// hold onto the lock for a little bit
|
||||||
time.Sleep(time.Duration(rand.Intn(10)) * time.Microsecond)
|
time.Sleep(time.Duration(rand.Intn(10)) * time.Microsecond)
|
||||||
|
|
||||||
err = locker.Unlock(id)
|
err = locker.Unlock(t.Context(), id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to unlock: %v", err)
|
t.Errorf("failed to unlock: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ type RemoteClient struct {
|
|||||||
workspace string
|
workspace string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
|
func (c *RemoteClient) Get(ctx context.Context) (payload *remote.Payload, err error) {
|
||||||
secretName, err := c.createSecretName()
|
secretName, err := c.createSecretName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
secret, err := c.kubernetesSecretClient.Get(context.Background(), secretName, metav1.GetOptions{})
|
secret, err := c.kubernetesSecretClient.Get(ctx, secretName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if k8serrors.IsNotFound(err) {
|
if k8serrors.IsNotFound(err) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -83,8 +83,7 @@ func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Put(data []byte) error {
|
func (c *RemoteClient) Put(ctx context.Context, data []byte) error {
|
||||||
ctx := context.Background()
|
|
||||||
secretName, err := c.createSecretName()
|
secretName, err := c.createSecretName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -95,7 +94,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
secret, err := c.getSecret(secretName)
|
secret, err := c.getSecret(ctx, secretName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !k8serrors.IsNotFound(err) {
|
if !k8serrors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
@@ -124,13 +123,13 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete the state secret
|
// Delete the state secret
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(ctx context.Context) error {
|
||||||
secretName, err := c.createSecretName()
|
secretName, err := c.createSecretName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.deleteSecret(secretName)
|
err = c.deleteSecret(ctx, secretName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !k8serrors.IsNotFound(err) {
|
if !k8serrors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
@@ -142,7 +141,7 @@ func (c *RemoteClient) Delete() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.deleteLease(leaseName)
|
err = c.deleteLease(ctx, leaseName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !k8serrors.IsNotFound(err) {
|
if !k8serrors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
@@ -151,14 +150,13 @@ func (c *RemoteClient) Delete() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
ctx := context.Background()
|
|
||||||
leaseName, err := c.createLeaseName()
|
leaseName, err := c.createLeaseName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
lease, err := c.getLease(leaseName)
|
lease, err := c.getLease(ctx, leaseName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !k8serrors.IsNotFound(err) {
|
if !k8serrors.IsNotFound(err) {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -213,13 +211,13 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
return info.ID, err
|
return info.ID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(ctx context.Context, id string) error {
|
||||||
leaseName, err := c.createLeaseName()
|
leaseName, err := c.createLeaseName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lease, err := c.getLease(leaseName)
|
lease, err := c.getLease(ctx, leaseName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -242,7 +240,7 @@ func (c *RemoteClient) Unlock(id string) error {
|
|||||||
lease.Spec.HolderIdentity = nil
|
lease.Spec.HolderIdentity = nil
|
||||||
removeLockInfo(lease)
|
removeLockInfo(lease)
|
||||||
|
|
||||||
_, err = c.kubernetesLeaseClient.Update(context.Background(), lease, metav1.UpdateOptions{})
|
_, err = c.kubernetesLeaseClient.Update(ctx, lease, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lockErr.Err = err
|
lockErr.Err = err
|
||||||
return lockErr
|
return lockErr
|
||||||
@@ -283,16 +281,16 @@ func (c *RemoteClient) getLabels() map[string]string {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) getSecret(name string) (*unstructured.Unstructured, error) {
|
func (c *RemoteClient) getSecret(ctx context.Context, name string) (*unstructured.Unstructured, error) {
|
||||||
return c.kubernetesSecretClient.Get(context.Background(), name, metav1.GetOptions{})
|
return c.kubernetesSecretClient.Get(ctx, name, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) getLease(name string) (*coordinationv1.Lease, error) {
|
func (c *RemoteClient) getLease(ctx context.Context, name string) (*coordinationv1.Lease, error) {
|
||||||
return c.kubernetesLeaseClient.Get(context.Background(), name, metav1.GetOptions{})
|
return c.kubernetesLeaseClient.Get(ctx, name, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) deleteSecret(name string) error {
|
func (c *RemoteClient) deleteSecret(ctx context.Context, name string) error {
|
||||||
secret, err := c.getSecret(name)
|
secret, err := c.getSecret(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -305,11 +303,11 @@ func (c *RemoteClient) deleteSecret(name string) error {
|
|||||||
|
|
||||||
delProp := metav1.DeletePropagationBackground
|
delProp := metav1.DeletePropagationBackground
|
||||||
delOps := metav1.DeleteOptions{PropagationPolicy: &delProp}
|
delOps := metav1.DeleteOptions{PropagationPolicy: &delProp}
|
||||||
return c.kubernetesSecretClient.Delete(context.Background(), name, delOps)
|
return c.kubernetesSecretClient.Delete(ctx, name, delOps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) deleteLease(name string) error {
|
func (c *RemoteClient) deleteLease(ctx context.Context, name string) error {
|
||||||
secret, err := c.getLease(name)
|
secret, err := c.getLease(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -322,7 +320,7 @@ func (c *RemoteClient) deleteLease(name string) error {
|
|||||||
|
|
||||||
delProp := metav1.DeletePropagationBackground
|
delProp := metav1.DeletePropagationBackground
|
||||||
delOps := metav1.DeleteOptions{PropagationPolicy: &delProp}
|
delOps := metav1.DeleteOptions{PropagationPolicy: &delProp}
|
||||||
return c.kubernetesLeaseClient.Delete(context.Background(), name, delOps)
|
return c.kubernetesLeaseClient.Delete(ctx, name, delOps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) createSecretName() (string, error) {
|
func (c *RemoteClient) createSecretName() (string, error) {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err := s1.Lock(info)
|
lockID, err := s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
t.Fatal("failed to get default state to force unlock:", err)
|
t.Fatal("failed to get default state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s2.Unlock(lockID); err != nil {
|
if err := s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock default state")
|
t.Fatal("failed to force-unlock default state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err = s1.Lock(info)
|
lockID, err = s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
t.Fatal("failed to get named state to force unlock:", err)
|
t.Fatal("failed to get named state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock named state")
|
t.Fatal("failed to force-unlock named state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func (b *Backend) Workspaces(context.Context) ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
func (b *Backend) DeleteWorkspace(ctx context.Context, name string, _ bool) error {
|
||||||
if name == backend.DefaultStateName || name == "" {
|
if name == backend.DefaultStateName || name == "" {
|
||||||
return fmt.Errorf("can't delete default state")
|
return fmt.Errorf("can't delete default state")
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return client.Delete()
|
return client.Delete(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, error) {
|
func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, error) {
|
||||||
@@ -141,21 +141,21 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
// take a lock on this state while we write it
|
// take a lock on this state while we write it
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockId, err := client.Lock(lockInfo)
|
lockId, err := client.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to lock OSS state: %w", err)
|
return nil, fmt.Errorf("failed to lock OSS state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(e error) error {
|
lockUnlock := func(e error) error {
|
||||||
if err := stateMgr.Unlock(lockId); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockId); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(stateUnlockError), lockId, err)
|
return fmt.Errorf(strings.TrimSpace(stateUnlockError), lockId, err)
|
||||||
}
|
}
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the value
|
// Grab the value
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package oss
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -55,7 +56,7 @@ type RemoteClient struct {
|
|||||||
otsTable string
|
otsTable string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
|
func (c *RemoteClient) Get(_ context.Context) (payload *remote.Payload, err error) {
|
||||||
deadline := time.Now().Add(consistencyRetryTimeout)
|
deadline := time.Now().Add(consistencyRetryTimeout)
|
||||||
|
|
||||||
// If we have a checksum, and the returned payload doesn't match, we retry
|
// If we have a checksum, and the returned payload doesn't match, we retry
|
||||||
@@ -98,7 +99,7 @@ func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
|
|||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Put(data []byte) error {
|
func (c *RemoteClient) Put(_ context.Context, data []byte) error {
|
||||||
bucket, err := c.ossClient.Bucket(c.bucketName)
|
bucket, err := c.ossClient.Bucket(c.bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting bucket: %w", err)
|
return fmt.Errorf("error getting bucket: %w", err)
|
||||||
@@ -131,7 +132,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(_ context.Context) error {
|
||||||
bucket, err := c.ossClient.Bucket(c.bucketName)
|
bucket, err := c.ossClient.Bucket(c.bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting bucket %s: %w", c.bucketName, err)
|
return fmt.Errorf("error getting bucket %s: %w", c.bucketName, err)
|
||||||
@@ -149,7 +150,7 @@ func (c *RemoteClient) Delete() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(_ context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
if c.otsTable == "" {
|
if c.otsTable == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
@@ -360,7 +361,7 @@ func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
|
|||||||
}
|
}
|
||||||
return lockInfo, nil
|
return lockInfo, nil
|
||||||
}
|
}
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(_ context.Context, id string) error {
|
||||||
if c.otsTable == "" {
|
if c.otsTable == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func TestRemoteClientLocks_multipleStates(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := s1.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := s1.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatal("failed to get lock for s1:", err)
|
t.Fatal("failed to get lock for s1:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ func TestRemoteClientLocks_multipleStates(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := s2.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := s2.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatal("failed to get lock for s2:", err)
|
t.Fatal("failed to get lock for s2:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ func TestRemoteForceUnlock(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err := s1.Lock(info)
|
lockID, err := s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ func TestRemoteForceUnlock(t *testing.T) {
|
|||||||
t.Fatal("failed to get default state to force unlock:", err)
|
t.Fatal("failed to get default state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s2.Unlock(lockID); err != nil {
|
if err := s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock default state")
|
t.Fatal("failed to force-unlock default state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ func TestRemoteForceUnlock(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err = s1.Lock(info)
|
lockID, err = s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ func TestRemoteForceUnlock(t *testing.T) {
|
|||||||
t.Fatal("failed to get named state to force unlock:", err)
|
t.Fatal("failed to get named state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock named state")
|
t.Fatal("failed to force-unlock named state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,22 +318,22 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
|||||||
client2 := s2.(*remote.State).Client
|
client2 := s2.(*remote.State).Client
|
||||||
|
|
||||||
// write the new state through client2 so that there is no checksum yet
|
// write the new state through client2 so that there is no checksum yet
|
||||||
if err := client2.Put(newState.Bytes()); err != nil {
|
if err := client2.Put(t.Context(), newState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that we can pull a state without a checksum
|
// verify that we can pull a state without a checksum
|
||||||
if _, err := client1.Get(); err != nil {
|
if _, err := client1.Get(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the new state back with its checksum
|
// write the new state back with its checksum
|
||||||
if err := client1.Put(newState.Bytes()); err != nil {
|
if err := client1.Put(t.Context(), newState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// put an empty state in place to check for panics during get
|
// put an empty state in place to check for panics during get
|
||||||
if err := client2.Put([]byte{}); err != nil {
|
if err := client2.Put(t.Context(), []byte{}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,24 +349,24 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
|||||||
|
|
||||||
// fetching an empty state through client1 should now error out due to a
|
// fetching an empty state through client1 should now error out due to a
|
||||||
// mismatched checksum.
|
// mismatched checksum.
|
||||||
if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
if _, err := client1.Get(t.Context()); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
||||||
t.Fatalf("expected state checksum error: got %s", err)
|
t.Fatalf("expected state checksum error: got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// put the old state in place of the new, without updating the checksum
|
// put the old state in place of the new, without updating the checksum
|
||||||
if err := client2.Put(oldState.Bytes()); err != nil {
|
if err := client2.Put(t.Context(), oldState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetching the wrong state through client1 should now error out due to a
|
// fetching the wrong state through client1 should now error out due to a
|
||||||
// mismatched checksum.
|
// mismatched checksum.
|
||||||
if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
if _, err := client1.Get(t.Context()); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
||||||
t.Fatalf("expected state checksum error: got %s", err)
|
t.Fatalf("expected state checksum error: got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the state with the correct one after we Get again
|
// update the state with the correct one after we Get again
|
||||||
testChecksumHook = func() {
|
testChecksumHook = func() {
|
||||||
if err := client2.Put(newState.Bytes()); err != nil {
|
if err := client2.Put(t.Context(), newState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
testChecksumHook = nil
|
testChecksumHook = nil
|
||||||
@@ -377,7 +377,7 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
|||||||
// this final Get will fail to fail the checksum verification, the above
|
// this final Get will fail to fail the checksum verification, the above
|
||||||
// callback will update the state with the correct version, and Get should
|
// callback will update the state with the correct version, and Get should
|
||||||
// retry automatically.
|
// retry automatically.
|
||||||
if _, err := client1.Get(); err != nil {
|
if _, err := client1.Get(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,14 +92,14 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
if !exists {
|
if !exists {
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockId, err := stateMgr.Lock(lockInfo)
|
lockId, err := stateMgr.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to lock state in Postgres: %w", err)
|
return nil, fmt.Errorf("failed to lock state in Postgres: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(parent error) error {
|
lockUnlock := func(parent error) error {
|
||||||
if err := stateMgr.Unlock(lockId); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockId); err != nil {
|
||||||
return fmt.Errorf("error unlocking Postgres state: %w", err)
|
return fmt.Errorf("error unlocking Postgres state: %w", err)
|
||||||
}
|
}
|
||||||
return parent
|
return parent
|
||||||
@@ -110,7 +110,7 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -630,48 +630,48 @@ func TestBackendConcurrentLock(t *testing.T) {
|
|||||||
|
|
||||||
// First we need to create the workspace as the lock for creating them is
|
// First we need to create the workspace as the lock for creating them is
|
||||||
// global
|
// global
|
||||||
lockID1, err := s1.Lock(i1)
|
lockID1, err := s1.Lock(t.Context(), i1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to lock first state: %v", err)
|
t.Fatalf("failed to lock first state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s1.PersistState(nil); err != nil {
|
if err = s1.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("failed to persist state: %v", err)
|
t.Fatalf("failed to persist state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s1.Unlock(lockID1); err != nil {
|
if err = s1.Unlock(t.Context(), lockID1); err != nil {
|
||||||
t.Fatalf("failed to unlock first state: %v", err)
|
t.Fatalf("failed to unlock first state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockID2, err := s2.Lock(i2)
|
lockID2, err := s2.Lock(t.Context(), i2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to lock second state: %v", err)
|
t.Fatalf("failed to lock second state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.PersistState(nil); err != nil {
|
if err = s2.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("failed to persist state: %v", err)
|
t.Fatalf("failed to persist state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID2); err != nil {
|
if err = s2.Unlock(t.Context(), lockID2); err != nil {
|
||||||
t.Fatalf("failed to unlock first state: %v", err)
|
t.Fatalf("failed to unlock first state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can test concurrent lock
|
// Now we can test concurrent lock
|
||||||
lockID1, err = s1.Lock(i1)
|
lockID1, err = s1.Lock(t.Context(), i1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to lock first state: %v", err)
|
t.Fatalf("failed to lock first state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockID2, err = s2.Lock(i2)
|
lockID2, err = s2.Lock(t.Context(), i2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to lock second state: %v", err)
|
t.Fatalf("failed to lock second state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s1.Unlock(lockID1); err != nil {
|
if err = s1.Unlock(t.Context(), lockID1); err != nil {
|
||||||
t.Fatalf("failed to unlock first state: %v", err)
|
t.Fatalf("failed to unlock first state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID2); err != nil {
|
if err = s2.Unlock(t.Context(), lockID2); err != nil {
|
||||||
t.Fatalf("failed to unlock first state: %v", err)
|
t.Fatalf("failed to unlock first state: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package pg
|
package pg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -29,7 +30,7 @@ type RemoteClient struct {
|
|||||||
info *statemgr.LockInfo
|
info *statemgr.LockInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Get() (*remote.Payload, error) {
|
func (c *RemoteClient) Get(_ context.Context) (*remote.Payload, error) {
|
||||||
query := fmt.Sprintf(`SELECT data FROM %s.%s WHERE name = $1`, pq.QuoteIdentifier(c.SchemaName), pq.QuoteIdentifier(c.TableName))
|
query := fmt.Sprintf(`SELECT data FROM %s.%s WHERE name = $1`, pq.QuoteIdentifier(c.SchemaName), pq.QuoteIdentifier(c.TableName))
|
||||||
row := c.Client.QueryRow(query, c.Name)
|
row := c.Client.QueryRow(query, c.Name)
|
||||||
var data []byte
|
var data []byte
|
||||||
@@ -49,7 +50,7 @@ func (c *RemoteClient) Get() (*remote.Payload, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Put(data []byte) error {
|
func (c *RemoteClient) Put(_ context.Context, data []byte) error {
|
||||||
query := fmt.Sprintf(`INSERT INTO %s.%s (name, data) VALUES ($1, $2)
|
query := fmt.Sprintf(`INSERT INTO %s.%s (name, data) VALUES ($1, $2)
|
||||||
ON CONFLICT (name) DO UPDATE
|
ON CONFLICT (name) DO UPDATE
|
||||||
SET data = $2 WHERE %s.name = $1`, pq.QuoteIdentifier(c.SchemaName), pq.QuoteIdentifier(c.TableName), pq.QuoteIdentifier(c.TableName))
|
SET data = $2 WHERE %s.name = $1`, pq.QuoteIdentifier(c.SchemaName), pq.QuoteIdentifier(c.TableName), pq.QuoteIdentifier(c.TableName))
|
||||||
@@ -60,7 +61,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(_ context.Context) error {
|
||||||
query := fmt.Sprintf(`DELETE FROM %s.%s WHERE name = $1`, pq.QuoteIdentifier(c.SchemaName), pq.QuoteIdentifier(c.TableName))
|
query := fmt.Sprintf(`DELETE FROM %s.%s WHERE name = $1`, pq.QuoteIdentifier(c.SchemaName), pq.QuoteIdentifier(c.TableName))
|
||||||
_, err := c.Client.Exec(query, c.Name)
|
_, err := c.Client.Exec(query, c.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -69,7 +70,7 @@ func (c *RemoteClient) Delete() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(_ context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
var err error
|
var err error
|
||||||
var lockID string
|
var lockID string
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
return info.ID, nil
|
return info.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(_ context.Context, id string) error {
|
||||||
if c.info != nil && c.info.Path != "" {
|
if c.info != nil && c.info.Path != "" {
|
||||||
query := `SELECT pg_advisory_unlock($1)`
|
query := `SELECT pg_advisory_unlock($1)`
|
||||||
row := c.Client.QueryRow(query, c.info.Path)
|
row := c.Client.QueryRow(query, c.info.Path)
|
||||||
|
|||||||
@@ -175,10 +175,10 @@ func TestConcurrentCreationLocksInDifferentSchemas(t *testing.T) {
|
|||||||
// Those calls with empty database must think they are locking
|
// Those calls with empty database must think they are locking
|
||||||
// for workspace creation, both of them must succeed since they
|
// for workspace creation, both of them must succeed since they
|
||||||
// are operating on different schemas.
|
// are operating on different schemas.
|
||||||
if _, err = firstClient.Lock(lock); err != nil {
|
if _, err = firstClient.Lock(t.Context(), lock); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err = secondClient.Lock(lock); err != nil {
|
if _, err = secondClient.Lock(t.Context(), lock); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ func TestConcurrentCreationLocksInDifferentSchemas(t *testing.T) {
|
|||||||
// lock as the first client. We need to make this call from a
|
// lock as the first client. We need to make this call from a
|
||||||
// separate session, since advisory locks are okay to be re-acquired
|
// separate session, since advisory locks are okay to be re-acquired
|
||||||
// during the same session.
|
// during the same session.
|
||||||
if _, err = thirdClient.Lock(lock); err == nil {
|
if _, err = thirdClient.Lock(t.Context(), lock); err == nil {
|
||||||
t.Fatal("Expected an error to be thrown on a second lock attempt")
|
t.Fatal("Expected an error to be thrown on a second lock attempt")
|
||||||
} else if lockErr := err.(*statemgr.LockError); lockErr.Info != lock && //nolint:errcheck,errorlint // this is a test, I am fine with panic here
|
} else if lockErr := err.(*statemgr.LockError); lockErr.Info != lock && //nolint:errcheck,errorlint // this is a test, I am fine with panic here
|
||||||
lockErr.Err.Error() != "Already locked for workspace creation: default" {
|
lockErr.Err.Error() != "Already locked for workspace creation: default" {
|
||||||
@@ -277,10 +277,10 @@ func TestConcurrentCreationLocksInDifferentTables(t *testing.T) {
|
|||||||
// Those calls with empty database must think they are locking
|
// Those calls with empty database must think they are locking
|
||||||
// for workspace creation, both of them must succeed since they
|
// for workspace creation, both of them must succeed since they
|
||||||
// are operating on different schemas.
|
// are operating on different schemas.
|
||||||
if _, err = firstClient.Lock(lock); err != nil {
|
if _, err = firstClient.Lock(t.Context(), lock); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err = secondClient.Lock(lock); err != nil {
|
if _, err = secondClient.Lock(t.Context(), lock); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ func TestConcurrentCreationLocksInDifferentTables(t *testing.T) {
|
|||||||
// lock as the first client. We need to make this call from a
|
// lock as the first client. We need to make this call from a
|
||||||
// separate session, since advisory locks are okay to be re-acquired
|
// separate session, since advisory locks are okay to be re-acquired
|
||||||
// during the same session.
|
// during the same session.
|
||||||
if _, err = thirdClient.Lock(lock); err == nil {
|
if _, err = thirdClient.Lock(t.Context(), lock); err == nil {
|
||||||
t.Fatal("Expected an error to be thrown on a second lock attempt")
|
t.Fatal("Expected an error to be thrown on a second lock attempt")
|
||||||
} else if lockErr := err.(*statemgr.LockError); lockErr.Info != lock && //nolint:errcheck // this is a test, I am fine with panic here
|
} else if lockErr := err.(*statemgr.LockError); lockErr.Info != lock && //nolint:errcheck // this is a test, I am fine with panic here
|
||||||
lockErr.Err.Error() != "Already locked for workspace creation: default" {
|
lockErr.Err.Error() != "Already locked for workspace creation: default" {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func (b *Backend) keyEnv(key string) string {
|
|||||||
return parts[0]
|
return parts[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
func (b *Backend) DeleteWorkspace(ctx context.Context, name string, _ bool) error {
|
||||||
if name == backend.DefaultStateName || name == "" {
|
if name == backend.DefaultStateName || name == "" {
|
||||||
return fmt.Errorf("can't delete default state")
|
return fmt.Errorf("can't delete default state")
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.Delete()
|
return client.Delete(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a remote client configured for this state
|
// get a remote client configured for this state
|
||||||
@@ -182,14 +182,14 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
// take a lock on this state while we write it
|
// take a lock on this state while we write it
|
||||||
lockInfo := statemgr.NewLockInfo()
|
lockInfo := statemgr.NewLockInfo()
|
||||||
lockInfo.Operation = "init"
|
lockInfo.Operation = "init"
|
||||||
lockId, err := client.Lock(lockInfo)
|
lockId, err := client.Lock(context.TODO(), lockInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to lock s3 state: %w", err)
|
return nil, fmt.Errorf("failed to lock s3 state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local helper function so we can call it multiple places
|
// Local helper function so we can call it multiple places
|
||||||
lockUnlock := func(parent error) error {
|
lockUnlock := func(parent error) error {
|
||||||
if err := stateMgr.Unlock(lockId); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockId); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
|
return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
|
||||||
}
|
}
|
||||||
return parent
|
return parent
|
||||||
@@ -198,7 +198,7 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
// Grab the value
|
// Grab the value
|
||||||
// This is to ensure that no one beat us to writing a state between
|
// This is to ensure that no one beat us to writing a state between
|
||||||
// the `exists` check and taking the lock.
|
// the `exists` check and taking the lock.
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ func (b *Backend) StateMgr(ctx context.Context, name string) (statemgr.Full, err
|
|||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), nil); err != nil {
|
||||||
err = lockUnlock(err)
|
err = lockUnlock(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1283,7 +1283,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
if err := stateMgr.WriteState(s1); err != nil {
|
if err := stateMgr.WriteState(s1); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1295,7 +1295,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
if err := stateMgr2.WriteState(s2); err != nil {
|
if err := stateMgr2.WriteState(s2); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := stateMgr2.PersistState(nil); err != nil {
|
if err := stateMgr2.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1310,7 +1310,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := checkStateList(t.Context(), b, []string{"default", "s1", "s2"}); err != nil {
|
if err := checkStateList(t.Context(), b, []string{"default", "s1", "s2"}); err != nil {
|
||||||
@@ -1322,7 +1322,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := checkStateList(t.Context(), b, []string{"default", "s1", "s2"}); err != nil {
|
if err := checkStateList(t.Context(), b, []string{"default", "s1", "s2"}); err != nil {
|
||||||
@@ -1330,7 +1330,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove the state with extra subkey
|
// remove the state with extra subkey
|
||||||
if err := client.Delete(); err != nil {
|
if err := client.Delete(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,7 +1348,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s2Mgr.RefreshState(); err != nil {
|
if err := s2Mgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1363,7 +1363,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(nil); err != nil {
|
if err := stateMgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1372,7 +1372,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s2Mgr.RefreshState(); err != nil {
|
if err := s2Mgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1405,7 +1405,7 @@ func TestBackendPrefixInWorkspace(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := sMgr.RefreshState(); err != nil {
|
if err := sMgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,7 @@ var (
|
|||||||
// test hook called when checksums don't match
|
// test hook called when checksums don't match
|
||||||
var testChecksumHook func()
|
var testChecksumHook func()
|
||||||
|
|
||||||
func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
|
func (c *RemoteClient) Get(ctx context.Context) (payload *remote.Payload, err error) {
|
||||||
ctx := context.TODO()
|
|
||||||
deadline := time.Now().Add(consistencyRetryTimeout)
|
deadline := time.Now().Add(consistencyRetryTimeout)
|
||||||
|
|
||||||
// If we have a checksum, and the returned payload doesn't match, we retry
|
// If we have a checksum, and the returned payload doesn't match, we retry
|
||||||
@@ -194,7 +193,7 @@ func (c *RemoteClient) get(ctx context.Context) (*remote.Payload, error) {
|
|||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Put(data []byte) error {
|
func (c *RemoteClient) Put(ctx context.Context, data []byte) error {
|
||||||
contentLength := int64(len(data))
|
contentLength := int64(len(data))
|
||||||
|
|
||||||
i := &s3.PutObjectInput{
|
i := &s3.PutObjectInput{
|
||||||
@@ -208,7 +207,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
c.configurePutObjectChecksum(data, i)
|
c.configurePutObjectChecksum(data, i)
|
||||||
c.configurePutObjectEncryption(i)
|
c.configurePutObjectEncryption(i)
|
||||||
c.configurePutObjectACL(i)
|
c.configurePutObjectACL(i)
|
||||||
ctx := context.TODO()
|
|
||||||
ctx, _ = attachLoggerToContext(ctx)
|
ctx, _ = attachLoggerToContext(ctx)
|
||||||
|
|
||||||
log.Printf("[DEBUG] Uploading remote state to S3: %#v", i)
|
log.Printf("[DEBUG] Uploading remote state to S3: %#v", i)
|
||||||
@@ -227,8 +226,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(ctx context.Context) error {
|
||||||
ctx := context.TODO()
|
|
||||||
ctx, _ = attachLoggerToContext(ctx)
|
ctx, _ = attachLoggerToContext(ctx)
|
||||||
|
|
||||||
_, err := c.s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
|
_, err := c.s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
|
||||||
@@ -247,7 +245,7 @@ func (c *RemoteClient) Delete() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
if !c.IsLockingEnabled() {
|
if !c.IsLockingEnabled() {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
@@ -261,12 +259,12 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
info.Path = c.lockPath()
|
info.Path = c.lockPath()
|
||||||
|
|
||||||
if err := c.s3Lock(info); err != nil {
|
if err := c.s3Lock(ctx, info); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := c.dynamoDBLock(info); err != nil {
|
if err := c.dynamoDBLock(ctx, info); err != nil {
|
||||||
// when the second lock fails from getting acquired, release the initially acquired one
|
// when the second lock fails from getting acquired, release the initially acquired one
|
||||||
if uErr := c.s3Unlock(info.ID); uErr != nil {
|
if uErr := c.s3Unlock(ctx, info.ID); uErr != nil {
|
||||||
log.Printf("[WARN] failed to release the S3 lock after failed to acquire the dynamoDD lock: %v", uErr)
|
log.Printf("[WARN] failed to release the S3 lock after failed to acquire the dynamoDD lock: %v", uErr)
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
@@ -275,7 +273,7 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dynamoDBLock expects the statemgr.LockInfo#ID to be filled already
|
// dynamoDBLock expects the statemgr.LockInfo#ID to be filled already
|
||||||
func (c *RemoteClient) dynamoDBLock(info *statemgr.LockInfo) error {
|
func (c *RemoteClient) dynamoDBLock(ctx context.Context, info *statemgr.LockInfo) error {
|
||||||
if c.ddbTable == "" {
|
if c.ddbTable == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -289,7 +287,6 @@ func (c *RemoteClient) dynamoDBLock(info *statemgr.LockInfo) error {
|
|||||||
ConditionExpression: aws.String("attribute_not_exists(LockID)"),
|
ConditionExpression: aws.String("attribute_not_exists(LockID)"),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.TODO()
|
|
||||||
_, err := c.dynClient.PutItem(ctx, putParams)
|
_, err := c.dynClient.PutItem(ctx, putParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lockInfo, infoErr := c.getLockInfoFromDynamoDB(ctx)
|
lockInfo, infoErr := c.getLockInfoFromDynamoDB(ctx)
|
||||||
@@ -308,7 +305,7 @@ func (c *RemoteClient) dynamoDBLock(info *statemgr.LockInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// s3Lock expects the statemgr.LockInfo#ID to be filled already
|
// s3Lock expects the statemgr.LockInfo#ID to be filled already
|
||||||
func (c *RemoteClient) s3Lock(info *statemgr.LockInfo) error {
|
func (c *RemoteClient) s3Lock(ctx context.Context, info *statemgr.LockInfo) error {
|
||||||
if !c.useLockfile {
|
if !c.useLockfile {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -325,7 +322,7 @@ func (c *RemoteClient) s3Lock(info *statemgr.LockInfo) error {
|
|||||||
c.configurePutObjectChecksum(lInfo, putParams)
|
c.configurePutObjectChecksum(lInfo, putParams)
|
||||||
c.configurePutObjectEncryption(putParams)
|
c.configurePutObjectEncryption(putParams)
|
||||||
c.configurePutObjectACL(putParams)
|
c.configurePutObjectACL(putParams)
|
||||||
ctx := context.TODO()
|
|
||||||
ctx, _ = attachLoggerToContext(ctx)
|
ctx, _ = attachLoggerToContext(ctx)
|
||||||
|
|
||||||
log.Printf("[DEBUG] Uploading s3 locking object: %#v", putParams)
|
log.Printf("[DEBUG] Uploading s3 locking object: %#v", putParams)
|
||||||
@@ -488,11 +485,11 @@ func (c *RemoteClient) getLockInfoFromS3(ctx context.Context) (*statemgr.LockInf
|
|||||||
return lockInfo, nil
|
return lockInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(ctx context.Context, id string) error {
|
||||||
// Attempt to release the lock from both sources.
|
// Attempt to release the lock from both sources.
|
||||||
// We want to do so to be sure that we are leaving no locks unhandled
|
// We want to do so to be sure that we are leaving no locks unhandled
|
||||||
s3Err := c.s3Unlock(id)
|
s3Err := c.s3Unlock(ctx, id)
|
||||||
dynamoDBErr := c.dynamoDBUnlock(id)
|
dynamoDBErr := c.dynamoDBUnlock(ctx, id)
|
||||||
switch {
|
switch {
|
||||||
case s3Err != nil && dynamoDBErr != nil:
|
case s3Err != nil && dynamoDBErr != nil:
|
||||||
s3Err.Err = multierror.Append(s3Err.Err, dynamoDBErr.Err)
|
s3Err.Err = multierror.Append(s3Err.Err, dynamoDBErr.Err)
|
||||||
@@ -511,12 +508,11 @@ func (c *RemoteClient) Unlock(id string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) s3Unlock(id string) *statemgr.LockError {
|
func (c *RemoteClient) s3Unlock(ctx context.Context, id string) *statemgr.LockError {
|
||||||
if !c.useLockfile {
|
if !c.useLockfile {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
lockErr := &statemgr.LockError{}
|
lockErr := &statemgr.LockError{}
|
||||||
ctx := context.TODO()
|
|
||||||
ctx, _ = attachLoggerToContext(ctx)
|
ctx, _ = attachLoggerToContext(ctx)
|
||||||
|
|
||||||
lockInfo, err := c.getLockInfoFromS3(ctx)
|
lockInfo, err := c.getLockInfoFromS3(ctx)
|
||||||
@@ -544,13 +540,12 @@ func (c *RemoteClient) s3Unlock(id string) *statemgr.LockError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) dynamoDBUnlock(id string) *statemgr.LockError {
|
func (c *RemoteClient) dynamoDBUnlock(ctx context.Context, id string) *statemgr.LockError {
|
||||||
if c.ddbTable == "" {
|
if c.ddbTable == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lockErr := &statemgr.LockError{}
|
lockErr := &statemgr.LockError{}
|
||||||
ctx := context.TODO()
|
|
||||||
|
|
||||||
lockInfo, err := c.getLockInfoFromDynamoDB(ctx)
|
lockInfo, err := c.getLockInfoFromDynamoDB(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ func TestRemoteS3AndDynamoDBClientLocksWithNoDBInstance(t *testing.T) {
|
|||||||
infoA.Operation = "test"
|
infoA.Operation = "test"
|
||||||
infoA.Who = "clientA"
|
infoA.Who = "clientA"
|
||||||
|
|
||||||
if _, err := s1.Lock(infoA); err == nil {
|
if _, err := s1.Lock(t.Context(), infoA); err == nil {
|
||||||
t.Fatal("unexpected successful lock: ", err)
|
t.Fatal("unexpected successful lock: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err := s1.Lock(info)
|
lockID, err := s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
t.Fatal("failed to get default state to force unlock:", err)
|
t.Fatal("failed to get default state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s2.Unlock(lockID); err != nil {
|
if err := s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock default state")
|
t.Fatal("failed to force-unlock default state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err = s1.Lock(info)
|
lockID, err = s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
t.Fatal("failed to get named state to force unlock:", err)
|
t.Fatal("failed to get named state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock named state")
|
t.Fatal("failed to force-unlock named state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +307,7 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s2.Unlock(lockID)
|
err = s2.Unlock(t.Context(), lockID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected an error to occur:", err)
|
t.Fatal("expected an error to occur:", err)
|
||||||
}
|
}
|
||||||
@@ -352,7 +352,7 @@ func TestForceUnlockS3Only(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err := s1.Lock(info)
|
lockID, err := s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -363,7 +363,7 @@ func TestForceUnlockS3Only(t *testing.T) {
|
|||||||
t.Fatal("failed to get default state to force unlock:", err)
|
t.Fatal("failed to get default state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock default state")
|
t.Fatal("failed to force-unlock default state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +378,7 @@ func TestForceUnlockS3Only(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err = s1.Lock(info)
|
lockID, err = s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -389,7 +389,7 @@ func TestForceUnlockS3Only(t *testing.T) {
|
|||||||
t.Fatal("failed to get named state to force unlock:", err)
|
t.Fatal("failed to get named state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock named state")
|
t.Fatal("failed to force-unlock named state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@ func TestForceUnlockS3Only(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s2.Unlock(lockID)
|
err = s2.Unlock(t.Context(), lockID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected an error to occur:", err)
|
t.Fatal("expected an error to occur:", err)
|
||||||
}
|
}
|
||||||
@@ -455,7 +455,7 @@ func TestForceUnlockS3AndDynamo(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err := s1.Lock(info)
|
lockID, err := s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -466,7 +466,7 @@ func TestForceUnlockS3AndDynamo(t *testing.T) {
|
|||||||
t.Fatal("failed to get default state to force unlock:", err)
|
t.Fatal("failed to get default state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock default state")
|
t.Fatal("failed to force-unlock default state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,7 +481,7 @@ func TestForceUnlockS3AndDynamo(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err = s1.Lock(info)
|
lockID, err = s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -492,7 +492,7 @@ func TestForceUnlockS3AndDynamo(t *testing.T) {
|
|||||||
t.Fatal("failed to get named state to force unlock:", err)
|
t.Fatal("failed to get named state to force unlock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock named state")
|
t.Fatal("failed to force-unlock named state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,7 +502,7 @@ func TestForceUnlockS3AndDynamo(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s2.Unlock(lockID)
|
err = s2.Unlock(t.Context(), lockID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected an error to occur:", err)
|
t.Fatal("expected an error to occur:", err)
|
||||||
}
|
}
|
||||||
@@ -546,7 +546,7 @@ func TestForceUnlockS3WithAndDynamoWithout(t *testing.T) {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Who = "clientA"
|
info.Who = "clientA"
|
||||||
|
|
||||||
lockID, err := s1.Lock(info)
|
lockID, err := s1.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -554,7 +554,7 @@ func TestForceUnlockS3WithAndDynamoWithout(t *testing.T) {
|
|||||||
// Remove the dynamo lock to simulate that the lock in s3 was acquired, dynamo failed but s3 release failed in the end.
|
// Remove the dynamo lock to simulate that the lock in s3 was acquired, dynamo failed but s3 release failed in the end.
|
||||||
// Therefore, the user is left in the situation with s3 lock existing and dynamo missing.
|
// Therefore, the user is left in the situation with s3 lock existing and dynamo missing.
|
||||||
deleteDynamoEntry(t.Context(), t, b1.dynClient, bucketName, info.Path)
|
deleteDynamoEntry(t.Context(), t, b1.dynClient, bucketName, info.Path)
|
||||||
err = s1.Unlock(lockID)
|
err = s1.Unlock(t.Context(), lockID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected to get an error but got nil")
|
t.Fatal("expected to get an error but got nil")
|
||||||
}
|
}
|
||||||
@@ -564,7 +564,7 @@ func TestForceUnlockS3WithAndDynamoWithout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now, unlocking should fail with error on both locks
|
// Now, unlocking should fail with error on both locks
|
||||||
err = s1.Unlock(lockID)
|
err = s1.Unlock(t.Context(), lockID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected to get an error but got nil")
|
t.Fatal("expected to get an error but got nil")
|
||||||
}
|
}
|
||||||
@@ -676,22 +676,22 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
|||||||
client2 := s2.(*remote.State).Client
|
client2 := s2.(*remote.State).Client
|
||||||
|
|
||||||
// write the new state through client2 so that there is no checksum yet
|
// write the new state through client2 so that there is no checksum yet
|
||||||
if err := client2.Put(newState.Bytes()); err != nil {
|
if err := client2.Put(t.Context(), newState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that we can pull a state without a checksum
|
// verify that we can pull a state without a checksum
|
||||||
if _, err := client1.Get(); err != nil {
|
if _, err := client1.Get(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the new state back with its checksum
|
// write the new state back with its checksum
|
||||||
if err := client1.Put(newState.Bytes()); err != nil {
|
if err := client1.Put(t.Context(), newState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// put an empty state in place to check for panics during get
|
// put an empty state in place to check for panics during get
|
||||||
if err := client2.Put([]byte{}); err != nil {
|
if err := client2.Put(t.Context(), []byte{}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -707,24 +707,24 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
|||||||
|
|
||||||
// fetching an empty state through client1 should now error out due to a
|
// fetching an empty state through client1 should now error out due to a
|
||||||
// mismatched checksum.
|
// mismatched checksum.
|
||||||
if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
if _, err := client1.Get(t.Context()); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
||||||
t.Fatalf("expected state checksum error: got %s", err)
|
t.Fatalf("expected state checksum error: got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// put the old state in place of the new, without updating the checksum
|
// put the old state in place of the new, without updating the checksum
|
||||||
if err := client2.Put(oldState.Bytes()); err != nil {
|
if err := client2.Put(t.Context(), oldState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetching the wrong state through client1 should now error out due to a
|
// fetching the wrong state through client1 should now error out due to a
|
||||||
// mismatched checksum.
|
// mismatched checksum.
|
||||||
if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
if _, err := client1.Get(t.Context()); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
|
||||||
t.Fatalf("expected state checksum error: got %s", err)
|
t.Fatalf("expected state checksum error: got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the state with the correct one after we Get again
|
// update the state with the correct one after we Get again
|
||||||
testChecksumHook = func() {
|
testChecksumHook = func() {
|
||||||
if err := client2.Put(newState.Bytes()); err != nil {
|
if err := client2.Put(t.Context(), newState.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
testChecksumHook = nil
|
testChecksumHook = nil
|
||||||
@@ -735,7 +735,7 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
|||||||
// this final Get will fail to fail the checksum verification, the above
|
// this final Get will fail to fail the checksum verification, the above
|
||||||
// callback will update the state with the correct version, and Get should
|
// callback will update the state with the correct version, and Get should
|
||||||
// retry automatically.
|
// retry automatically.
|
||||||
if _, err := client1.Get(); err != nil {
|
if _, err := client1.Get(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -821,7 +821,7 @@ func TestS3ChecksumsHeaders(t *testing.T) {
|
|||||||
name: "s3.Put with included checksum",
|
name: "s3.Put with included checksum",
|
||||||
skipChecksum: false,
|
skipChecksum: false,
|
||||||
action: func(cl *RemoteClient) error {
|
action: func(cl *RemoteClient) error {
|
||||||
return cl.Put([]byte("test"))
|
return cl.Put(t.Context(), []byte("test"))
|
||||||
},
|
},
|
||||||
wantMissingHeaders: []string{
|
wantMissingHeaders: []string{
|
||||||
"X-Amz-Checksum-Mode",
|
"X-Amz-Checksum-Mode",
|
||||||
@@ -837,7 +837,7 @@ func TestS3ChecksumsHeaders(t *testing.T) {
|
|||||||
name: "s3.Put with skipped checksum",
|
name: "s3.Put with skipped checksum",
|
||||||
skipChecksum: true,
|
skipChecksum: true,
|
||||||
action: func(cl *RemoteClient) error {
|
action: func(cl *RemoteClient) error {
|
||||||
return cl.Put([]byte("test"))
|
return cl.Put(t.Context(), []byte("test"))
|
||||||
},
|
},
|
||||||
wantMissingHeaders: []string{
|
wantMissingHeaders: []string{
|
||||||
"X-Amz-Checksum-Mode",
|
"X-Amz-Checksum-Mode",
|
||||||
@@ -854,7 +854,7 @@ func TestS3ChecksumsHeaders(t *testing.T) {
|
|||||||
name: "s3.HeadObject and s3.GetObject with included checksum",
|
name: "s3.HeadObject and s3.GetObject with included checksum",
|
||||||
skipChecksum: false,
|
skipChecksum: false,
|
||||||
action: func(cl *RemoteClient) error {
|
action: func(cl *RemoteClient) error {
|
||||||
_, err := cl.Get()
|
_, err := cl.Get(t.Context())
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
wantMissingHeaders: []string{
|
wantMissingHeaders: []string{
|
||||||
@@ -871,7 +871,7 @@ func TestS3ChecksumsHeaders(t *testing.T) {
|
|||||||
name: "s3.HeadObject and s3.GetObject with skipped checksum",
|
name: "s3.HeadObject and s3.GetObject with skipped checksum",
|
||||||
skipChecksum: true,
|
skipChecksum: true,
|
||||||
action: func(cl *RemoteClient) error {
|
action: func(cl *RemoteClient) error {
|
||||||
_, err := cl.Get()
|
_, err := cl.Get(t.Context())
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
wantMissingHeaders: []string{
|
wantMissingHeaders: []string{
|
||||||
@@ -939,7 +939,7 @@ func TestS3LockingWritingHeaders(t *testing.T) {
|
|||||||
)
|
)
|
||||||
// get the request from state writing
|
// get the request from state writing
|
||||||
{
|
{
|
||||||
err := rc.Put([]byte("test"))
|
err := rc.Put(t.Context(), []byte("test"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected to have no error writing the state object but got one: %s", err)
|
t.Fatalf("expected to have no error writing the state object but got one: %s", err)
|
||||||
}
|
}
|
||||||
@@ -950,7 +950,7 @@ func TestS3LockingWritingHeaders(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// get the request from lock object writing
|
// get the request from lock object writing
|
||||||
{
|
{
|
||||||
err := rc.s3Lock(&statemgr.LockInfo{Info: "test"})
|
err := rc.s3Lock(t.Context(), &statemgr.LockInfo{Info: "test"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected to have no error writing the lock object but got one: %s", err)
|
t.Fatalf("expected to have no error writing the lock object but got one: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ func (b *Remote) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
|||||||
encryption: b.encryption,
|
encryption: b.encryption,
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.Delete()
|
return client.Delete(context.TODO())
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateMgr implements backend.Enhanced.
|
// StateMgr implements backend.Enhanced.
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ func TestRemote_applyBasic(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ func TestRemote_applyCanceled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -488,7 +488,7 @@ func TestRemote_applyWithExclude(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -654,7 +654,7 @@ func TestRemote_applyNoConfig(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (b *Remote) LocalRun(ctx context.Context, op *backend.Operation) (*backend.
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
log.Printf("[TRACE] backend/remote: reading remote state for workspace %q", remoteWorkspaceName)
|
log.Printf("[TRACE] backend/remote: reading remote state for workspace %q", remoteWorkspaceName)
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf("error loading state: %w", err))
|
diags = diags.Append(fmt.Errorf("error loading state: %w", err))
|
||||||
return nil, nil, diags
|
return nil, nil, diags
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ func TestRemoteContextWithVars(t *testing.T) {
|
|||||||
// When Context() returns an error, it should unlock the state,
|
// When Context() returns an error, it should unlock the state,
|
||||||
// so re-locking it is expected to succeed.
|
// so re-locking it is expected to succeed.
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state: %s", err.Error())
|
t.Fatalf("unexpected error locking state: %s", err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -237,7 +237,7 @@ func TestRemoteContextWithVars(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// When Context() succeeds, this should fail w/ "workspace already locked"
|
// When Context() succeeds, this should fail w/ "workspace already locked"
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err == nil {
|
||||||
t.Fatal("unexpected success locking state after Context")
|
t.Fatal("unexpected success locking state after Context")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,7 +445,7 @@ func TestRemoteVariablesDoNotOverride(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// When Context() succeeds, this should fail w/ "workspace already locked"
|
// When Context() succeeds, this should fail w/ "workspace already locked"
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err == nil {
|
||||||
t.Fatal("unexpected success locking state after Context")
|
t.Fatal("unexpected success locking state after Context")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ func TestRemote_planBasic(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
// An error suggests that the state was not unlocked after the operation finished
|
// An error suggests that the state was not unlocked after the operation finished
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ func TestRemote_planCanceled(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
stateMgr, _ := b.StateMgr(t.Context(), backend.DefaultStateName)
|
||||||
// An error suggests that the state was not unlocked after the operation finished
|
// An error suggests that the state was not unlocked after the operation finished
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error())
|
t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,7 @@ type remoteClient struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the remote state.
|
// Get the remote state.
|
||||||
func (r *remoteClient) Get() (*remote.Payload, error) {
|
func (r *remoteClient) Get(ctx context.Context) (*remote.Payload, error) {
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
sv, err := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)
|
sv, err := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == tfe.ErrResourceNotFound {
|
if err == tfe.ErrResourceNotFound {
|
||||||
@@ -93,9 +91,7 @@ func (r *remoteClient) uploadStateFallback(ctx context.Context, stateFile *state
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put the remote state.
|
// Put the remote state.
|
||||||
func (r *remoteClient) Put(state []byte) error {
|
func (r *remoteClient) Put(ctx context.Context, state []byte) error {
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// Read the raw state into a OpenTofu state.
|
// Read the raw state into a OpenTofu state.
|
||||||
stateFile, err := statefile.Read(bytes.NewReader(state), r.encryption)
|
stateFile, err := statefile.Read(bytes.NewReader(state), r.encryption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -145,8 +141,8 @@ func (r *remoteClient) Put(state []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete the remote state.
|
// Delete the remote state.
|
||||||
func (r *remoteClient) Delete() error {
|
func (r *remoteClient) Delete(ctx context.Context) error {
|
||||||
err := r.client.Workspaces.Delete(context.Background(), r.organization, r.workspace.Name)
|
err := r.client.Workspaces.Delete(ctx, r.organization, r.workspace.Name)
|
||||||
if err != nil && err != tfe.ErrResourceNotFound {
|
if err != nil && err != tfe.ErrResourceNotFound {
|
||||||
return fmt.Errorf("error deleting workspace %s: %w", r.workspace.Name, err)
|
return fmt.Errorf("error deleting workspace %s: %w", r.workspace.Name, err)
|
||||||
}
|
}
|
||||||
@@ -161,9 +157,7 @@ func (r *remoteClient) EnableForcePush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock the remote state.
|
// Lock the remote state.
|
||||||
func (r *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
func (r *remoteClient) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
lockErr := &statemgr.LockError{Info: r.lockInfo}
|
lockErr := &statemgr.LockError{Info: r.lockInfo}
|
||||||
|
|
||||||
// Lock the workspace.
|
// Lock the workspace.
|
||||||
@@ -185,9 +179,7 @@ func (r *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unlock the remote state.
|
// Unlock the remote state.
|
||||||
func (r *remoteClient) Unlock(id string) error {
|
func (r *remoteClient) Unlock(ctx context.Context, id string) error {
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// We first check if there was an error while uploading the latest
|
// We first check if there was an error while uploading the latest
|
||||||
// state. If so, we will not unlock the workspace to prevent any
|
// state. If so, we will not unlock the workspace to prevent any
|
||||||
// changes from being applied until the correct state is uploaded.
|
// changes from being applied until the correct state is uploaded.
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func TestRemoteClient_Put_withRunID(t *testing.T) {
|
|||||||
|
|
||||||
// Store the new state to verify (this will be done
|
// Store the new state to verify (this will be done
|
||||||
// by the mock that is used) that the run ID is set.
|
// by the mock that is used) that the run ID is set.
|
||||||
if err := client.Put(buf.Bytes()); err != nil {
|
if err := client.Put(t.Context(), buf.Bytes()); err != nil {
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,13 +382,13 @@ func TestRemote_Unlock_ignoreVersion(t *testing.T) {
|
|||||||
t.Fatalf("error: %v", err)
|
t.Fatalf("error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockID, err := state.Lock(statemgr.NewLockInfo())
|
lockID, err := state.Lock(t.Context(), statemgr.NewLockInfo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %v", err)
|
t.Fatalf("error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should succeed since the version conflict is ignored
|
// this should succeed since the version conflict is ignored
|
||||||
if err = state.Unlock(lockID); err != nil {
|
if err = state.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatalf("error: %v", err)
|
t.Fatalf("error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %s", err)
|
t.Fatalf("error: %s", err)
|
||||||
}
|
}
|
||||||
if err := foo.RefreshState(); err != nil {
|
if err := foo.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("bad: %s", err)
|
t.Fatalf("bad: %s", err)
|
||||||
}
|
}
|
||||||
if v := foo.State(); v.HasManagedResourceInstanceObjects() {
|
if v := foo.State(); v.HasManagedResourceInstanceObjects() {
|
||||||
@@ -176,7 +176,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %s", err)
|
t.Fatalf("error: %s", err)
|
||||||
}
|
}
|
||||||
if err := bar.RefreshState(); err != nil {
|
if err := bar.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("bad: %s", err)
|
t.Fatalf("bad: %s", err)
|
||||||
}
|
}
|
||||||
if v := bar.State(); v.HasManagedResourceInstanceObjects() {
|
if v := bar.State(); v.HasManagedResourceInstanceObjects() {
|
||||||
@@ -194,7 +194,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
if err := foo.WriteState(fooState); err != nil {
|
if err := foo.WriteState(fooState); err != nil {
|
||||||
t.Fatal("error writing foo state:", err)
|
t.Fatal("error writing foo state:", err)
|
||||||
}
|
}
|
||||||
if err := foo.PersistState(nil); err != nil {
|
if err := foo.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal("error persisting foo state:", err)
|
t.Fatal("error persisting foo state:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,12 +223,12 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
if err := bar.WriteState(barState); err != nil {
|
if err := bar.WriteState(barState); err != nil {
|
||||||
t.Fatalf("bad: %s", err)
|
t.Fatalf("bad: %s", err)
|
||||||
}
|
}
|
||||||
if err := bar.PersistState(nil); err != nil {
|
if err := bar.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("bad: %s", err)
|
t.Fatalf("bad: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that foo is unchanged with the existing state manager
|
// verify that foo is unchanged with the existing state manager
|
||||||
if err := foo.RefreshState(); err != nil {
|
if err := foo.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal("error refreshing foo:", err)
|
t.Fatal("error refreshing foo:", err)
|
||||||
}
|
}
|
||||||
fooState = foo.State()
|
fooState = foo.State()
|
||||||
@@ -241,7 +241,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error re-fetching state:", err)
|
t.Fatal("error re-fetching state:", err)
|
||||||
}
|
}
|
||||||
if err := foo.RefreshState(); err != nil {
|
if err := foo.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal("error refreshing foo:", err)
|
t.Fatal("error refreshing foo:", err)
|
||||||
}
|
}
|
||||||
fooState = foo.State()
|
fooState = foo.State()
|
||||||
@@ -254,7 +254,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error re-fetching state:", err)
|
t.Fatal("error re-fetching state:", err)
|
||||||
}
|
}
|
||||||
if err := bar.RefreshState(); err != nil {
|
if err := bar.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal("error refreshing bar:", err)
|
t.Fatal("error refreshing bar:", err)
|
||||||
}
|
}
|
||||||
barState = bar.State()
|
barState = bar.State()
|
||||||
@@ -298,7 +298,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %s", err)
|
t.Fatalf("error: %s", err)
|
||||||
}
|
}
|
||||||
if err := foo.RefreshState(); err != nil {
|
if err := foo.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("bad: %s", err)
|
t.Fatalf("bad: %s", err)
|
||||||
}
|
}
|
||||||
if v := foo.State(); v.HasManagedResourceInstanceObjects() {
|
if v := foo.State(); v.HasManagedResourceInstanceObjects() {
|
||||||
@@ -371,7 +371,7 @@ func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, wo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %s", err)
|
t.Fatalf("error: %s", err)
|
||||||
}
|
}
|
||||||
if err := b1StateMgr.RefreshState(); err != nil {
|
if err := b1StateMgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("bad: %s", err)
|
t.Fatalf("bad: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, wo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %s", err)
|
t.Fatalf("error: %s", err)
|
||||||
}
|
}
|
||||||
if err := b2StateMgr.RefreshState(); err != nil {
|
if err := b2StateMgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("bad: %s", err)
|
t.Fatalf("bad: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,7 +403,7 @@ func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, wo
|
|||||||
infoB.Operation = "test"
|
infoB.Operation = "test"
|
||||||
infoB.Who = "clientB"
|
infoB.Who = "clientB"
|
||||||
|
|
||||||
lockIDA, err := lockerA.Lock(infoA)
|
lockIDA, err := lockerA.Lock(t.Context(), infoA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
@@ -422,17 +422,17 @@ func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, wo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = lockerB.Lock(infoB)
|
_, err = lockerB.Lock(t.Context(), infoB)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = lockerA.Unlock(lockIDA) // test already failed, no need to check err further
|
_ = lockerA.Unlock(t.Context(), lockIDA) // test already failed, no need to check err further
|
||||||
t.Fatal("client B obtained lock while held by client A")
|
t.Fatal("client B obtained lock while held by client A")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := lockerA.Unlock(lockIDA); err != nil {
|
if err := lockerA.Unlock(t.Context(), lockIDA); err != nil {
|
||||||
t.Fatal("error unlocking client A", err)
|
t.Fatal("error unlocking client A", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockIDB, err := lockerB.Lock(infoB)
|
lockIDB, err := lockerB.Lock(t.Context(), infoB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to obtain lock from client B")
|
t.Fatal("unable to obtain lock from client B")
|
||||||
}
|
}
|
||||||
@@ -441,7 +441,7 @@ func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, wo
|
|||||||
t.Errorf("duplicate lock IDs: %q", lockIDB)
|
t.Errorf("duplicate lock IDs: %q", lockIDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = lockerB.Unlock(lockIDB); err != nil {
|
if err = lockerB.Unlock(t.Context(), lockIDB); err != nil {
|
||||||
t.Fatal("error unlocking client B:", err)
|
t.Fatal("error unlocking client B:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,18 +457,18 @@ func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, wo
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockIDA, err = lockerA.Lock(infoA)
|
lockIDA, err = lockerA.Lock(t.Context(), infoA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get re lock A:", err)
|
t.Fatal("unable to get re lock A:", err)
|
||||||
}
|
}
|
||||||
unlock := func() {
|
unlock := func() {
|
||||||
err := lockerA.Unlock(lockIDA)
|
err := lockerA.Unlock(t.Context(), lockIDA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = lockerB.Lock(infoB)
|
_, err = lockerB.Lock(t.Context(), infoB)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
unlock()
|
unlock()
|
||||||
t.Fatal("client B obtained lock while held by client A")
|
t.Fatal("client B obtained lock while held by client A")
|
||||||
@@ -481,7 +481,7 @@ func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, wo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try to unlock with the second unlocker, using the ID from the error
|
// try to unlock with the second unlocker, using the ID from the error
|
||||||
if err := lockerB.Unlock(infoErr.Info.ID); err != nil {
|
if err := lockerB.Unlock(t.Context(), infoErr.Info.ID); err != nil {
|
||||||
unlock()
|
unlock()
|
||||||
t.Fatalf("could not unlock with the reported ID %q: %s", infoErr.Info.ID, err)
|
t.Fatalf("could not unlock with the reported ID %q: %s", infoErr.Info.ID, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ func dataSourceRemoteStateRead(ctx context.Context, d cty.Value, enc encryption.
|
|||||||
return cty.NilVal, diags
|
return cty.NilVal, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := state.RefreshState(); err != nil {
|
if err := state.RefreshState(ctx); err != nil {
|
||||||
diags = diags.Append(err)
|
diags = diags.Append(err)
|
||||||
return cty.NilVal, diags
|
return cty.NilVal, diags
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func TestCloud_applyBasic(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ func TestCloud_applyJSONBasic(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,7 +261,7 @@ func TestCloud_applyJSONWithOutputs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ func TestCloud_applyCanceled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,7 +496,7 @@ func TestCloud_applyWithCloudPlan(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -644,7 +644,7 @@ func TestCloud_applyWithExclude(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -744,7 +744,7 @@ func TestCloud_applyNoConfig(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1405,7 +1405,7 @@ func TestCloud_applyJSONWithProvisioner(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (b *Cloud) LocalRun(ctx context.Context, op *backend.Operation) (*backend.L
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
log.Printf("[TRACE] cloud: reading remote state for workspace %q", remoteWorkspaceName)
|
log.Printf("[TRACE] cloud: reading remote state for workspace %q", remoteWorkspaceName)
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf("error loading state: %w", err))
|
diags = diags.Append(fmt.Errorf("error loading state: %w", err))
|
||||||
return nil, nil, diags
|
return nil, nil, diags
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ func TestRemoteContextWithVars(t *testing.T) {
|
|||||||
// When Context() returns an error, it should unlock the state,
|
// When Context() returns an error, it should unlock the state,
|
||||||
// so re-locking it is expected to succeed.
|
// so re-locking it is expected to succeed.
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state: %s", err.Error())
|
t.Fatalf("unexpected error locking state: %s", err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -236,7 +236,7 @@ func TestRemoteContextWithVars(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// When Context() succeeds, this should fail w/ "workspace already locked"
|
// When Context() succeeds, this should fail w/ "workspace already locked"
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err == nil {
|
||||||
t.Fatal("unexpected success locking state after Context")
|
t.Fatal("unexpected success locking state after Context")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -444,7 +444,7 @@ func TestRemoteVariablesDoNotOverride(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// When Context() succeeds, this should fail w/ "workspace already locked"
|
// When Context() succeeds, this should fail w/ "workspace already locked"
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err == nil {
|
||||||
t.Fatal("unexpected success locking state after Context")
|
t.Fatal("unexpected success locking state after Context")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func TestCloud_planBasic(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after the operation finished
|
// An error suggests that the state was not unlocked after the operation finished
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +145,7 @@ func TestCloud_planJSONBasic(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after the operation finished
|
// An error suggests that the state was not unlocked after the operation finished
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ func TestCloud_planCanceled(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after the operation finished
|
// An error suggests that the state was not unlocked after the operation finished
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error())
|
t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,7 @@ func TestCloud_planJSONFull(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after the operation finished
|
// An error suggests that the state was not unlocked after the operation finished
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1322,7 +1322,7 @@ func TestCloud_planImportConfigGeneration(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after the operation finished
|
// An error suggests that the state was not unlocked after the operation finished
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func TestCloud_refreshBasicActuallyRunsApplyRefresh(t *testing.T) {
|
|||||||
|
|
||||||
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
stateMgr, _ := b.StateMgr(t.Context(), testBackendSingleWorkspaceName)
|
||||||
// An error suggests that the state was not unlocked after apply
|
// An error suggests that the state was not unlocked after apply
|
||||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
if _, err := stateMgr.Lock(t.Context(), statemgr.NewLockInfo()); err != nil {
|
||||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ func (s *State) WriteState(state *states.State) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PersistState uploads a snapshot of the latest state as a StateVersion to Terraform Cloud
|
// PersistState uploads a snapshot of the latest state as a StateVersion to Terraform Cloud
|
||||||
func (s *State) PersistState(schemas *tofu.Schemas) error {
|
func (s *State) PersistState(ctx context.Context, schemas *tofu.Schemas) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ func (s *State) PersistState(schemas *tofu.Schemas) error {
|
|||||||
// We might be writing a new state altogether, but before we do that
|
// We might be writing a new state altogether, but before we do that
|
||||||
// we'll check to make sure there isn't already a snapshot present
|
// we'll check to make sure there isn't already a snapshot present
|
||||||
// that we ought to be updating.
|
// that we ought to be updating.
|
||||||
err := s.refreshState()
|
err := s.refreshState(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed checking for existing remote state: %w", err)
|
return fmt.Errorf("failed checking for existing remote state: %w", err)
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ func (s *State) PersistState(schemas *tofu.Schemas) error {
|
|||||||
return fmt.Errorf("failed to marshal outputs to json: %w", err)
|
return fmt.Errorf("failed to marshal outputs to json: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.uploadState(s.lineage, s.serial, s.forcePush, buf.Bytes(), jsonState, jsonStateOutputs)
|
err = s.uploadState(ctx, s.lineage, s.serial, s.forcePush, buf.Bytes(), jsonState, jsonStateOutputs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.stateUploadErr = true
|
s.stateUploadErr = true
|
||||||
return fmt.Errorf("error uploading state: %w", err)
|
return fmt.Errorf("error uploading state: %w", err)
|
||||||
@@ -298,9 +298,7 @@ func (s *State) uploadStateFallback(ctx context.Context, lineage string, serial
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) uploadState(lineage string, serial uint64, isForcePush bool, state, jsonState, jsonStateOutputs []byte) error {
|
func (s *State) uploadState(ctx context.Context, lineage string, serial uint64, isForcePush bool, state, jsonState, jsonStateOutputs []byte) error {
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
options := tfe.StateVersionUploadOptions{
|
options := tfe.StateVersionUploadOptions{
|
||||||
StateVersionCreateOptions: tfe.StateVersionCreateOptions{
|
StateVersionCreateOptions: tfe.StateVersionCreateOptions{
|
||||||
Lineage: tfe.String(lineage),
|
Lineage: tfe.String(lineage),
|
||||||
@@ -337,14 +335,13 @@ func (s *State) uploadState(lineage string, serial uint64, isForcePush bool, sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock calls the Client's Lock method if it's implemented.
|
// Lock calls the Client's Lock method if it's implemented.
|
||||||
func (s *State) Lock(info *statemgr.LockInfo) (string, error) {
|
func (s *State) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
if s.disableLocks {
|
if s.disableLocks {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
lockErr := &statemgr.LockError{Info: s.lockInfo}
|
lockErr := &statemgr.LockError{Info: s.lockInfo}
|
||||||
|
|
||||||
@@ -367,16 +364,16 @@ func (s *State) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// statemgr.Refresher impl.
|
// statemgr.Refresher impl.
|
||||||
func (s *State) RefreshState() error {
|
func (s *State) RefreshState(ctx context.Context) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
return s.refreshState()
|
return s.refreshState(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// refreshState is the main implementation of RefreshState, but split out so
|
// refreshState is the main implementation of RefreshState, but split out so
|
||||||
// that we can make internal calls to it from methods that are already holding
|
// that we can make internal calls to it from methods that are already holding
|
||||||
// the s.mu lock.
|
// the s.mu lock.
|
||||||
func (s *State) refreshState() error {
|
func (s *State) refreshState(ctx context.Context) error {
|
||||||
payload, err := s.getStatePayload()
|
payload, err := s.getStatePayload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -443,7 +440,7 @@ func (s *State) getStatePayload() (*remote.Payload, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unlock calls the Client's Unlock method if it's implemented.
|
// Unlock calls the Client's Unlock method if it's implemented.
|
||||||
func (s *State) Unlock(id string) error {
|
func (s *State) Unlock(ctx context.Context, id string) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@@ -451,8 +448,6 @@ func (s *State) Unlock(id string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// We first check if there was an error while uploading the latest
|
// We first check if there was an error while uploading the latest
|
||||||
// state. If so, we will not unlock the workspace to prevent any
|
// state. If so, we will not unlock the workspace to prevent any
|
||||||
// changes from being applied until the correct state is uploaded.
|
// changes from being applied until the correct state is uploaded.
|
||||||
@@ -521,9 +516,7 @@ func (s *State) Delete(force bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRootOutputValues fetches output values from Terraform Cloud
|
// GetRootOutputValues fetches output values from Terraform Cloud
|
||||||
func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
func (s *State) GetRootOutputValues(ctx context.Context) (map[string]*states.OutputValue, error) {
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
so, err := s.tfeClient.StateVersionOutputs.ReadCurrent(ctx, s.workspace.ID)
|
so, err := s.tfeClient.StateVersionOutputs.ReadCurrent(ctx, s.workspace.ID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -540,7 +533,7 @@ func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
|||||||
// requires a higher level of authorization.
|
// requires a higher level of authorization.
|
||||||
log.Printf("[DEBUG] falling back to reading full state")
|
log.Printf("[DEBUG] falling back to reading full state")
|
||||||
|
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(ctx); err != nil {
|
||||||
return nil, fmt.Errorf("failed to load state: %w", err)
|
return nil, fmt.Errorf("failed to load state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func TestState_GetRootOutputValues(t *testing.T) {
|
|||||||
state := &State{tfeClient: b.client, organization: b.organization, workspace: &tfe.Workspace{
|
state := &State{tfeClient: b.client, organization: b.organization, workspace: &tfe.Workspace{
|
||||||
ID: "ws-abcd",
|
ID: "ws-abcd",
|
||||||
}, encryption: encryption.StateEncryptionDisabled()}
|
}, encryption: encryption.StateEncryptionDisabled()}
|
||||||
outputs, err := state.GetRootOutputValues()
|
outputs, err := state.GetRootOutputValues(t.Context())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error returned from GetRootOutputValues: %s", err)
|
t.Fatalf("error returned from GetRootOutputValues: %s", err)
|
||||||
@@ -119,7 +119,7 @@ func TestState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
if err := state.uploadState(state.lineage, state.serial, state.forcePush, data, jsonState, jsonStateOutputs); err != nil {
|
if err := state.uploadState(t.Context(), state.lineage, state.serial, state.forcePush, data, jsonState, jsonStateOutputs); err != nil {
|
||||||
t.Fatalf("put: %s", err)
|
t.Fatalf("put: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,25 +175,25 @@ func TestCloudLocks(t *testing.T) {
|
|||||||
infoB.Operation = "test"
|
infoB.Operation = "test"
|
||||||
infoB.Who = "clientB"
|
infoB.Who = "clientB"
|
||||||
|
|
||||||
lockIDA, err := lockerA.Lock(infoA)
|
lockIDA, err := lockerA.Lock(t.Context(), infoA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = lockerB.Lock(infoB)
|
_, err = lockerB.Lock(t.Context(), infoB)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = lockerA.Unlock(lockIDA) // test already failed, no need to check err further
|
_ = lockerA.Unlock(t.Context(), lockIDA) // test already failed, no need to check err further
|
||||||
t.Fatal("client B obtained lock while held by client A")
|
t.Fatal("client B obtained lock while held by client A")
|
||||||
}
|
}
|
||||||
if _, ok := err.(*statemgr.LockError); !ok {
|
if _, ok := err.(*statemgr.LockError); !ok {
|
||||||
t.Errorf("expected a LockError, but was %t: %s", err, err)
|
t.Errorf("expected a LockError, but was %t: %s", err, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := lockerA.Unlock(lockIDA); err != nil {
|
if err := lockerA.Unlock(t.Context(), lockIDA); err != nil {
|
||||||
t.Fatal("error unlocking client A", err)
|
t.Fatal("error unlocking client A", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockIDB, err := lockerB.Lock(infoB)
|
lockIDB, err := lockerB.Lock(t.Context(), infoB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to obtain lock from client B")
|
t.Fatal("unable to obtain lock from client B")
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ func TestCloudLocks(t *testing.T) {
|
|||||||
t.Fatalf("duplicate lock IDs: %q", lockIDB)
|
t.Fatalf("duplicate lock IDs: %q", lockIDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = lockerB.Unlock(lockIDB); err != nil {
|
if err = lockerB.Unlock(t.Context(), lockIDB); err != nil {
|
||||||
t.Fatal("error unlocking client B:", err)
|
t.Fatal("error unlocking client B:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ func TestState_PersistState(t *testing.T) {
|
|||||||
t.Fatal("expected nil initial readState")
|
t.Fatal("expected nil initial readState")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := cloudState.PersistState(nil)
|
err := cloudState.PersistState(t.Context(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected no error, got %q", err)
|
t.Fatalf("expected no error, got %q", err)
|
||||||
}
|
}
|
||||||
@@ -331,7 +331,7 @@ func TestState_PersistState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
cloudState.tfeClient = client
|
cloudState.tfeClient = client
|
||||||
|
|
||||||
err = cloudState.RefreshState()
|
err = cloudState.RefreshState(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -345,7 +345,7 @@ func TestState_PersistState(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cloudState.PersistState(nil)
|
err = cloudState.PersistState(t.Context(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ func TestApply_defaultState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create an existing state file
|
// create an existing state file
|
||||||
if err := statemgr.WriteAndPersist(statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled()), states.NewState(), nil); err != nil {
|
if err := statemgr.WriteAndPersist(t.Context(), statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled()), states.NewState(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,7 +733,7 @@ func TestApply_plan_backup(t *testing.T) {
|
|||||||
// create a state file that needs to be backed up
|
// create a state file that needs to be backed up
|
||||||
fs := statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled())
|
fs := statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled())
|
||||||
fs.StateSnapshotMeta()
|
fs.StateSnapshotMeta()
|
||||||
if err := statemgr.WriteAndPersist(fs, states.NewState(), nil); err != nil {
|
if err := statemgr.WriteAndPersist(t.Context(), fs, states.NewState(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package clistate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -123,12 +124,12 @@ func (s *LocalState) writeState(state *tofu.State) error {
|
|||||||
// PersistState for LocalState is a no-op since WriteState always persists.
|
// PersistState for LocalState is a no-op since WriteState always persists.
|
||||||
//
|
//
|
||||||
// StatePersister impl.
|
// StatePersister impl.
|
||||||
func (s *LocalState) PersistState() error {
|
func (s *LocalState) PersistState(_ context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateRefresher impl.
|
// StateRefresher impl.
|
||||||
func (s *LocalState) RefreshState() error {
|
func (s *LocalState) RefreshState(_ context.Context) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@@ -187,7 +188,7 @@ func (s *LocalState) RefreshState() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock implements a local filesystem state.Locker.
|
// Lock implements a local filesystem state.Locker.
|
||||||
func (s *LocalState) Lock(info *statemgr.LockInfo) (string, error) {
|
func (s *LocalState) Lock(_ context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@@ -219,7 +220,7 @@ func (s *LocalState) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
return s.lockID, s.writeLockInfo(info)
|
return s.lockID, s.writeLockInfo(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LocalState) Unlock(id string) error {
|
func (s *LocalState) Unlock(_ context.Context, id string) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ func (l *locker) Unlock() tfdiags.Diagnostics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := slowmessage.Do(LockThreshold, func() error {
|
err := slowmessage.Do(LockThreshold, func() error {
|
||||||
return l.state.Unlock(l.lockID)
|
return l.state.Unlock(l.ctx, l.lockID)
|
||||||
}, l.view.Unlocking)
|
}, l.view.Unlocking)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@@ -281,7 +282,7 @@ func (c *ImportCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := state.PersistState(schemas); err != nil {
|
if err := state.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ func (c *InitCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sMgr.RefreshState(); err != nil {
|
if err := sMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1257,7 +1257,7 @@ func TestInit_inputFalse(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
if err := statemgr.WriteAndPersist(statemgr.NewFilesystem("foo", encryption.StateEncryptionDisabled()), fooState, nil); err != nil {
|
if err := statemgr.WriteAndPersist(t.Context(), statemgr.NewFilesystem("foo", encryption.StateEncryptionDisabled()), fooState, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
barState := states.BuildState(func(s *states.SyncState) {
|
barState := states.BuildState(func(s *states.SyncState) {
|
||||||
@@ -1268,7 +1268,7 @@ func TestInit_inputFalse(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
if err := statemgr.WriteAndPersist(statemgr.NewFilesystem("bar", encryption.StateEncryptionDisabled()), barState, nil); err != nil {
|
if err := statemgr.WriteAndPersist(t.Context(), statemgr.NewFilesystem("bar", encryption.StateEncryptionDisabled()), barState, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ func (m *Meta) backendFromConfig(ctx context.Context, opts *BackendOpts, enc enc
|
|||||||
// we haven't used a non-local backend before. That is okay.
|
// we haven't used a non-local backend before. That is okay.
|
||||||
statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
|
statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
|
||||||
sMgr := &clistate.LocalState{Path: statePath}
|
sMgr := &clistate.LocalState{Path: statePath}
|
||||||
if err := sMgr.RefreshState(); err != nil {
|
if err := sMgr.RefreshState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf("Failed to load state: %w", err))
|
diags = diags.Append(fmt.Errorf("Failed to load state: %w", err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
@@ -793,7 +793,7 @@ func (m *Meta) backendFromState(ctx context.Context, enc encryption.StateEncrypt
|
|||||||
// we haven't used a non-local backend before. That is okay.
|
// we haven't used a non-local backend before. That is okay.
|
||||||
statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
|
statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
|
||||||
sMgr := &clistate.LocalState{Path: statePath}
|
sMgr := &clistate.LocalState{Path: statePath}
|
||||||
if err := sMgr.RefreshState(); err != nil {
|
if err := sMgr.RefreshState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf("Failed to load state: %w", err))
|
diags = diags.Append(fmt.Errorf("Failed to load state: %w", err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
@@ -943,7 +943,7 @@ func (m *Meta) backend_c_r_S(
|
|||||||
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
|
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if err := sMgr.PersistState(); err != nil {
|
if err := sMgr.PersistState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
|
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
@@ -989,7 +989,7 @@ func (m *Meta) backend_C_r_s(ctx context.Context, c *configs.Backend, cHash int,
|
|||||||
diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
|
diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if err := localState.RefreshState(); err != nil {
|
if err := localState.RefreshState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
|
diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
@@ -1052,7 +1052,7 @@ func (m *Meta) backend_C_r_s(ctx context.Context, c *configs.Backend, cHash int,
|
|||||||
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
|
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if err := localState.PersistState(nil); err != nil {
|
if err := localState.PersistState(context.TODO(), nil); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
|
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
@@ -1112,7 +1112,7 @@ func (m *Meta) backend_C_r_s(ctx context.Context, c *configs.Backend, cHash int,
|
|||||||
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if err := sMgr.PersistState(); err != nil {
|
if err := sMgr.PersistState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
@@ -1244,7 +1244,7 @@ func (m *Meta) backend_C_r_S_changed(ctx context.Context, c *configs.Backend, cH
|
|||||||
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if err := sMgr.PersistState(); err != nil {
|
if err := sMgr.PersistState(context.TODO()); err != nil {
|
||||||
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ func (m *Meta) backendMigrateState_s_s(ctx context.Context, opts *backendMigrate
|
|||||||
return fmt.Errorf(strings.TrimSpace(
|
return fmt.Errorf(strings.TrimSpace(
|
||||||
errMigrateSingleLoadDefault), opts.SourceType, err)
|
errMigrateSingleLoadDefault), opts.SourceType, err)
|
||||||
}
|
}
|
||||||
if err := sourceState.RefreshState(); err != nil {
|
if err := sourceState.RefreshState(context.TODO()); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(
|
return fmt.Errorf(strings.TrimSpace(
|
||||||
errMigrateSingleLoadDefault), opts.SourceType, err)
|
errMigrateSingleLoadDefault), opts.SourceType, err)
|
||||||
}
|
}
|
||||||
@@ -318,7 +318,7 @@ func (m *Meta) backendMigrateState_s_s(ctx context.Context, opts *backendMigrate
|
|||||||
return fmt.Errorf(strings.TrimSpace(
|
return fmt.Errorf(strings.TrimSpace(
|
||||||
errMigrateSingleLoadDefault), opts.DestinationType, err)
|
errMigrateSingleLoadDefault), opts.DestinationType, err)
|
||||||
}
|
}
|
||||||
if err := destinationState.RefreshState(); err != nil {
|
if err := destinationState.RefreshState(context.TODO()); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(
|
return fmt.Errorf(strings.TrimSpace(
|
||||||
errMigrateSingleLoadDefault), opts.DestinationType, err)
|
errMigrateSingleLoadDefault), opts.DestinationType, err)
|
||||||
}
|
}
|
||||||
@@ -371,12 +371,12 @@ func (m *Meta) backendMigrateState_s_s(ctx context.Context, opts *backendMigrate
|
|||||||
// We now own a lock, so double check that we have the version
|
// We now own a lock, so double check that we have the version
|
||||||
// corresponding to the lock.
|
// corresponding to the lock.
|
||||||
log.Print("[TRACE] backendMigrateState: refreshing source workspace state")
|
log.Print("[TRACE] backendMigrateState: refreshing source workspace state")
|
||||||
if err := sourceState.RefreshState(); err != nil {
|
if err := sourceState.RefreshState(context.TODO()); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(
|
return fmt.Errorf(strings.TrimSpace(
|
||||||
errMigrateSingleLoadDefault), opts.SourceType, err)
|
errMigrateSingleLoadDefault), opts.SourceType, err)
|
||||||
}
|
}
|
||||||
log.Print("[TRACE] backendMigrateState: refreshing destination workspace state")
|
log.Print("[TRACE] backendMigrateState: refreshing destination workspace state")
|
||||||
if err := destinationState.RefreshState(); err != nil {
|
if err := destinationState.RefreshState(context.TODO()); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(
|
return fmt.Errorf(strings.TrimSpace(
|
||||||
errMigrateSingleLoadDefault), opts.SourceType, err)
|
errMigrateSingleLoadDefault), opts.SourceType, err)
|
||||||
}
|
}
|
||||||
@@ -455,7 +455,7 @@ func (m *Meta) backendMigrateState_s_s(ctx context.Context, opts *backendMigrate
|
|||||||
// so requiring schemas here could lead to a catch-22 where it requires some manual
|
// so requiring schemas here could lead to a catch-22 where it requires some manual
|
||||||
// intervention to proceed far enough for provider installation. To avoid this,
|
// intervention to proceed far enough for provider installation. To avoid this,
|
||||||
// when migrating to TFC backend, the initial JSON variant of state won't be generated and stored.
|
// when migrating to TFC backend, the initial JSON variant of state won't be generated and stored.
|
||||||
if err := destinationState.PersistState(nil); err != nil {
|
if err := destinationState.PersistState(context.TODO(), nil); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(errBackendStateCopy),
|
return fmt.Errorf(strings.TrimSpace(errBackendStateCopy),
|
||||||
opts.SourceType, opts.DestinationType, err)
|
opts.SourceType, opts.DestinationType, err)
|
||||||
}
|
}
|
||||||
@@ -500,7 +500,7 @@ func (m *Meta) backendMigrateNonEmptyConfirm(
|
|||||||
|
|
||||||
// Helper to write the state
|
// Helper to write the state
|
||||||
saveHelper := func(n, path string, s *states.State) error {
|
saveHelper := func(n, path string, s *states.State) error {
|
||||||
return statemgr.WriteAndPersist(statemgr.NewFilesystem(path, encryption.StateEncryptionDisabled()), s, nil)
|
return statemgr.WriteAndPersist(context.TODO(), statemgr.NewFilesystem(path, encryption.StateEncryptionDisabled()), s, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the states
|
// Write the states
|
||||||
@@ -602,7 +602,7 @@ func (m *Meta) backendMigrateTFC(ctx context.Context, opts *backendMigrateOpts)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := sourceState.RefreshState(); err != nil {
|
if err := sourceState.RefreshState(context.TODO()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if sourceState.State().Empty() {
|
if sourceState.State().Empty() {
|
||||||
@@ -690,7 +690,7 @@ func (m *Meta) backendMigrateState_S_TFC(ctx context.Context, opts *backendMigra
|
|||||||
errMigrateSingleLoadDefault), opts.SourceType, err)
|
errMigrateSingleLoadDefault), opts.SourceType, err)
|
||||||
}
|
}
|
||||||
// RefreshState is what actually pulls the state to be evaluated.
|
// RefreshState is what actually pulls the state to be evaluated.
|
||||||
if err := sourceState.RefreshState(); err != nil {
|
if err := sourceState.RefreshState(context.TODO()); err != nil {
|
||||||
return fmt.Errorf(strings.TrimSpace(
|
return fmt.Errorf(strings.TrimSpace(
|
||||||
errMigrateSingleLoadDefault), opts.SourceType, err)
|
errMigrateSingleLoadDefault), opts.SourceType, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func TestMetaBackend_emptyDir(t *testing.T) {
|
|||||||
if err := s.WriteState(testState()); err != nil {
|
if err := s.WriteState(testState()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ func TestMetaBackend_emptyWithDefaultState(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
if actual := s.State().String(); actual != testState().String() {
|
if actual := s.State().String(); actual != testState().String() {
|
||||||
@@ -146,7 +146,7 @@ func TestMetaBackend_emptyWithDefaultState(t *testing.T) {
|
|||||||
if err := s.WriteState(next); err != nil {
|
if err := s.WriteState(next); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ func TestMetaBackend_emptyWithExplicitState(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
if actual := s.State().String(); actual != testState().String() {
|
if actual := s.State().String(); actual != testState().String() {
|
||||||
@@ -217,7 +217,7 @@ func TestMetaBackend_emptyWithExplicitState(t *testing.T) {
|
|||||||
if err := s.WriteState(next); err != nil {
|
if err := s.WriteState(next); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +264,7 @@ func TestMetaBackend_configureNew(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -279,7 +279,7 @@ func TestMetaBackend_configureNew(t *testing.T) {
|
|||||||
if err := s.WriteState(state); err != nil {
|
if err := s.WriteState(state); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@ func TestMetaBackend_configureNewWithState(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state, err := statemgr.RefreshAndRead(s)
|
state, err := statemgr.RefreshAndRead(t.Context(), s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
@@ -353,7 +353,7 @@ func TestMetaBackend_configureNewWithState(t *testing.T) {
|
|||||||
state = states.NewState()
|
state = states.NewState()
|
||||||
mark := markStateForMatching(state, "changing")
|
mark := markStateForMatching(state, "changing")
|
||||||
|
|
||||||
if err := statemgr.WriteAndPersist(s, state, nil); err != nil {
|
if err := statemgr.WriteAndPersist(t.Context(), s, state, nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,7 +460,7 @@ func TestMetaBackend_configureNewWithStateNoMigrate(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if state := s.State(); state != nil {
|
if state := s.State(); state != nil {
|
||||||
@@ -503,7 +503,7 @@ func TestMetaBackend_configureNewWithStateExisting(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -521,7 +521,7 @@ func TestMetaBackend_configureNewWithStateExisting(t *testing.T) {
|
|||||||
if err := s.WriteState(state); err != nil {
|
if err := s.WriteState(state); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,7 +577,7 @@ func TestMetaBackend_configureNewWithStateExistingNoMigrate(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -594,7 +594,7 @@ func TestMetaBackend_configureNewWithStateExistingNoMigrate(t *testing.T) {
|
|||||||
if err := s.WriteState(state); err != nil {
|
if err := s.WriteState(state); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,7 +644,7 @@ func TestMetaBackend_configuredUnchanged(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -788,7 +788,7 @@ func TestMetaBackend_configuredUnchangedWithStaticEvalVars(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -834,7 +834,7 @@ func TestMetaBackend_configuredChange(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -859,7 +859,7 @@ func TestMetaBackend_configuredChange(t *testing.T) {
|
|||||||
if err := s.WriteState(state); err != nil {
|
if err := s.WriteState(state); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,7 +922,7 @@ func TestMetaBackend_reconfigureChange(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
newState := s.State()
|
newState := s.State()
|
||||||
@@ -932,7 +932,7 @@ func TestMetaBackend_reconfigureChange(t *testing.T) {
|
|||||||
|
|
||||||
// verify that the old state is still there
|
// verify that the old state is still there
|
||||||
s = statemgr.NewFilesystem("local-state.tfstate", encryption.StateEncryptionDisabled())
|
s = statemgr.NewFilesystem("local-state.tfstate", encryption.StateEncryptionDisabled())
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
oldState := s.State()
|
oldState := s.State()
|
||||||
@@ -1062,7 +1062,7 @@ func TestMetaBackend_configuredChangeCopy(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1115,7 +1115,7 @@ func TestMetaBackend_configuredChangeCopy_singleState(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1169,7 +1169,7 @@ func TestMetaBackend_configuredChangeCopy_multiToSingleDefault(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1223,7 +1223,7 @@ func TestMetaBackend_configuredChangeCopy_multiToSingle(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1297,7 +1297,7 @@ func TestMetaBackend_configuredChangeCopy_multiToSingleCurrentEnv(t *testing.T)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1365,7 +1365,7 @@ func TestMetaBackend_configuredChangeCopy_multiToMulti(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1383,7 +1383,7 @@ func TestMetaBackend_configuredChangeCopy_multiToMulti(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1463,7 +1463,7 @@ func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithDefault(t *testing
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1537,7 +1537,7 @@ func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithoutDefault(t *test
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1590,7 +1590,7 @@ func TestMetaBackend_configuredUnset(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1614,7 +1614,7 @@ func TestMetaBackend_configuredUnset(t *testing.T) {
|
|||||||
if err := s.WriteState(testState()); err != nil {
|
if err := s.WriteState(testState()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1654,7 +1654,7 @@ func TestMetaBackend_configuredUnsetCopy(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1674,7 +1674,7 @@ func TestMetaBackend_configuredUnsetCopy(t *testing.T) {
|
|||||||
if err := s.WriteState(testState()); err != nil {
|
if err := s.WriteState(testState()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1724,7 +1724,7 @@ func TestMetaBackend_planLocal(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1755,7 +1755,7 @@ func TestMetaBackend_planLocal(t *testing.T) {
|
|||||||
if err := s.WriteState(state); err != nil {
|
if err := s.WriteState(state); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1807,7 +1807,7 @@ func TestMetaBackend_planLocalStatePath(t *testing.T) {
|
|||||||
statePath := "foo.tfstate"
|
statePath := "foo.tfstate"
|
||||||
|
|
||||||
// put an initial state there that needs to be backed up
|
// put an initial state there that needs to be backed up
|
||||||
err = statemgr.WriteAndPersist(statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled()), original, nil)
|
err = statemgr.WriteAndPersist(t.Context(), statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled()), original, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1827,7 +1827,7 @@ func TestMetaBackend_planLocalStatePath(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1858,7 +1858,7 @@ func TestMetaBackend_planLocalStatePath(t *testing.T) {
|
|||||||
if err := s.WriteState(state); err != nil {
|
if err := s.WriteState(state); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1918,7 +1918,7 @@ func TestMetaBackend_planLocalMatch(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
state := s.State()
|
state := s.State()
|
||||||
@@ -1947,7 +1947,7 @@ func TestMetaBackend_planLocalMatch(t *testing.T) {
|
|||||||
if err := s.WriteState(state); err != nil {
|
if err := s.WriteState(state); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ func (c *OutputCommand) Outputs(ctx context.Context, statePath string, enc encry
|
|||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := stateStore.GetRootOutputValues()
|
output, err := stateStore.GetRootOutputValues(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, diags.Append(err)
|
return nil, diags.Append(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -117,7 +118,7 @@ func (c *ProvidersCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ func TestRefresh_defaultState(t *testing.T) {
|
|||||||
statePath := testStateFile(t, originalState)
|
statePath := testStateFile(t, originalState)
|
||||||
|
|
||||||
localState := statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled())
|
localState := statemgr.NewFilesystem(statePath, encryption.StateEncryptionDisabled())
|
||||||
if err := localState.RefreshState(); err != nil {
|
if err := localState.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
s := localState.State()
|
s := localState.State()
|
||||||
|
|||||||
@@ -521,7 +521,7 @@ func getStateFromBackend(ctx context.Context, b backend.Backend, workspace strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the state store with the latest state snapshot from persistent storage
|
// Refresh the state store with the latest state snapshot from persistent storage
|
||||||
if err := stateStore.RefreshState(); err != nil {
|
if err := stateStore.RefreshState(context.TODO()); err != nil {
|
||||||
tracing.SetSpanError(span, err)
|
tracing.SetSpanError(span, err)
|
||||||
return nil, fmt.Errorf("failed to load state: %w", err)
|
return nil, fmt.Errorf("failed to load state: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ func (c *StateListCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
|
c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateFromMgr.RefreshState(); err != nil {
|
if err := stateFromMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to refresh source state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to refresh source state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -158,7 +159,7 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateToMgr.RefreshState(); err != nil {
|
if err := stateToMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to refresh destination state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to refresh destination state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -420,7 +421,7 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateToMgr.PersistState(schemas); err != nil {
|
if err := stateToMgr.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -431,7 +432,7 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateFromMgr.PersistState(schemas); err != nil {
|
if err := stateFromMgr.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ func (c *StatePullCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
|
c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@@ -128,7 +129,7 @@ func (c *StatePushCommand) Run(args []string) int {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to refresh destination state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to refresh destination state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -155,7 +156,7 @@ func (c *StatePushCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(schemas); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to persist state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to persist state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ func TestStatePush_forceRemoteState(t *testing.T) {
|
|||||||
if err := sMgr.WriteState(states.NewState()); err != nil {
|
if err := sMgr.WriteState(states.NewState()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := sMgr.PersistState(nil); err != nil {
|
if err := sMgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ func (c *StateReplaceProviderCommand) Run(args []string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Refresh and load state
|
// Refresh and load state
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to refresh source state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to refresh source state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -197,7 +198,7 @@ func (c *StateReplaceProviderCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(schemas); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ func (c *StateRmCommand) Run(args []string) int {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -144,7 +145,7 @@ func (c *StateRmCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(schemas); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -138,7 +139,7 @@ func (c *StateShowCommand) Run(args []string) int {
|
|||||||
c.Streams.Eprintln(fmt.Sprintf(errStateLoadingState, err))
|
c.Streams.Eprintln(fmt.Sprintf(errStateLoadingState, err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Streams.Eprintf("Failed to refresh state: %s\n", err)
|
c.Streams.Eprintf("Failed to refresh state: %s\n", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -118,7 +119,7 @@ func (c *TaintCommand) Run(args []string) int {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -193,7 +194,7 @@ func (c *TaintCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(schemas); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
5
internal/command/testdata/statelocker.go
vendored
5
internal/command/testdata/statelocker.go
vendored
@@ -4,6 +4,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -28,7 +29,7 @@ func main() {
|
|||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
info.Info = "state locker"
|
info.Info = "state locker"
|
||||||
|
|
||||||
lockID, err := s.Lock(info)
|
lockID, err := s.Lock(context.Background(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
io.WriteString(os.Stderr, err.Error())
|
io.WriteString(os.Stderr, err.Error())
|
||||||
return
|
return
|
||||||
@@ -38,7 +39,7 @@ func main() {
|
|||||||
io.WriteString(os.Stdout, "LOCKID "+lockID)
|
io.WriteString(os.Stdout, "LOCKID "+lockID)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := s.Unlock(lockID); err != nil {
|
if err := s.Unlock(context.Background(), lockID); err != nil {
|
||||||
io.WriteString(os.Stderr, err.Error())
|
io.WriteString(os.Stderr, err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func (c *UnlockCommand) Run(args []string) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateMgr.Unlock(lockID); err != nil {
|
if err := stateMgr.Unlock(context.TODO(), lockID); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to unlock state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to unlock state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ func (c *UntaintCommand) Run(args []string) int {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -194,7 +195,7 @@ func (c *UntaintCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := stateMgr.PersistState(schemas); err != nil {
|
if err := stateMgr.PersistState(context.TODO(), schemas); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ func TestWorkspace_createWithState(t *testing.T) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
err := statemgr.WriteAndPersist(statemgr.NewFilesystem("test.tfstate", encryption.StateEncryptionDisabled()), originalState, nil)
|
err := statemgr.WriteAndPersist(t.Context(), statemgr.NewFilesystem("test.tfstate", encryption.StateEncryptionDisabled()), originalState, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@ func TestWorkspace_createWithState(t *testing.T) {
|
|||||||
|
|
||||||
newPath := filepath.Join(local.DefaultWorkspaceDir, "test", DefaultStateFilename)
|
newPath := filepath.Join(local.DefaultWorkspaceDir, "test", DefaultStateFilename)
|
||||||
envState := statemgr.NewFilesystem(newPath, encryption.StateEncryptionDisabled())
|
envState := statemgr.NewFilesystem(newPath, encryption.StateEncryptionDisabled())
|
||||||
err = envState.RefreshState()
|
err = envState.RefreshState(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -134,7 +135,7 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
|
|||||||
stateLocker = clistate.NewNoopLocker()
|
stateLocker = clistate.NewNoopLocker()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateMgr.RefreshState(); err != nil {
|
if err := stateMgr.RefreshState(context.TODO()); err != nil {
|
||||||
// We need to release the lock before exit
|
// We need to release the lock before exit
|
||||||
stateLocker.Unlock()
|
stateLocker.Unlock()
|
||||||
c.Ui.Error(err.Error())
|
c.Ui.Error(err.Error())
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -173,7 +174,7 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
|
|||||||
c.Ui.Error(err.Error())
|
c.Ui.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
err = stateMgr.PersistState(nil)
|
err = stateMgr.PersistState(context.TODO(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(err.Error())
|
c.Ui.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/states/statemgr"
|
"github.com/opentofu/opentofu/internal/states/statemgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,9 +15,9 @@ import (
|
|||||||
// driver. It supports dumb put/get/delete, and the higher level structs
|
// driver. It supports dumb put/get/delete, and the higher level structs
|
||||||
// handle persisting the state properly here.
|
// handle persisting the state properly here.
|
||||||
type Client interface {
|
type Client interface {
|
||||||
Get() (*Payload, error)
|
Get(context.Context) (*Payload, error)
|
||||||
Put([]byte) error
|
Put(context.Context, []byte) error
|
||||||
Delete() error
|
Delete(context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientForcePusher is an optional interface that allows a remote
|
// ClientForcePusher is an optional interface that allows a remote
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -15,7 +16,7 @@ func TestRemoteClient_noPayload(t *testing.T) {
|
|||||||
s := &State{
|
s := &State{
|
||||||
Client: nilClient{},
|
Client: nilClient{},
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal("error refreshing empty remote state")
|
t.Fatal("error refreshing empty remote state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,11 +24,11 @@ func TestRemoteClient_noPayload(t *testing.T) {
|
|||||||
// nilClient returns nil for everything
|
// nilClient returns nil for everything
|
||||||
type nilClient struct{}
|
type nilClient struct{}
|
||||||
|
|
||||||
func (nilClient) Get() (*Payload, error) { return nil, nil }
|
func (nilClient) Get(context.Context) (*Payload, error) { return nil, nil }
|
||||||
|
|
||||||
func (c nilClient) Put([]byte) error { return nil }
|
func (c nilClient) Put(context.Context, []byte) error { return nil }
|
||||||
|
|
||||||
func (c nilClient) Delete() error { return nil }
|
func (c nilClient) Delete(context.Context) error { return nil }
|
||||||
|
|
||||||
// mockClient is a client that tracks persisted state snapshots only in
|
// mockClient is a client that tracks persisted state snapshots only in
|
||||||
// memory and also logs what it has been asked to do for use in test
|
// memory and also logs what it has been asked to do for use in test
|
||||||
@@ -42,7 +43,7 @@ type mockClientRequest struct {
|
|||||||
Content map[string]interface{}
|
Content map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockClient) Get() (*Payload, error) {
|
func (c *mockClient) Get(_ context.Context) (*Payload, error) {
|
||||||
c.appendLog("Get", c.current)
|
c.appendLog("Get", c.current)
|
||||||
if c.current == nil {
|
if c.current == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -54,13 +55,13 @@ func (c *mockClient) Get() (*Payload, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockClient) Put(data []byte) error {
|
func (c *mockClient) Put(_ context.Context, data []byte) error {
|
||||||
c.appendLog("Put", data)
|
c.appendLog("Put", data)
|
||||||
c.current = data
|
c.current = data
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockClient) Delete() error {
|
func (c *mockClient) Delete(_ context.Context) error {
|
||||||
c.appendLog("Delete", c.current)
|
c.appendLog("Delete", c.current)
|
||||||
c.current = nil
|
c.current = nil
|
||||||
return nil
|
return nil
|
||||||
@@ -91,7 +92,7 @@ type mockClientForcePusher struct {
|
|||||||
log []mockClientRequest
|
log []mockClientRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockClientForcePusher) Get() (*Payload, error) {
|
func (c *mockClientForcePusher) Get(_ context.Context) (*Payload, error) {
|
||||||
c.appendLog("Get", c.current)
|
c.appendLog("Get", c.current)
|
||||||
if c.current == nil {
|
if c.current == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -103,7 +104,7 @@ func (c *mockClientForcePusher) Get() (*Payload, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockClientForcePusher) Put(data []byte) error {
|
func (c *mockClientForcePusher) Put(_ context.Context, data []byte) error {
|
||||||
if c.force {
|
if c.force {
|
||||||
c.appendLog("Force Put", data)
|
c.appendLog("Force Put", data)
|
||||||
} else {
|
} else {
|
||||||
@@ -118,7 +119,7 @@ func (c *mockClientForcePusher) EnableForcePush() {
|
|||||||
c.force = true
|
c.force = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockClientForcePusher) Delete() error {
|
func (c *mockClientForcePusher) Delete(_ context.Context) error {
|
||||||
c.appendLog("Delete", c.current)
|
c.appendLog("Delete", c.current)
|
||||||
c.current = nil
|
c.current = nil
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package remote
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -77,8 +78,8 @@ func (s *State) State() *states.State {
|
|||||||
return s.state.DeepCopy()
|
return s.state.DeepCopy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
func (s *State) GetRootOutputValues(ctx context.Context) (map[string]*states.OutputValue, error) {
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(ctx); err != nil {
|
||||||
return nil, fmt.Errorf("Failed to load state: %w", err)
|
return nil, fmt.Errorf("Failed to load state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,17 +143,17 @@ func (s *State) WriteStateForMigration(f *statefile.File, force bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// statemgr.Refresher impl.
|
// statemgr.Refresher impl.
|
||||||
func (s *State) RefreshState() error {
|
func (s *State) RefreshState(ctx context.Context) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
return s.refreshState()
|
return s.refreshState(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// refreshState is the main implementation of RefreshState, but split out so
|
// refreshState is the main implementation of RefreshState, but split out so
|
||||||
// that we can make internal calls to it from methods that are already holding
|
// that we can make internal calls to it from methods that are already holding
|
||||||
// the s.mu lock.
|
// the s.mu lock.
|
||||||
func (s *State) refreshState() error {
|
func (s *State) refreshState(ctx context.Context) error {
|
||||||
payload, err := s.Client.Get()
|
payload, err := s.Client.Get(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -184,7 +185,7 @@ func (s *State) refreshState() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// statemgr.Persister impl.
|
// statemgr.Persister impl.
|
||||||
func (s *State) PersistState(schemas *tofu.Schemas) error {
|
func (s *State) PersistState(ctx context.Context, schemas *tofu.Schemas) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@@ -204,7 +205,7 @@ func (s *State) PersistState(schemas *tofu.Schemas) error {
|
|||||||
// We might be writing a new state altogether, but before we do that
|
// We might be writing a new state altogether, but before we do that
|
||||||
// we'll check to make sure there isn't already a snapshot present
|
// we'll check to make sure there isn't already a snapshot present
|
||||||
// that we ought to be updating.
|
// that we ought to be updating.
|
||||||
err := s.refreshState()
|
err := s.refreshState(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed checking for existing remote state: %w", err)
|
return fmt.Errorf("failed checking for existing remote state: %w", err)
|
||||||
}
|
}
|
||||||
@@ -228,7 +229,7 @@ func (s *State) PersistState(schemas *tofu.Schemas) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Client.Put(buf.Bytes())
|
err = s.Client.Put(ctx, buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -255,7 +256,7 @@ func (s *State) ShouldPersistIntermediateState(info *local.IntermediateStatePers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock calls the Client's Lock method if it's implemented.
|
// Lock calls the Client's Lock method if it's implemented.
|
||||||
func (s *State) Lock(info *statemgr.LockInfo) (string, error) {
|
func (s *State) Lock(ctx context.Context, info *statemgr.LockInfo) (string, error) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@@ -264,13 +265,13 @@ func (s *State) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c, ok := s.Client.(ClientLocker); ok {
|
if c, ok := s.Client.(ClientLocker); ok {
|
||||||
return c.Lock(info)
|
return c.Lock(ctx, info)
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock calls the Client's Unlock method if it's implemented.
|
// Unlock calls the Client's Unlock method if it's implemented.
|
||||||
func (s *State) Unlock(id string) error {
|
func (s *State) Unlock(ctx context.Context, id string) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@@ -279,7 +280,7 @@ func (s *State) Unlock(id string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c, ok := s.Client.(ClientLocker); ok {
|
if c, ok := s.Client.(ClientLocker); ok {
|
||||||
return c.Unlock(id)
|
return c.Unlock(ctx, id)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -46,10 +47,10 @@ func TestStateRace(t *testing.T) {
|
|||||||
if err := s.WriteState(current); err != nil {
|
if err := s.WriteState(current); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := s.PersistState(nil); err != nil {
|
if err := s.PersistState(t.Context(), nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -342,7 +343,7 @@ func TestStatePersist(t *testing.T) {
|
|||||||
// before any writes would happen, so we'll mimic that here for realism.
|
// before any writes would happen, so we'll mimic that here for realism.
|
||||||
// NB This causes a GET to be logged so the first item in the test cases
|
// NB This causes a GET to be logged so the first item in the test cases
|
||||||
// must account for this
|
// must account for this
|
||||||
if err := mgr.RefreshState(); err != nil {
|
if err := mgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("failed to RefreshState: %s", err)
|
t.Fatalf("failed to RefreshState: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +364,7 @@ func TestStatePersist(t *testing.T) {
|
|||||||
if err := mgr.WriteState(s); err != nil {
|
if err := mgr.WriteState(s); err != nil {
|
||||||
t.Fatalf("failed to WriteState for %q: %s", tc.name, err)
|
t.Fatalf("failed to WriteState for %q: %s", tc.name, err)
|
||||||
}
|
}
|
||||||
if err := mgr.PersistState(nil); err != nil {
|
if err := mgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatalf("failed to PersistState for %q: %s", tc.name, err)
|
t.Fatalf("failed to PersistState for %q: %s", tc.name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +413,7 @@ func TestState_GetRootOutputValues(t *testing.T) {
|
|||||||
encryption.StateEncryptionDisabled(),
|
encryption.StateEncryptionDisabled(),
|
||||||
)
|
)
|
||||||
|
|
||||||
outputs, err := mgr.GetRootOutputValues()
|
outputs, err := mgr.GetRootOutputValues(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected GetRootOutputValues to not return an error, but it returned %v", err)
|
t.Errorf("Expected GetRootOutputValues to not return an error, but it returned %v", err)
|
||||||
}
|
}
|
||||||
@@ -528,7 +529,7 @@ func TestWriteStateForMigration(t *testing.T) {
|
|||||||
// before any writes would happen, so we'll mimic that here for realism.
|
// before any writes would happen, so we'll mimic that here for realism.
|
||||||
// NB This causes a GET to be logged so the first item in the test cases
|
// NB This causes a GET to be logged so the first item in the test cases
|
||||||
// must account for this
|
// must account for this
|
||||||
if err := mgr.RefreshState(); err != nil {
|
if err := mgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("failed to RefreshState: %s", err)
|
t.Fatalf("failed to RefreshState: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,7 +571,7 @@ func TestWriteStateForMigration(t *testing.T) {
|
|||||||
if err := mgr.WriteState(mgr.State()); err != nil {
|
if err := mgr.WriteState(mgr.State()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := mgr.PersistState(nil); err != nil {
|
if err := mgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,7 +690,7 @@ func TestWriteStateForMigrationWithForcePushClient(t *testing.T) {
|
|||||||
// before any writes would happen, so we'll mimic that here for realism.
|
// before any writes would happen, so we'll mimic that here for realism.
|
||||||
// NB This causes a GET to be logged so the first item in the test cases
|
// NB This causes a GET to be logged so the first item in the test cases
|
||||||
// must account for this
|
// must account for this
|
||||||
if err := mgr.RefreshState(); err != nil {
|
if err := mgr.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("failed to RefreshState: %s", err)
|
t.Fatalf("failed to RefreshState: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,7 +742,7 @@ func TestWriteStateForMigrationWithForcePushClient(t *testing.T) {
|
|||||||
if err := mgr.WriteState(mgr.State()); err != nil {
|
if err := mgr.WriteState(mgr.State()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := mgr.PersistState(nil); err != nil {
|
if err := mgr.PersistState(t.Context(), nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -773,12 +774,12 @@ type mockClientLocker struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implement the mock Lock method for mockOptionalClientLocker
|
// Implement the mock Lock method for mockOptionalClientLocker
|
||||||
func (c *mockOptionalClientLocker) Lock(_ *statemgr.LockInfo) (string, error) {
|
func (c *mockOptionalClientLocker) Lock(_ context.Context, _ *statemgr.LockInfo) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the mock Unlock method for mockOptionalClientLocker
|
// Implement the mock Unlock method for mockOptionalClientLocker
|
||||||
func (c *mockOptionalClientLocker) Unlock(_ string) error {
|
func (c *mockOptionalClientLocker) Unlock(_ context.Context, _ string) error {
|
||||||
// Provide a simple implementation
|
// Provide a simple implementation
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -789,12 +790,12 @@ func (c *mockOptionalClientLocker) IsLockingEnabled() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implement the mock Lock method for mockClientLocker
|
// Implement the mock Lock method for mockClientLocker
|
||||||
func (c *mockClientLocker) Lock(_ *statemgr.LockInfo) (string, error) {
|
func (c *mockClientLocker) Lock(_ context.Context, _ *statemgr.LockInfo) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the mock Unlock method for mockClientLocker
|
// Implement the mock Unlock method for mockClientLocker
|
||||||
func (c *mockClientLocker) Unlock(_ string) error {
|
func (c *mockClientLocker) Unlock(_ context.Context, _ string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ func TestClient(t *testing.T, c Client) {
|
|||||||
}
|
}
|
||||||
data := buf.Bytes()
|
data := buf.Bytes()
|
||||||
|
|
||||||
if err := c.Put(data); err != nil {
|
if err := c.Put(t.Context(), data); err != nil {
|
||||||
t.Fatalf("put: %s", err)
|
t.Fatalf("put: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := c.Get()
|
p, err := c.Get(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("get: %s", err)
|
t.Fatalf("get: %s", err)
|
||||||
}
|
}
|
||||||
@@ -37,11 +37,11 @@ func TestClient(t *testing.T, c Client) {
|
|||||||
t.Fatalf("expected full state %q\n\ngot: %q", string(p.Data), string(data))
|
t.Fatalf("expected full state %q\n\ngot: %q", string(p.Data), string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.Delete(); err != nil {
|
if err := c.Delete(t.Context()); err != nil {
|
||||||
t.Fatalf("delete: %s", err)
|
t.Fatalf("delete: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err = c.Get()
|
p, err = c.Get(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("get: %s", err)
|
t.Fatalf("get: %s", err)
|
||||||
}
|
}
|
||||||
@@ -73,14 +73,14 @@ func TestRemoteLocks(t *testing.T, a, b Client) {
|
|||||||
infoB.Operation = "test"
|
infoB.Operation = "test"
|
||||||
infoB.Who = "clientB"
|
infoB.Who = "clientB"
|
||||||
|
|
||||||
lockIDA, err := lockerA.Lock(infoA)
|
lockIDA, err := lockerA.Lock(t.Context(), infoA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to get initial lock:", err)
|
t.Fatal("unable to get initial lock:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = lockerB.Lock(infoB)
|
_, err = lockerB.Lock(t.Context(), infoB)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := lockerA.Unlock(lockIDA); err != nil {
|
if err := lockerA.Unlock(t.Context(), lockIDA); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
t.Fatal("client B obtained lock while held by client A")
|
t.Fatal("client B obtained lock while held by client A")
|
||||||
@@ -89,11 +89,11 @@ func TestRemoteLocks(t *testing.T, a, b Client) {
|
|||||||
t.Errorf("expected a LockError, but was %t: %s", err, err)
|
t.Errorf("expected a LockError, but was %t: %s", err, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := lockerA.Unlock(lockIDA); err != nil {
|
if err := lockerA.Unlock(t.Context(), lockIDA); err != nil {
|
||||||
t.Fatal("error unlocking client A", err)
|
t.Fatal("error unlocking client A", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockIDB, err := lockerB.Lock(infoB)
|
lockIDB, err := lockerB.Lock(t.Context(), infoB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unable to obtain lock from client B")
|
t.Fatal("unable to obtain lock from client B")
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ func TestRemoteLocks(t *testing.T, a, b Client) {
|
|||||||
t.Fatalf("duplicate lock IDs: %q", lockIDB)
|
t.Fatalf("duplicate lock IDs: %q", lockIDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = lockerB.Unlock(lockIDB); err != nil {
|
if err = lockerB.Unlock(t.Context(), lockIDB); err != nil {
|
||||||
t.Fatal("error unlocking client B:", err)
|
t.Fatal("error unlocking client B:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package statemgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -158,7 +159,7 @@ func (s *Filesystem) writeState(state *states.State, meta *SnapshotMeta) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PersistState writes state to a tfstate file.
|
// PersistState writes state to a tfstate file.
|
||||||
func (s *Filesystem) PersistState(schemas *tofu.Schemas) error {
|
func (s *Filesystem) PersistState(_ context.Context, schemas *tofu.Schemas) error {
|
||||||
defer s.mutex()()
|
defer s.mutex()()
|
||||||
|
|
||||||
return s.persistState(schemas)
|
return s.persistState(schemas)
|
||||||
@@ -249,13 +250,13 @@ func (s *Filesystem) persistState(schemas *tofu.Schemas) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RefreshState is an implementation of Refresher.
|
// RefreshState is an implementation of Refresher.
|
||||||
func (s *Filesystem) RefreshState() error {
|
func (s *Filesystem) RefreshState(_ context.Context) error {
|
||||||
defer s.mutex()()
|
defer s.mutex()()
|
||||||
return s.refreshState()
|
return s.refreshState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Filesystem) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
func (s *Filesystem) GetRootOutputValues(ctx context.Context) (map[string]*states.OutputValue, error) {
|
||||||
err := s.RefreshState()
|
err := s.RefreshState(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -331,7 +332,7 @@ func (s *Filesystem) refreshState() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock implements Locker using filesystem discretionary locks.
|
// Lock implements Locker using filesystem discretionary locks.
|
||||||
func (s *Filesystem) Lock(info *LockInfo) (string, error) {
|
func (s *Filesystem) Lock(_ context.Context, info *LockInfo) (string, error) {
|
||||||
defer s.mutex()()
|
defer s.mutex()()
|
||||||
|
|
||||||
if s.stateFileOut == nil {
|
if s.stateFileOut == nil {
|
||||||
@@ -364,7 +365,7 @@ func (s *Filesystem) Lock(info *LockInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unlock is the companion to Lock, completing the implementation of Locker.
|
// Unlock is the companion to Lock, completing the implementation of Locker.
|
||||||
func (s *Filesystem) Unlock(id string) error {
|
func (s *Filesystem) Unlock(_ context.Context, id string) error {
|
||||||
defer s.mutex()()
|
defer s.mutex()()
|
||||||
|
|
||||||
if s.lockID == "" {
|
if s.lockID == "" {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func TestFilesystemLocks(t *testing.T) {
|
|||||||
// lock first
|
// lock first
|
||||||
info := NewLockInfo()
|
info := NewLockInfo()
|
||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
lockID, err := s.Lock(info)
|
lockID, err := s.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -84,22 +84,22 @@ func TestFilesystemLocks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// a noop, since we unlock on exit
|
// a noop, since we unlock on exit
|
||||||
if err := s.Unlock(lockID); err != nil {
|
if err := s.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// local locks can re-lock
|
// local locks can re-lock
|
||||||
lockID, err = s.Lock(info)
|
lockID, err = s.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Unlock(lockID); err != nil {
|
if err := s.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we should not be able to unlock the same lock twice
|
// we should not be able to unlock the same lock twice
|
||||||
if err := s.Unlock(lockID); err == nil {
|
if err := s.Unlock(t.Context(), lockID); err == nil {
|
||||||
t.Fatal("unlocking an unlocked state should fail")
|
t.Fatal("unlocking an unlocked state should fail")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,12 +120,12 @@ func TestFilesystem_writeWhileLocked(t *testing.T) {
|
|||||||
// lock first
|
// lock first
|
||||||
info := NewLockInfo()
|
info := NewLockInfo()
|
||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
lockID, err := s.Lock(info)
|
lockID, err := s.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := s.Unlock(lockID); err != nil {
|
if err := s.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -256,17 +256,17 @@ func TestFilesystem_backupAndReadPath(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
err = WriteAndPersist(ls, newState, nil)
|
err = WriteAndPersist(t.Context(), ls, newState, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to write new state: %s", err)
|
t.Fatalf("failed to write new state: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockID, err := ls.Lock(info)
|
lockID, err := ls.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ls.Unlock(lockID); err != nil {
|
if err := ls.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +308,7 @@ func TestFilesystem_backupAndReadPath(t *testing.T) {
|
|||||||
func TestFilesystem_nonExist(t *testing.T) {
|
func TestFilesystem_nonExist(t *testing.T) {
|
||||||
defer testOverrideVersion(t, "1.2.3")()
|
defer testOverrideVersion(t, "1.2.3")()
|
||||||
ls := NewFilesystem("ishouldntexist", encryption.StateEncryptionDisabled())
|
ls := NewFilesystem("ishouldntexist", encryption.StateEncryptionDisabled())
|
||||||
if err := ls.RefreshState(); err != nil {
|
if err := ls.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ func TestFilesystem_lockUnlockWithoutWrite(t *testing.T) {
|
|||||||
os.Remove(ls.path)
|
os.Remove(ls.path)
|
||||||
|
|
||||||
// Lock the state, and in doing so recreate the tempfile
|
// Lock the state, and in doing so recreate the tempfile
|
||||||
lockID, err := ls.Lock(info)
|
lockID, err := ls.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -336,7 +336,7 @@ func TestFilesystem_lockUnlockWithoutWrite(t *testing.T) {
|
|||||||
t.Fatal("should have marked state as created")
|
t.Fatal("should have marked state as created")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ls.Unlock(lockID); err != nil {
|
if err := ls.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +381,7 @@ func testFilesystem(t *testing.T) *Filesystem {
|
|||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
ls := NewFilesystem(f.Name(), encryption.StateEncryptionDisabled())
|
ls := NewFilesystem(f.Name(), encryption.StateEncryptionDisabled())
|
||||||
if err := ls.RefreshState(); err != nil {
|
if err := ls.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatalf("initial refresh failed: %s", err)
|
t.Fatalf("initial refresh failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,17 +413,17 @@ func TestFilesystem_refreshWhileLocked(t *testing.T) {
|
|||||||
// lock first
|
// lock first
|
||||||
info := NewLockInfo()
|
info := NewLockInfo()
|
||||||
info.Operation = "test"
|
info.Operation = "test"
|
||||||
lockID, err := s.Lock(info)
|
lockID, err := s.Lock(t.Context(), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := s.Unlock(lockID); err != nil {
|
if err := s.Unlock(t.Context(), lockID); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := s.RefreshState(); err != nil {
|
if err := s.RefreshState(t.Context()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ func TestFilesystem_refreshWhileLocked(t *testing.T) {
|
|||||||
func TestFilesystem_GetRootOutputValues(t *testing.T) {
|
func TestFilesystem_GetRootOutputValues(t *testing.T) {
|
||||||
fs := testFilesystem(t)
|
fs := testFilesystem(t)
|
||||||
|
|
||||||
outputs, err := fs.GetRootOutputValues()
|
outputs, err := fs.GetRootOutputValues(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected GetRootOutputValues to not return an error, but it returned %v", err)
|
t.Errorf("Expected GetRootOutputValues to not return an error, but it returned %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ package statemgr
|
|||||||
// operations done against full state managers.
|
// operations done against full state managers.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/states"
|
"github.com/opentofu/opentofu/internal/states"
|
||||||
"github.com/opentofu/opentofu/internal/states/statefile"
|
"github.com/opentofu/opentofu/internal/states/statefile"
|
||||||
"github.com/opentofu/opentofu/internal/tofu"
|
"github.com/opentofu/opentofu/internal/tofu"
|
||||||
@@ -30,8 +32,8 @@ func NewStateFile() *statefile.File {
|
|||||||
//
|
//
|
||||||
// This is a wrapper around calling RefreshState and then State on the given
|
// This is a wrapper around calling RefreshState and then State on the given
|
||||||
// manager.
|
// manager.
|
||||||
func RefreshAndRead(mgr Storage) (*states.State, error) {
|
func RefreshAndRead(ctx context.Context, mgr Storage) (*states.State, error) {
|
||||||
err := mgr.RefreshState()
|
err := mgr.RefreshState(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -50,10 +52,10 @@ func RefreshAndRead(mgr Storage) (*states.State, error) {
|
|||||||
// out quickly with a user-facing error. In situations where more control
|
// out quickly with a user-facing error. In situations where more control
|
||||||
// is required, call WriteState and PersistState on the state manager directly
|
// is required, call WriteState and PersistState on the state manager directly
|
||||||
// and handle their errors.
|
// and handle their errors.
|
||||||
func WriteAndPersist(mgr Storage, state *states.State, schemas *tofu.Schemas) error {
|
func WriteAndPersist(ctx context.Context, mgr Storage, state *states.State, schemas *tofu.Schemas) error {
|
||||||
err := mgr.WriteState(state)
|
err := mgr.WriteState(state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return mgr.PersistState(schemas)
|
return mgr.PersistState(ctx, schemas)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
package statemgr
|
package statemgr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/states"
|
"github.com/opentofu/opentofu/internal/states"
|
||||||
"github.com/opentofu/opentofu/internal/tofu"
|
"github.com/opentofu/opentofu/internal/tofu"
|
||||||
)
|
)
|
||||||
@@ -25,26 +27,26 @@ func (s *LockDisabled) State() *states.State {
|
|||||||
return s.Inner.State()
|
return s.Inner.State()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LockDisabled) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
func (s *LockDisabled) GetRootOutputValues(ctx context.Context) (map[string]*states.OutputValue, error) {
|
||||||
return s.Inner.GetRootOutputValues()
|
return s.Inner.GetRootOutputValues(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LockDisabled) WriteState(v *states.State) error {
|
func (s *LockDisabled) WriteState(v *states.State) error {
|
||||||
return s.Inner.WriteState(v)
|
return s.Inner.WriteState(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LockDisabled) RefreshState() error {
|
func (s *LockDisabled) RefreshState(ctx context.Context) error {
|
||||||
return s.Inner.RefreshState()
|
return s.Inner.RefreshState(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LockDisabled) PersistState(schemas *tofu.Schemas) error {
|
func (s *LockDisabled) PersistState(ctx context.Context, schemas *tofu.Schemas) error {
|
||||||
return s.Inner.PersistState(schemas)
|
return s.Inner.PersistState(ctx, schemas)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LockDisabled) Lock(info *LockInfo) (string, error) {
|
func (s *LockDisabled) Lock(_ context.Context, info *LockInfo) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LockDisabled) Unlock(id string) error {
|
func (s *LockDisabled) Unlock(_ context.Context, id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ type Locker interface {
|
|||||||
// an instance of LockError immediately if the lock is already held,
|
// an instance of LockError immediately if the lock is already held,
|
||||||
// and the helper function LockWithContext uses this to automatically
|
// and the helper function LockWithContext uses this to automatically
|
||||||
// retry lock acquisition periodically until a timeout is reached.
|
// retry lock acquisition periodically until a timeout is reached.
|
||||||
Lock(info *LockInfo) (string, error)
|
Lock(ctx context.Context, info *LockInfo) (string, error)
|
||||||
|
|
||||||
// Unlock releases a lock previously acquired by Lock.
|
// Unlock releases a lock previously acquired by Lock.
|
||||||
//
|
//
|
||||||
@@ -63,7 +63,7 @@ type Locker interface {
|
|||||||
// another user with some sort of administrative override privilege --
|
// another user with some sort of administrative override privilege --
|
||||||
// then an error is returned explaining the situation in a way that
|
// then an error is returned explaining the situation in a way that
|
||||||
// is suitable for returning to an end-user.
|
// is suitable for returning to an end-user.
|
||||||
Unlock(id string) error
|
Unlock(ctx context.Context, id string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// OptionalLocker extends Locker interface to allow callers
|
// OptionalLocker extends Locker interface to allow callers
|
||||||
@@ -88,7 +88,10 @@ func LockWithContext(ctx context.Context, s Locker, info *LockInfo) (string, err
|
|||||||
delay := time.Second
|
delay := time.Second
|
||||||
maxDelay := 16 * time.Second
|
maxDelay := 16 * time.Second
|
||||||
for {
|
for {
|
||||||
id, err := s.Lock(info)
|
// We disable cancellation on the context passed to s.Lock
|
||||||
|
// because we want it to run to completion if possible and then
|
||||||
|
// we'll check context cancellation explicitly below.
|
||||||
|
id, err := s.Lock(context.WithoutCancel(ctx), info)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
package statemgr
|
package statemgr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
version "github.com/hashicorp/go-version"
|
version "github.com/hashicorp/go-version"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/states"
|
"github.com/opentofu/opentofu/internal/states"
|
||||||
@@ -33,7 +35,7 @@ type Persistent interface {
|
|||||||
// to differentiate reading the state and reading the outputs within the state.
|
// to differentiate reading the state and reading the outputs within the state.
|
||||||
type OutputReader interface {
|
type OutputReader interface {
|
||||||
// GetRootOutputValues fetches the root module output values from state or another source
|
// GetRootOutputValues fetches the root module output values from state or another source
|
||||||
GetRootOutputValues() (map[string]*states.OutputValue, error)
|
GetRootOutputValues(context.Context) (map[string]*states.OutputValue, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresher is the interface for managers that can read snapshots from
|
// Refresher is the interface for managers that can read snapshots from
|
||||||
@@ -63,7 +65,7 @@ type Refresher interface {
|
|||||||
// return only a subset of what was written. Callers must assume that
|
// return only a subset of what was written. Callers must assume that
|
||||||
// ephemeral portions of the state may be unpopulated after calling
|
// ephemeral portions of the state may be unpopulated after calling
|
||||||
// RefreshState.
|
// RefreshState.
|
||||||
RefreshState() error
|
RefreshState(context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persister is the interface for managers that can write snapshots to
|
// Persister is the interface for managers that can write snapshots to
|
||||||
@@ -83,7 +85,7 @@ type Refresher interface {
|
|||||||
// state. For example, when representing state in an external JSON
|
// state. For example, when representing state in an external JSON
|
||||||
// representation.
|
// representation.
|
||||||
type Persister interface {
|
type Persister interface {
|
||||||
PersistState(*tofu.Schemas) error
|
PersistState(context.Context, *tofu.Schemas) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// PersistentMeta is an optional extension to Persistent that allows inspecting
|
// PersistentMeta is an optional extension to Persistent that allows inspecting
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package statemgr
|
package statemgr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -63,19 +64,19 @@ func (m *fakeFull) WriteState(s *states.State) error {
|
|||||||
return m.t.WriteState(s)
|
return m.t.WriteState(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeFull) RefreshState() error {
|
func (m *fakeFull) RefreshState(_ context.Context) error {
|
||||||
return m.t.WriteState(m.fakeP.State())
|
return m.t.WriteState(m.fakeP.State())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeFull) PersistState(schemas *tofu.Schemas) error {
|
func (m *fakeFull) PersistState(_ context.Context, schemas *tofu.Schemas) error {
|
||||||
return m.fakeP.WriteState(m.t.State())
|
return m.fakeP.WriteState(m.t.State())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeFull) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
func (m *fakeFull) GetRootOutputValues(_ context.Context) (map[string]*states.OutputValue, error) {
|
||||||
return m.State().RootModule().OutputValues, nil
|
return m.State().RootModule().OutputValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeFull) Lock(info *LockInfo) (string, error) {
|
func (m *fakeFull) Lock(_ context.Context, info *LockInfo) (string, error) {
|
||||||
m.lockLock.Lock()
|
m.lockLock.Lock()
|
||||||
defer m.lockLock.Unlock()
|
defer m.lockLock.Unlock()
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ func (m *fakeFull) Lock(info *LockInfo) (string, error) {
|
|||||||
return "placeholder", nil
|
return "placeholder", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeFull) Unlock(id string) error {
|
func (m *fakeFull) Unlock(_ context.Context, id string) error {
|
||||||
m.lockLock.Lock()
|
m.lockLock.Lock()
|
||||||
defer m.lockLock.Unlock()
|
defer m.lockLock.Unlock()
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ func (m *fakeErrorFull) State() *states.State {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeErrorFull) GetRootOutputValues() (map[string]*states.OutputValue, error) {
|
func (m *fakeErrorFull) GetRootOutputValues(_ context.Context) (map[string]*states.OutputValue, error) {
|
||||||
return nil, errors.New("fake state manager error")
|
return nil, errors.New("fake state manager error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,18 +130,18 @@ func (m *fakeErrorFull) WriteState(s *states.State) error {
|
|||||||
return errors.New("fake state manager error")
|
return errors.New("fake state manager error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeErrorFull) RefreshState() error {
|
func (m *fakeErrorFull) RefreshState(_ context.Context) error {
|
||||||
return errors.New("fake state manager error")
|
return errors.New("fake state manager error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeErrorFull) PersistState(schemas *tofu.Schemas) error {
|
func (m *fakeErrorFull) PersistState(_ context.Context, schemas *tofu.Schemas) error {
|
||||||
return errors.New("fake state manager error")
|
return errors.New("fake state manager error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeErrorFull) Lock(info *LockInfo) (string, error) {
|
func (m *fakeErrorFull) Lock(_ context.Context, info *LockInfo) (string, error) {
|
||||||
return "placeholder", nil
|
return "placeholder", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeErrorFull) Unlock(id string) error {
|
func (m *fakeErrorFull) Unlock(_ context.Context, id string) error {
|
||||||
return errors.New("fake state manager error")
|
return errors.New("fake state manager error")
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user