Skip to content

Commit

Permalink
Merge pull request #14949 from hashicorp/jbardin/s3-config
Browse files Browse the repository at this point in the history
Replace lock_table with dynamodb_table in S3 backend config
  • Loading branch information
jbardin authored May 30, 2017
2 parents 48490a0 + eba5093 commit 6a3a3b3
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 56 deletions.
17 changes: 15 additions & 2 deletions backend/remote-state/s3/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ func New() backend.Backend {
Optional: true,
Description: "DynamoDB table for state locking",
Default: "",
Deprecated: "please use the dynamodb_table attribute",
},

"dynamodb_table": {
Type: schema.TypeString,
Optional: true,
Description: "DynamoDB table for state locking and consistency",
Default: "",
},

"profile": {
Expand Down Expand Up @@ -151,7 +159,7 @@ type Backend struct {
serverSideEncryption bool
acl string
kmsKeyID string
lockTable string
ddbTable string
}

func (b *Backend) configure(ctx context.Context) error {
Expand All @@ -167,7 +175,12 @@ func (b *Backend) configure(ctx context.Context) error {
b.serverSideEncryption = data.Get("encrypt").(bool)
b.acl = data.Get("acl").(string)
b.kmsKeyID = data.Get("kms_key_id").(string)
b.lockTable = data.Get("lock_table").(string)

b.ddbTable = data.Get("dynamodb_table").(string)
if b.ddbTable == "" {
// try the depracted field
b.ddbTable = data.Get("lock_table").(string)
}

cfg := &terraformAWS.Config{
AccessKey: data.Get("access_key").(string),
Expand Down
2 changes: 1 addition & 1 deletion backend/remote-state/s3/backend_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (b *Backend) State(name string) (state.State, error) {
serverSideEncryption: b.serverSideEncryption,
acl: b.acl,
kmsKeyID: b.kmsKeyID,
lockTable: b.lockTable,
ddbTable: b.ddbTable,
}

stateMgr := &remote.State{Client: client}
Expand Down
28 changes: 14 additions & 14 deletions backend/remote-state/s3/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ func TestBackend_impl(t *testing.T) {
func TestBackendConfig(t *testing.T) {
testACC(t)
config := map[string]interface{}{
"region": "us-west-1",
"bucket": "tf-test",
"key": "state",
"encrypt": true,
"lock_table": "dynamoTable",
"region": "us-west-1",
"bucket": "tf-test",
"key": "state",
"encrypt": true,
"dynamodb_table": "dynamoTable",
}

b := backend.TestBackendConfig(t, New(), config).(*Backend)
Expand Down Expand Up @@ -90,17 +90,17 @@ func TestBackendLocked(t *testing.T) {
keyName := "test/state"

b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"dynamodb_table": bucketName,
}).(*Backend)

b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"dynamodb_table": bucketName,
}).(*Backend)

createS3Bucket(t, b1.s3Client, bucketName)
Expand Down Expand Up @@ -139,7 +139,7 @@ func TestBackendExtraPaths(t *testing.T) {
serverSideEncryption: b.serverSideEncryption,
acl: b.acl,
kmsKeyID: b.kmsKeyID,
lockTable: b.lockTable,
ddbTable: b.ddbTable,
}

stateMgr := &remote.State{Client: client}
Expand Down
24 changes: 12 additions & 12 deletions backend/remote-state/s3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type RemoteClient struct {
serverSideEncryption bool
acl string
kmsKeyID string
lockTable string
ddbTable string
}

var (
Expand Down Expand Up @@ -191,7 +191,7 @@ func (c *RemoteClient) Delete() error {
}

func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
if c.lockTable == "" {
if c.ddbTable == "" {
return "", nil
}

Expand All @@ -211,7 +211,7 @@ func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
"LockID": {S: aws.String(c.lockPath())},
"Info": {S: aws.String(string(info.Marshal()))},
},
TableName: aws.String(c.lockTable),
TableName: aws.String(c.ddbTable),
ConditionExpression: aws.String("attribute_not_exists(LockID)"),
}
_, err := c.dynClient.PutItem(putParams)
Expand All @@ -233,7 +233,7 @@ func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
}

func (c *RemoteClient) getMD5() ([]byte, error) {
if c.lockTable == "" {
if c.ddbTable == "" {
return nil, nil
}

Expand All @@ -242,7 +242,7 @@ func (c *RemoteClient) getMD5() ([]byte, error) {
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
},
ProjectionExpression: aws.String("LockID, Digest"),
TableName: aws.String(c.lockTable),
TableName: aws.String(c.ddbTable),
}

resp, err := c.dynClient.GetItem(getParams)
Expand All @@ -265,7 +265,7 @@ func (c *RemoteClient) getMD5() ([]byte, error) {

// store the hash of the state to that clients can check for stale state files.
func (c *RemoteClient) putMD5(sum []byte) error {
if c.lockTable == "" {
if c.ddbTable == "" {
return nil
}

Expand All @@ -278,7 +278,7 @@ func (c *RemoteClient) putMD5(sum []byte) error {
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
"Digest": {S: aws.String(hex.EncodeToString(sum))},
},
TableName: aws.String(c.lockTable),
TableName: aws.String(c.ddbTable),
}
_, err := c.dynClient.PutItem(putParams)
if err != nil {
Expand All @@ -290,15 +290,15 @@ func (c *RemoteClient) putMD5(sum []byte) error {

// remove the hash value for a deleted state
func (c *RemoteClient) deleteMD5() error {
if c.lockTable == "" {
if c.ddbTable == "" {
return nil
}

params := &dynamodb.DeleteItemInput{
Key: map[string]*dynamodb.AttributeValue{
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
},
TableName: aws.String(c.lockTable),
TableName: aws.String(c.ddbTable),
}
if _, err := c.dynClient.DeleteItem(params); err != nil {
return err
Expand All @@ -312,7 +312,7 @@ func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
"LockID": {S: aws.String(c.lockPath())},
},
ProjectionExpression: aws.String("LockID, Info"),
TableName: aws.String(c.lockTable),
TableName: aws.String(c.ddbTable),
}

resp, err := c.dynClient.GetItem(getParams)
Expand All @@ -335,7 +335,7 @@ func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
}

func (c *RemoteClient) Unlock(id string) error {
if c.lockTable == "" {
if c.ddbTable == "" {
return nil
}

Expand All @@ -360,7 +360,7 @@ func (c *RemoteClient) Unlock(id string) error {
Key: map[string]*dynamodb.AttributeValue{
"LockID": {S: aws.String(c.lockPath())},
},
TableName: aws.String(c.lockTable),
TableName: aws.String(c.ddbTable),
}
_, err = c.dynClient.DeleteItem(params)

Expand Down
46 changes: 23 additions & 23 deletions backend/remote-state/s3/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ func TestRemoteClientLocks(t *testing.T) {
keyName := "testState"

b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"dynamodb_table": bucketName,
}).(*Backend)

b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"dynamodb_table": bucketName,
}).(*Backend)

createS3Bucket(t, b1.s3Client, bucketName)
Expand Down Expand Up @@ -85,17 +85,17 @@ func TestForceUnlock(t *testing.T) {
keyName := "testState"

b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"dynamodb_table": bucketName,
}).(*Backend)

b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"encrypt": true,
"dynamodb_table": bucketName,
}).(*Backend)

createS3Bucket(t, b1.s3Client, bucketName)
Expand Down Expand Up @@ -162,9 +162,9 @@ func TestRemoteClient_clientMD5(t *testing.T) {
keyName := "testState"

b := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"dynamodb_table": bucketName,
}).(*Backend)

createS3Bucket(t, b.s3Client, bucketName)
Expand Down Expand Up @@ -210,9 +210,9 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
keyName := "testState"

b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
"key": keyName,
"lock_table": bucketName,
"bucket": bucketName,
"key": keyName,
"dynamodb_table": bucketName,
}).(*Backend)

