From efe754183b70f06e2d7216042267089c80ab3459 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 15 Feb 2017 14:20:59 -0800 Subject: [PATCH 1/3] state/remote: export ClientLocker, test for implementation This adds unit tests (that will fail at compile time) if various structs don't implement the right interfaces for locking --- backend/remote-state/consul/client_test.go | 1 + state/backup_test.go | 4 ++++ state/remote/remote.go | 11 +++++++++++ state/remote/state.go | 22 ++++++++-------------- state/remote/state_test.go | 1 + 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/backend/remote-state/consul/client_test.go b/backend/remote-state/consul/client_test.go index bd52092ca5..52246e48ba 100644 --- a/backend/remote-state/consul/client_test.go +++ b/backend/remote-state/consul/client_test.go @@ -13,6 +13,7 @@ import ( func TestRemoteClient_impl(t *testing.T) { var _ remote.Client = new(RemoteClient) + var _ remote.ClientLocker = new(RemoteClient) } func TestRemoteClient(t *testing.T) { diff --git a/state/backup_test.go b/state/backup_test.go index f86b6b299f..85f722863c 100644 --- a/state/backup_test.go +++ b/state/backup_test.go @@ -6,6 +6,10 @@ import ( "testing" ) +func TestBackupState_locker(t *testing.T) { + var _ Locker = new(BackupState) +} + func TestBackupState(t *testing.T) { f, err := ioutil.TempFile("", "tf") if err != nil { diff --git a/state/remote/remote.go b/state/remote/remote.go index 020a352308..8bf99c2310 100644 --- a/state/remote/remote.go +++ b/state/remote/remote.go @@ -2,6 +2,8 @@ package remote import ( "fmt" + + "github.com/hashicorp/terraform/state" ) // Client is the interface that must be implemented for a remote state @@ -13,6 +15,15 @@ type Client interface { Delete() error } +// ClientLocker is an optional interface that allows a remote state +// backend to enable state lock/unlock. +type ClientLocker interface { + Client + + Lock(*state.LockInfo) (string, error) + Unlock(string) error +} + // Payload is the return value from the remote state storage. type Payload struct { MD5 []byte diff --git a/state/remote/state.go b/state/remote/state.go index 57d3b7c4ba..c874167052 100644 --- a/state/remote/state.go +++ b/state/remote/state.go @@ -3,6 +3,7 @@ package remote import ( "bytes" + "github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/terraform" ) @@ -62,24 +63,17 @@ func (s *State) PersistState() error { } // Lock calls the Client's Lock method if it's implemented. -func (s *State) Lock(reason string) error { - if c, ok := s.Client.(stateLocker); ok { - return c.Lock(reason) +func (s *State) Lock(info *state.LockInfo) (string, error) { + if c, ok := s.Client.(ClientLocker); ok { + return c.Lock(info) } - return nil + return "", nil } // Unlock calls the Client's Unlock method if it's implemented. -func (s *State) Unlock() error { - if c, ok := s.Client.(stateLocker); ok { - return c.Unlock() +func (s *State) Unlock(id string) error { + if c, ok := s.Client.(ClientLocker); ok { + return c.Unlock(id) } return nil } - -// stateLocker mirrors the state.Locker interface. This can be implemented by -// Clients to provide methods for locking and unlocking remote state. -type stateLocker interface { - Lock(reason string) error - Unlock() error -} diff --git a/state/remote/state_test.go b/state/remote/state_test.go index 4878916675..01315b99ea 100644 --- a/state/remote/state_test.go +++ b/state/remote/state_test.go @@ -24,4 +24,5 @@ func TestState_impl(t *testing.T) { var _ state.StateWriter = new(State) var _ state.StatePersister = new(State) var _ state.StateRefresher = new(State) + var _ state.Locker = new(State) } From 9451acc5da0a18f3aead05067c0d4f8284aebaf8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 15 Feb 2017 14:25:53 -0800 Subject: [PATCH 2/3] state/remote: add unit test to verify s3 is a ClientLocker as well --- state/remote/s3_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/state/remote/s3_test.go b/state/remote/s3_test.go index 7a09835894..358c1a676c 100644 --- a/state/remote/s3_test.go +++ b/state/remote/s3_test.go @@ -13,6 +13,7 @@ import ( func TestS3Client_impl(t *testing.T) { var _ Client = new(S3Client) + var _ ClientLocker = new(S3Client) } func TestS3Factory(t *testing.T) { From 03f6c650ca9e78fc0d80d430ca1ec2a52c262da4 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 15 Feb 2017 14:27:02 -0800 Subject: [PATCH 3/3] state/remote: ClientLocker is just a Client that is a state.Locker --- state/remote/remote.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/state/remote/remote.go b/state/remote/remote.go index 8bf99c2310..414c115e9c 100644 --- a/state/remote/remote.go +++ b/state/remote/remote.go @@ -19,9 +19,7 @@ type Client interface { // backend to enable state lock/unlock. type ClientLocker interface { Client - - Lock(*state.LockInfo) (string, error) - Unlock(string) error + state.Locker } // Payload is the return value from the remote state storage.