mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
Make backend.DeleteWorkspace accept a context (#782)
Signed-off-by: Marcin Wyszynski <marcin.pixie@gmail.com>
This commit is contained in:
@@ -112,7 +112,7 @@ type Backend interface {
|
|||||||
// DeleteWorkspace cannot prevent deleting a state that is in use. It is
|
// DeleteWorkspace cannot prevent deleting a state that is in use. It is
|
||||||
// the responsibility of the caller to hold a Lock for the state manager
|
// the responsibility of the caller to hold a Lock for the state manager
|
||||||
// belonging to this workspace before calling this method.
|
// belonging to this workspace before calling this method.
|
||||||
DeleteWorkspace(name string, force bool) error
|
DeleteWorkspace(_ context.Context, name string, force bool) error
|
||||||
|
|
||||||
// States returns a list of the names of all of the workspaces that exist
|
// States returns a list of the names of all of the workspaces that exist
|
||||||
// in this backend.
|
// in this backend.
|
||||||
|
|||||||
@@ -220,10 +220,10 @@ func (b *Local) Workspaces() ([]string, error) {
|
|||||||
// DeleteWorkspace removes a workspace.
|
// DeleteWorkspace removes a workspace.
|
||||||
//
|
//
|
||||||
// The "default" workspace cannot be removed.
|
// The "default" workspace cannot be removed.
|
||||||
func (b *Local) DeleteWorkspace(name string, force bool) error {
|
func (b *Local) DeleteWorkspace(ctx context.Context, name string, force bool) error {
|
||||||
// If we have a backend handling state, defer to that.
|
// If we have a backend handling state, defer to that.
|
||||||
if b.Backend != nil {
|
if b.Backend != nil {
|
||||||
return b.Backend.DeleteWorkspace(name, force)
|
return b.Backend.DeleteWorkspace(ctx, name, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ func (b backendWithStateStorageThatFailsRefresh) Configure(context.Context, cty.
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b backendWithStateStorageThatFailsRefresh) DeleteWorkspace(name string, force bool) error {
|
func (b backendWithStateStorageThatFailsRefresh) DeleteWorkspace(_ context.Context, name string, force bool) error {
|
||||||
return fmt.Errorf("unimplemented")
|
return fmt.Errorf("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
t.Fatalf("expected %q, got %q", expectedStates, states)
|
t.Fatalf("expected %q, got %q", expectedStates, states)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(expectedA, true); err != nil {
|
if err := b.DeleteWorkspace(ctx, expectedA, true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
t.Fatalf("expected %q, got %q", expectedStates, states)
|
t.Fatalf("expected %q, got %q", expectedStates, states)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(expectedB, true); err != nil {
|
if err := b.DeleteWorkspace(ctx, expectedB, true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
t.Fatalf("expected %q, got %q", expectedStates, states)
|
t.Fatalf("expected %q, got %q", expectedStates, states)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(dflt, true); err == nil {
|
if err := b.DeleteWorkspace(ctx, dflt, true); err == nil {
|
||||||
t.Fatal("expected error deleting default state")
|
t.Fatal("expected error deleting default state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ func (b *testDelegateBackend) Workspaces() ([]string, error) {
|
|||||||
return []string{"default"}, nil
|
return []string{"default"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testDelegateBackend) DeleteWorkspace(name string, force bool) error {
|
func (b *testDelegateBackend) DeleteWorkspace(_ context.Context, name string, force bool) error {
|
||||||
if b.deleteErr {
|
if b.deleteErr {
|
||||||
return errTestDelegateDeleteState
|
return errTestDelegateDeleteState
|
||||||
}
|
}
|
||||||
@@ -218,7 +218,9 @@ func TestLocal_multiStateBackend(t *testing.T) {
|
|||||||
deleteErr: true,
|
deleteErr: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
if _, err := b.StateMgr(context.Background(), "test"); err != errTestDelegateState {
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if _, err := b.StateMgr(ctx, "test"); err != errTestDelegateState {
|
||||||
t.Fatal("expected errTestDelegateState, got:", err)
|
t.Fatal("expected errTestDelegateState, got:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ func TestLocal_multiStateBackend(t *testing.T) {
|
|||||||
t.Fatal("expected errTestDelegateStates, got:", err)
|
t.Fatal("expected errTestDelegateStates, got:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace("test", true); err != errTestDelegateDeleteState {
|
if err := b.DeleteWorkspace(ctx, "test", true); err != errTestDelegateDeleteState {
|
||||||
t.Fatal("expected errTestDelegateDeleteState, got:", err)
|
t.Fatal("expected errTestDelegateDeleteState, got:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func (b *TestLocalSingleState) Workspaces() ([]string, error) {
|
|||||||
return nil, backend.ErrWorkspacesNotSupported
|
return nil, backend.ErrWorkspacesNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *TestLocalSingleState) DeleteWorkspace(string, bool) error {
|
func (b *TestLocalSingleState) DeleteWorkspace(context.Context, string, bool) error {
|
||||||
return backend.ErrWorkspacesNotSupported
|
return backend.ErrWorkspacesNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,11 +164,11 @@ func (b *TestLocalNoDefaultState) Workspaces() ([]string, error) {
|
|||||||
return filtered, nil
|
return filtered, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *TestLocalNoDefaultState) DeleteWorkspace(name string, force bool) error {
|
func (b *TestLocalNoDefaultState) DeleteWorkspace(ctx context.Context, name string, force bool) error {
|
||||||
if name == backend.DefaultStateName {
|
if name == backend.DefaultStateName {
|
||||||
return backend.ErrDefaultWorkspaceNotSupported
|
return backend.ErrDefaultWorkspaceNotSupported
|
||||||
}
|
}
|
||||||
return b.Local.DeleteWorkspace(name, force)
|
return b.Local.DeleteWorkspace(ctx, name, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *TestLocalNoDefaultState) StateMgr(ctx context.Context, name string) (statemgr.Full, error) {
|
func (b *TestLocalNoDefaultState) StateMgr(ctx context.Context, name string) (statemgr.Full, error) {
|
||||||
|
|||||||
@@ -61,12 +61,11 @@ func (b *Backend) Workspaces() ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(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")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.TODO()
|
|
||||||
client, err := b.armClient.getBlobClient(ctx)
|
client, err := b.armClient.getBlobClient(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -102,14 +102,13 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(ctx context.Context) error {
|
||||||
options := blobs.DeleteInput{}
|
options := blobs.DeleteInput{}
|
||||||
|
|
||||||
if c.leaseID != "" {
|
if c.leaseID != "" {
|
||||||
options.LeaseID = &c.leaseID
|
options.LeaseID = &c.leaseID
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.TODO()
|
|
||||||
resp, err := c.giovanniBlobClient.Delete(ctx, c.accountName, c.containerName, c.keyName, options)
|
resp, err := c.giovanniBlobClient.Delete(ctx, c.accountName, c.containerName, c.keyName, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !resp.IsHTTPStatus(http.StatusNotFound) {
|
if !resp.IsHTTPStatus(http.StatusNotFound) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (b *Backend) Workspaces() ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(name string, _ bool) error {
|
func (b *Backend) DeleteWorkspace(_ 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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -293,7 +293,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()
|
||||||
|
|
||||||
|
|||||||
@@ -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(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func (b *Backend) Workspaces() ([]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(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 == "" {
|
||||||
@@ -73,7 +73,7 @@ func (b *Backend) DeleteWorkspace(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
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ const (
|
|||||||
|
|
||||||
// RemoteClient implements the client of remote state
|
// RemoteClient implements the client of remote state
|
||||||
type remoteClient struct {
|
type remoteClient struct {
|
||||||
|
// TODO: remove once all methods are using context passed via the CLI.
|
||||||
cosContext context.Context
|
cosContext context.Context
|
||||||
|
|
||||||
cosClient *cos.Client
|
cosClient *cos.Client
|
||||||
tagClient *tag.Client
|
tagClient *tag.Client
|
||||||
|
|
||||||
@@ -68,10 +70,10 @@ func (c *remoteClient) Put(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -121,7 +123,7 @@ func (c *remoteClient) Unlock(check string) error {
|
|||||||
return c.lockError(fmt.Errorf("lock id mismatch, %v != %v", info.ID, check))
|
return c.lockError(fmt.Errorf("lock id mismatch, %v != %v", info.ID, check))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.deleteObject(c.lockFile)
|
err = c.deleteObject(c.cosContext, c.lockFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.lockError(err)
|
return c.lockError(err)
|
||||||
}
|
}
|
||||||
@@ -252,8 +254,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)
|
||||||
@@ -328,7 +330,7 @@ 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 {
|
||||||
c.deleteObject(v.Key)
|
c.deleteObject(c.cosContext, v.Key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func (b *Backend) Workspaces() ([]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(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)
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ func (b *Backend) DeleteWorkspace(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.
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ import (
|
|||||||
// blobs representing state.
|
// blobs representing state.
|
||||||
// Implements "state/remote".ClientLocker
|
// Implements "state/remote".ClientLocker
|
||||||
type remoteClient struct {
|
type remoteClient struct {
|
||||||
|
// TODO: remove this once all methods are accepting an explicit context
|
||||||
storageContext context.Context
|
storageContext context.Context
|
||||||
|
|
||||||
storageClient *storage.Client
|
storageClient *storage.Client
|
||||||
bucketName string
|
bucketName string
|
||||||
stateFilePath string
|
stateFilePath string
|
||||||
@@ -76,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,6 +255,6 @@ func (b *Backend) Workspaces() ([]string, error) {
|
|||||||
return nil, backend.ErrWorkspacesNotSupported
|
return nil, backend.ErrWorkspacesNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(string, bool) error {
|
func (b *Backend) DeleteWorkspace(context.Context, string, bool) error {
|
||||||
return backend.ErrWorkspacesNotSupported
|
return backend.ErrWorkspacesNotSupported
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -39,7 +40,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) {
|
||||||
// If we have data we need a reader
|
// If we have data we need a reader
|
||||||
var reader io.Reader = nil
|
var reader io.Reader = nil
|
||||||
if data != nil {
|
if data != nil {
|
||||||
@@ -47,7 +48,7 @@ func (c *httpClient) httpRequest(method string, url *url.URL, data *[]byte, what
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the request
|
// Create the request
|
||||||
req, err := retryablehttp.NewRequest(method, url.String(), reader)
|
req, err := retryablehttp.NewRequestWithContext(ctx, method, url.String(), reader)
|
||||||
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)
|
||||||
}
|
}
|
||||||
@@ -83,7 +84,7 @@ func (c *httpClient) Lock(info *statemgr.LockInfo) (string, error) {
|
|||||||
c.lockID = ""
|
c.lockID = ""
|
||||||
|
|
||||||
jsonLockInfo := info.Marshal()
|
jsonLockInfo := info.Marshal()
|
||||||
resp, err := c.httpRequest(c.LockMethod, c.LockURL, &jsonLockInfo, "lock")
|
resp, err := c.httpRequest(context.TODO(), c.LockMethod, c.LockURL, &jsonLockInfo, "lock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -129,7 +130,7 @@ func (c *httpClient) Unlock(id string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := c.httpRequest(c.UnlockMethod, c.UnlockURL, &c.jsonLockInfo, "unlock")
|
resp, err := c.httpRequest(context.TODO(), c.UnlockMethod, c.UnlockURL, &c.jsonLockInfo, "unlock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -144,7 +145,7 @@ func (c *httpClient) Unlock(id string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Get() (*remote.Payload, error) {
|
func (c *httpClient) Get() (*remote.Payload, error) {
|
||||||
resp, err := c.httpRequest("GET", c.URL, nil, "get state")
|
resp, err := c.httpRequest(context.TODO(), "GET", c.URL, nil, "get state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -225,7 +226,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(context.TODO(), method, &base, &data, "upload state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -240,9 +241,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("DELETE", c.URL, nil, "delete state")
|
resp, err := c.httpRequest(ctx, "DELETE", c.URL, nil, "delete state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ func (b *Backend) Workspaces() ([]string, error) {
|
|||||||
return workspaces, nil
|
return workspaces, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(name string, _ bool) error {
|
func (b *Backend) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
||||||
states.Lock()
|
states.Lock()
|
||||||
defer states.Unlock()
|
defer states.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,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"
|
||||||
@@ -36,7 +37,7 @@ 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
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func (b *Backend) Workspaces() ([]string, error) {
|
|||||||
return states, nil
|
return states, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(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")
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ func (b *Backend) DeleteWorkspace(name string, _ bool) error {
|
|||||||
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) {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete the state secret
|
// Delete the state secret
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(context.Context) error {
|
||||||
secretName, err := c.createSecretName()
|
secretName, err := c.createSecretName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func (b *Backend) Workspaces() ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(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")
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ func (b *Backend) DeleteWorkspace(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) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package oss
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -129,7 +130,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 {
|
||||||
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)
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ func (b *Backend) Workspaces() ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(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")
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `DELETE FROM %s.%s WHERE name = $1`
|
query := `DELETE FROM %s.%s WHERE name = $1`
|
||||||
_, err := b.db.Exec(fmt.Sprintf(query, b.schemaName, statesTableName), name)
|
_, err := b.db.ExecContext(ctx, fmt.Sprintf(query, b.schemaName, statesTableName), name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package pg
|
package pg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -54,9 +55,9 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Delete() error {
|
func (c *RemoteClient) Delete(ctx context.Context) error {
|
||||||
query := `DELETE FROM %s.%s WHERE name = $1`
|
query := `DELETE FROM %s.%s WHERE name = $1`
|
||||||
_, err := c.Client.Exec(fmt.Sprintf(query, c.SchemaName, statesTableName), c.Name)
|
_, err := c.Client.ExecContext(ctx, fmt.Sprintf(query, c.SchemaName, statesTableName), c.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func (b *Backend) keyEnv(key string) string {
|
|||||||
return parts[0]
|
return parts[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DeleteWorkspace(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")
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ func (b *Backend) DeleteWorkspace(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
|
||||||
|
|||||||
@@ -1107,12 +1107,12 @@ 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(ctx); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the real workspace
|
// delete the real workspace
|
||||||
if err := b.DeleteWorkspace("s2", true); err != nil {
|
if err := b.DeleteWorkspace(ctx, "s2", true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,8 +202,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()
|
|
||||||
_, err := c.s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
|
_, err := c.s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
|
||||||
Bucket: &c.bucketName,
|
Bucket: &c.bucketName,
|
||||||
Key: &c.path,
|
Key: &c.path,
|
||||||
|
|||||||
@@ -609,7 +609,7 @@ func (b *Remote) WorkspaceNamePattern() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWorkspace implements backend.Enhanced.
|
// DeleteWorkspace implements backend.Enhanced.
|
||||||
func (b *Remote) DeleteWorkspace(name string, _ bool) error {
|
func (b *Remote) DeleteWorkspace(ctx context.Context, name string, _ bool) error {
|
||||||
if b.workspace == "" && name == backend.DefaultStateName {
|
if b.workspace == "" && name == backend.DefaultStateName {
|
||||||
return backend.ErrDefaultWorkspaceNotSupported
|
return backend.ErrDefaultWorkspaceNotSupported
|
||||||
}
|
}
|
||||||
@@ -633,7 +633,7 @@ func (b *Remote) DeleteWorkspace(name string, _ bool) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.Delete()
|
return client.Delete(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateMgr implements backend.Enhanced.
|
// StateMgr implements backend.Enhanced.
|
||||||
|
|||||||
@@ -141,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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -283,11 +283,11 @@ func TestRemote_addAndRemoveWorkspacesDefault(t *testing.T) {
|
|||||||
t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
|
t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(backend.DefaultStateName, true); err != nil {
|
if err := b.DeleteWorkspace(ctx, backend.DefaultStateName, true); err != nil {
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace("prod", true); err != backend.ErrWorkspacesNotSupported {
|
if err := b.DeleteWorkspace(ctx, "prod", true); err != backend.ErrWorkspacesNotSupported {
|
||||||
t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
|
t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,11 +342,11 @@ func TestRemote_addAndRemoveWorkspacesNoDefault(t *testing.T) {
|
|||||||
t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
|
t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(backend.DefaultStateName, true); err != backend.ErrDefaultWorkspaceNotSupported {
|
if err := b.DeleteWorkspace(ctx, backend.DefaultStateName, true); err != backend.ErrDefaultWorkspaceNotSupported {
|
||||||
t.Fatalf("expected error %v, got %v", backend.ErrDefaultWorkspaceNotSupported, err)
|
t.Fatalf("expected error %v, got %v", backend.ErrDefaultWorkspaceNotSupported, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(expectedA, true); err != nil {
|
if err := b.DeleteWorkspace(ctx, expectedA, true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +360,7 @@ func TestRemote_addAndRemoveWorkspacesNoDefault(t *testing.T) {
|
|||||||
t.Fatalf("expected %#+v got %#+v", expectedWorkspaces, states)
|
t.Fatalf("expected %#+v got %#+v", expectedWorkspaces, states)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(expectedB, true); err != nil {
|
if err := b.DeleteWorkspace(ctx, expectedB, true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -227,12 +227,12 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete some workspaces
|
// Delete some workspaces
|
||||||
if err := b.DeleteWorkspace("foo", true); err != nil {
|
if err := b.DeleteWorkspace(ctx, "foo", true); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the default state can't be deleted
|
// Verify the default state can't be deleted
|
||||||
if err := b.DeleteWorkspace(DefaultStateName, true); err == nil {
|
if err := b.DeleteWorkspace(ctx, DefaultStateName, true); err == nil {
|
||||||
t.Fatal("expected error")
|
t.Fatal("expected error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
|||||||
t.Fatalf("should be empty: %s", v)
|
t.Fatalf("should be empty: %s", v)
|
||||||
}
|
}
|
||||||
// and delete it again
|
// and delete it again
|
||||||
if err := b.DeleteWorkspace("foo", true); err != nil {
|
if err := b.DeleteWorkspace(ctx, "foo", true); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ func (b backendFailsConfigure) StateMgr(context.Context, string) (statemgr.Full,
|
|||||||
return nil, fmt.Errorf("StateMgr not implemented")
|
return nil, fmt.Errorf("StateMgr not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b backendFailsConfigure) DeleteWorkspace(name string, _ bool) error {
|
func (b backendFailsConfigure) DeleteWorkspace(_ context.Context, name string, _ bool) error {
|
||||||
return fmt.Errorf("DeleteWorkspace not implemented")
|
return fmt.Errorf("DeleteWorkspace not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ func (b *Cloud) Workspaces() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWorkspace implements backend.Enhanced.
|
// DeleteWorkspace implements backend.Enhanced.
|
||||||
func (b *Cloud) DeleteWorkspace(name string, force bool) error {
|
func (b *Cloud) DeleteWorkspace(ctx context.Context, name string, force bool) error {
|
||||||
if name == backend.DefaultStateName {
|
if name == backend.DefaultStateName {
|
||||||
return backend.ErrDefaultWorkspaceNotSupported
|
return backend.ErrDefaultWorkspaceNotSupported
|
||||||
}
|
}
|
||||||
@@ -601,7 +601,7 @@ func (b *Cloud) DeleteWorkspace(name string, force bool) error {
|
|||||||
return backend.ErrWorkspacesNotSupported
|
return backend.ErrWorkspacesNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace, err := b.client.Workspaces.Read(context.Background(), b.organization, name)
|
workspace, err := b.client.Workspaces.Read(ctx, b.organization, name)
|
||||||
if err == tfe.ErrResourceNotFound {
|
if err == tfe.ErrResourceNotFound {
|
||||||
return nil // If the workspace does not exist, succeed
|
return nil // If the workspace does not exist, succeed
|
||||||
}
|
}
|
||||||
@@ -612,7 +612,7 @@ func (b *Cloud) DeleteWorkspace(name string, force bool) error {
|
|||||||
|
|
||||||
// Configure the remote workspace name.
|
// Configure the remote workspace name.
|
||||||
State := &State{tfeClient: b.client, organization: b.organization, workspace: workspace, enableIntermediateSnapshots: false}
|
State := &State{tfeClient: b.client, organization: b.organization, workspace: workspace, enableIntermediateSnapshots: false}
|
||||||
return State.Delete(force)
|
return State.Delete(ctx, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateMgr implements backend.Enhanced.
|
// StateMgr implements backend.Enhanced.
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ func TestCloud_backendWithName(t *testing.T) {
|
|||||||
t.Fatalf("expected fetching a state which is NOT the single configured workspace to have an ErrWorkspacesNotSupported error, but got: %v", err)
|
t.Fatalf("expected fetching a state which is NOT the single configured workspace to have an ErrWorkspacesNotSupported error, but got: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(testBackendSingleWorkspaceName, true); err != backend.ErrWorkspacesNotSupported {
|
if err := b.DeleteWorkspace(ctx, testBackendSingleWorkspaceName, true); err != backend.ErrWorkspacesNotSupported {
|
||||||
t.Fatalf("expected deleting the single configured workspace name to result in an error, but got: %v", err)
|
t.Fatalf("expected deleting the single configured workspace name to result in an error, but got: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace("foo", true); err != backend.ErrWorkspacesNotSupported {
|
if err := b.DeleteWorkspace(ctx, "foo", true); err != backend.ErrWorkspacesNotSupported {
|
||||||
t.Fatalf("expected deleting a workspace which is NOT the configured workspace name to result in an error, but got: %v", err)
|
t.Fatalf("expected deleting a workspace which is NOT the configured workspace name to result in an error, but got: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1071,7 +1071,7 @@ func TestCloud_addAndRemoveWorkspacesDefault(t *testing.T) {
|
|||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.DeleteWorkspace(testBackendSingleWorkspaceName, true); err != backend.ErrWorkspacesNotSupported {
|
if err := b.DeleteWorkspace(ctx, testBackendSingleWorkspaceName, true); err != backend.ErrWorkspacesNotSupported {
|
||||||
t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
|
t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1396,7 +1396,7 @@ func TestCloudBackend_DeleteWorkspace_SafeAndForce(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error locking workspace: %v", err)
|
t.Fatalf("error locking workspace: %v", err)
|
||||||
}
|
}
|
||||||
err = b.DeleteWorkspace(safeDeleteWorkspaceName, false)
|
err = b.DeleteWorkspace(ctx, safeDeleteWorkspaceName, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("workspace should have failed to safe delete")
|
t.Fatalf("workspace should have failed to safe delete")
|
||||||
}
|
}
|
||||||
@@ -1406,7 +1406,7 @@ func TestCloudBackend_DeleteWorkspace_SafeAndForce(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error unlocking workspace: %v", err)
|
t.Fatalf("error unlocking workspace: %v", err)
|
||||||
}
|
}
|
||||||
err = b.DeleteWorkspace(safeDeleteWorkspaceName, false)
|
err = b.DeleteWorkspace(ctx, safeDeleteWorkspaceName, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error safe deleting workspace: %v", err)
|
t.Fatalf("error safe deleting workspace: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1420,7 +1420,7 @@ func TestCloudBackend_DeleteWorkspace_SafeAndForce(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error locking workspace: %v", err)
|
t.Fatalf("error locking workspace: %v", err)
|
||||||
}
|
}
|
||||||
err = b.DeleteWorkspace(forceDeleteWorkspaceName, true)
|
err = b.DeleteWorkspace(ctx, forceDeleteWorkspaceName, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error force deleting workspace: %v", err)
|
t.Fatalf("error force deleting workspace: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1430,7 +1430,9 @@ func TestCloudBackend_DeleteWorkspace_DoesNotExist(t *testing.T) {
|
|||||||
b, bCleanup := testBackendWithTags(t)
|
b, bCleanup := testBackendWithTags(t)
|
||||||
defer bCleanup()
|
defer bCleanup()
|
||||||
|
|
||||||
err := b.DeleteWorkspace("non-existent-workspace", false)
|
ctx := context.Background()
|
||||||
|
|
||||||
|
err := b.DeleteWorkspace(ctx, "non-existent-workspace", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected deleting a workspace which does not exist to succeed")
|
t.Fatalf("expected deleting a workspace which does not exist to succeed")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -497,15 +497,15 @@ func (s *State) Unlock(id string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete the remote state.
|
// Delete the remote state.
|
||||||
func (s *State) Delete(force bool) error {
|
func (s *State) Delete(ctx context.Context, force bool) error {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
isSafeDeleteSupported := s.workspace.Permissions.CanForceDelete != nil
|
isSafeDeleteSupported := s.workspace.Permissions.CanForceDelete != nil
|
||||||
if force || !isSafeDeleteSupported {
|
if force || !isSafeDeleteSupported {
|
||||||
err = s.tfeClient.Workspaces.Delete(context.Background(), s.organization, s.workspace.Name)
|
err = s.tfeClient.Workspaces.Delete(ctx, s.organization, s.workspace.Name)
|
||||||
} else {
|
} else {
|
||||||
err = s.tfeClient.Workspaces.SafeDelete(context.Background(), s.organization, s.workspace.Name)
|
err = s.tfeClient.Workspaces.SafeDelete(ctx, s.organization, s.workspace.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && err != tfe.ErrResourceNotFound {
|
if err != nil && err != tfe.ErrResourceNotFound {
|
||||||
|
|||||||
@@ -127,7 +127,9 @@ func TestState(t *testing.T) {
|
|||||||
t.Fatalf("expected full state %q\n\ngot: %q", string(payload.Data), string(data))
|
t.Fatalf("expected full state %q\n\ngot: %q", string(payload.Data), string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := state.Delete(true); err != nil {
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if err := state.Delete(ctx, true); err != nil {
|
||||||
t.Fatalf("delete: %s", err)
|
t.Fatalf("delete: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,9 +213,11 @@ func TestDelete_SafeDeleteNotSupported(t *testing.T) {
|
|||||||
state.workspace.Permissions.CanForceDelete = nil
|
state.workspace.Permissions.CanForceDelete = nil
|
||||||
state.workspace.ResourceCount = 5
|
state.workspace.ResourceCount = 5
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
// Typically delete(false) should safe-delete a cloud workspace, which should fail on this workspace with resources
|
// Typically delete(false) should safe-delete a cloud workspace, which should fail on this workspace with resources
|
||||||
// However, since we have set the workspace canForceDelete permission to nil, we should fall back to force delete
|
// However, since we have set the workspace canForceDelete permission to nil, we should fall back to force delete
|
||||||
if err := state.Delete(false); err != nil {
|
if err := state.Delete(ctx, false); err != nil {
|
||||||
t.Fatalf("delete: %s", err)
|
t.Fatalf("delete: %s", err)
|
||||||
}
|
}
|
||||||
workspace, err := state.tfeClient.Workspaces.ReadByID(context.Background(), workspaceId)
|
workspace, err := state.tfeClient.Workspaces.ReadByID(context.Background(), workspaceId)
|
||||||
@@ -228,7 +232,9 @@ func TestDelete_ForceDelete(t *testing.T) {
|
|||||||
state.workspace.Permissions.CanForceDelete = tfe.Bool(true)
|
state.workspace.Permissions.CanForceDelete = tfe.Bool(true)
|
||||||
state.workspace.ResourceCount = 5
|
state.workspace.ResourceCount = 5
|
||||||
|
|
||||||
if err := state.Delete(true); err != nil {
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if err := state.Delete(ctx, true); err != nil {
|
||||||
t.Fatalf("delete: %s", err)
|
t.Fatalf("delete: %s", err)
|
||||||
}
|
}
|
||||||
workspace, err := state.tfeClient.Workspaces.ReadByID(context.Background(), workspaceId)
|
workspace, err := state.tfeClient.Workspaces.ReadByID(context.Background(), workspaceId)
|
||||||
@@ -243,15 +249,17 @@ func TestDelete_SafeDelete(t *testing.T) {
|
|||||||
state.workspace.Permissions.CanForceDelete = tfe.Bool(false)
|
state.workspace.Permissions.CanForceDelete = tfe.Bool(false)
|
||||||
state.workspace.ResourceCount = 5
|
state.workspace.ResourceCount = 5
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
// safe-deleting a workspace with resources should fail
|
// safe-deleting a workspace with resources should fail
|
||||||
err := state.Delete(false)
|
err := state.Delete(ctx, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("workspace should have failed to safe delete")
|
t.Fatalf("workspace should have failed to safe delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
// safe-deleting a workspace with resources should succeed once it has no resources
|
// safe-deleting a workspace with resources should succeed once it has no resources
|
||||||
state.workspace.ResourceCount = 0
|
state.workspace.ResourceCount = 0
|
||||||
if err = state.Delete(false); err != nil {
|
if err = state.Delete(ctx, false); err != nil {
|
||||||
t.Fatalf("workspace safe-delete err: %s", err)
|
t.Fatalf("workspace safe-delete err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
|
|||||||
// be delegated from the Backend to the State itself.
|
// be delegated from the Backend to the State itself.
|
||||||
stateLocker.Unlock()
|
stateLocker.Unlock()
|
||||||
|
|
||||||
err = b.DeleteWorkspace(workspace, force)
|
err = b.DeleteWorkspace(ctx, workspace, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(err.Error())
|
c.Ui.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/states/statemgr"
|
"github.com/opentofu/opentofu/internal/states/statemgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,7 +15,7 @@ import (
|
|||||||
type Client interface {
|
type Client interface {
|
||||||
Get() (*Payload, error)
|
Get() (*Payload, error)
|
||||||
Put([]byte) error
|
Put([]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
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -25,7 +26,7 @@ func (nilClient) Get() (*Payload, error) { return nil, nil }
|
|||||||
|
|
||||||
func (c nilClient) Put([]byte) error { return nil }
|
func (c nilClient) Put([]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
|
||||||
@@ -58,7 +59,7 @@ func (c *mockClient) Put(data []byte) error {
|
|||||||
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
|
||||||
@@ -116,7 +117,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
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package remote
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/states/statefile"
|
"github.com/opentofu/opentofu/internal/states/statefile"
|
||||||
@@ -34,7 +35,9 @@ 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 {
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if err := c.Delete(ctx); err != nil {
|
||||||
t.Fatalf("delete: %s", err)
|
t.Fatalf("delete: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user