createS3Bucket(t, b1.s3Client, bucketName)
Expand All @@ -238,7 +238,7 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
t.Fatal(err)
}

// Use b2 without a lock_table to bypass the lock table to write the state directly.
// Use b2 without a dynamodb_table to bypass the lock table to write the state directly.
// client2 will write the "incorrect" state, simulating s3 eventually consistency delays
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"bucket": bucketName,
Expand Down
12 changes: 8 additions & 4 deletions website/source/docs/backends/types/s3.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,18 @@ The following configuration options or environment variables are supported:
* `secret_key` / `AWS_SECRET_ACCESS_KEY` - (Optional) AWS secret access key.
* `kms_key_id` - (Optional) The ARN of a KMS Key to use for encrypting
the state.
* `lock_table` - (Optional) The name of a DynamoDB table to use for state
locking. The table must have a primary key named LockID. If not present,
locking will be disabled.
* `lock_table` - (Optional, Deprecated) Use `dynamodb_table` instead.
* `dynamodb_table` - (Optional) The name of a DynamoDB table to use for state
locking and consistency. The table must have a primary key named LockID. If
not present, locking will be disabled.
* `profile` - (Optional) This is the AWS profile name as set in the
shared credentials file.
* `shared_credentials_file` - (Optional) This is the path to the
shared credentials file. If this is not set and a profile is specified,
`~/.aws/credentials` will be used.
* `token` - (Optional) Use this to set an MFA token. It can also be
sourced from the `AWS_SESSION_TOKEN` environment variable.
* `role_arn` - (Optional) The role to be assumed
* `role_arn` - (Optional) The role to be assumed.
* `assume_role_policy` - (Optional) The permissions applied when assuming a role.
* `external_id` - (Optional) The external ID to use when assuming the role.
* `session_name` - (Optional) The session name to use when assuming the role.

0 comments on commit 6a3a3b3

Please sign in to comment.