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
This commit is contained in:
Mitchell Hashimoto 2017-02-15 14:20:59 -08:00
parent 6798cd5911
commit efe754183b
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 25 additions and 14 deletions

View File

@ -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) {

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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)
}