Merge pull request #14949 from hashicorp/jbardin/s3-config
Replace lock_table with dynamodb_table in S3 backend config
This commit is contained in:
commit
6a3a3b3b05
|
@ -81,6 +81,14 @@ func New() backend.Backend {
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Description: "DynamoDB table for state locking",
|
Description: "DynamoDB table for state locking",
|
||||||
Default: "",
|
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": {
|
"profile": {
|
||||||
|
@ -151,7 +159,7 @@ type Backend struct {
|
||||||
serverSideEncryption bool
|
serverSideEncryption bool
|
||||||
acl string
|
acl string
|
||||||
kmsKeyID string
|
kmsKeyID string
|
||||||
lockTable string
|
ddbTable string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) configure(ctx context.Context) error {
|
func (b *Backend) configure(ctx context.Context) error {
|
||||||
|
@ -167,7 +175,12 @@ func (b *Backend) configure(ctx context.Context) error {
|
||||||
b.serverSideEncryption = data.Get("encrypt").(bool)
|
b.serverSideEncryption = data.Get("encrypt").(bool)
|
||||||
b.acl = data.Get("acl").(string)
|
b.acl = data.Get("acl").(string)
|
||||||
b.kmsKeyID = data.Get("kms_key_id").(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{
|
cfg := &terraformAWS.Config{
|
||||||
AccessKey: data.Get("access_key").(string),
|
AccessKey: data.Get("access_key").(string),
|
||||||
|
|
|
@ -96,7 +96,7 @@ func (b *Backend) State(name string) (state.State, error) {
|
||||||
serverSideEncryption: b.serverSideEncryption,
|
serverSideEncryption: b.serverSideEncryption,
|
||||||
acl: b.acl,
|
acl: b.acl,
|
||||||
kmsKeyID: b.kmsKeyID,
|
kmsKeyID: b.kmsKeyID,
|
||||||
lockTable: b.lockTable,
|
ddbTable: b.ddbTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
stateMgr := &remote.State{Client: client}
|
stateMgr := &remote.State{Client: client}
|
||||||
|
|
|
@ -34,11 +34,11 @@ func TestBackend_impl(t *testing.T) {
|
||||||
func TestBackendConfig(t *testing.T) {
|
func TestBackendConfig(t *testing.T) {
|
||||||
testACC(t)
|
testACC(t)
|
||||||
config := map[string]interface{}{
|
config := map[string]interface{}{
|
||||||
"region": "us-west-1",
|
"region": "us-west-1",
|
||||||
"bucket": "tf-test",
|
"bucket": "tf-test",
|
||||||
"key": "state",
|
"key": "state",
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
"lock_table": "dynamoTable",
|
"dynamodb_table": "dynamoTable",
|
||||||
}
|
}
|
||||||
|
|
||||||
b := backend.TestBackendConfig(t, New(), config).(*Backend)
|
b := backend.TestBackendConfig(t, New(), config).(*Backend)
|
||||||
|
@ -90,17 +90,17 @@ func TestBackendLocked(t *testing.T) {
|
||||||
keyName := "test/state"
|
keyName := "test/state"
|
||||||
|
|
||||||
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
createS3Bucket(t, b1.s3Client, bucketName)
|
createS3Bucket(t, b1.s3Client, bucketName)
|
||||||
|
@ -139,7 +139,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
||||||
serverSideEncryption: b.serverSideEncryption,
|
serverSideEncryption: b.serverSideEncryption,
|
||||||
acl: b.acl,
|
acl: b.acl,
|
||||||
kmsKeyID: b.kmsKeyID,
|
kmsKeyID: b.kmsKeyID,
|
||||||
lockTable: b.lockTable,
|
ddbTable: b.ddbTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
stateMgr := &remote.State{Client: client}
|
stateMgr := &remote.State{Client: client}
|
||||||
|
|
|
@ -32,7 +32,7 @@ type RemoteClient struct {
|
||||||
serverSideEncryption bool
|
serverSideEncryption bool
|
||||||
acl string
|
acl string
|
||||||
kmsKeyID string
|
kmsKeyID string
|
||||||
lockTable string
|
ddbTable string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -191,7 +191,7 @@ func (c *RemoteClient) Delete() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
|
func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
|
||||||
if c.lockTable == "" {
|
if c.ddbTable == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
|
||||||
"LockID": {S: aws.String(c.lockPath())},
|
"LockID": {S: aws.String(c.lockPath())},
|
||||||
"Info": {S: aws.String(string(info.Marshal()))},
|
"Info": {S: aws.String(string(info.Marshal()))},
|
||||||
},
|
},
|
||||||
TableName: aws.String(c.lockTable),
|
TableName: aws.String(c.ddbTable),
|
||||||
ConditionExpression: aws.String("attribute_not_exists(LockID)"),
|
ConditionExpression: aws.String("attribute_not_exists(LockID)"),
|
||||||
}
|
}
|
||||||
_, err := c.dynClient.PutItem(putParams)
|
_, err := c.dynClient.PutItem(putParams)
|
||||||
|
@ -233,7 +233,7 @@ func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) getMD5() ([]byte, error) {
|
func (c *RemoteClient) getMD5() ([]byte, error) {
|
||||||
if c.lockTable == "" {
|
if c.ddbTable == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ func (c *RemoteClient) getMD5() ([]byte, error) {
|
||||||
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
|
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
|
||||||
},
|
},
|
||||||
ProjectionExpression: aws.String("LockID, Digest"),
|
ProjectionExpression: aws.String("LockID, Digest"),
|
||||||
TableName: aws.String(c.lockTable),
|
TableName: aws.String(c.ddbTable),
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := c.dynClient.GetItem(getParams)
|
resp, err := c.dynClient.GetItem(getParams)
|
||||||
|
@ -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.
|
// store the hash of the state to that clients can check for stale state files.
|
||||||
func (c *RemoteClient) putMD5(sum []byte) error {
|
func (c *RemoteClient) putMD5(sum []byte) error {
|
||||||
if c.lockTable == "" {
|
if c.ddbTable == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ func (c *RemoteClient) putMD5(sum []byte) error {
|
||||||
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
|
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
|
||||||
"Digest": {S: aws.String(hex.EncodeToString(sum))},
|
"Digest": {S: aws.String(hex.EncodeToString(sum))},
|
||||||
},
|
},
|
||||||
TableName: aws.String(c.lockTable),
|
TableName: aws.String(c.ddbTable),
|
||||||
}
|
}
|
||||||
_, err := c.dynClient.PutItem(putParams)
|
_, err := c.dynClient.PutItem(putParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -290,7 +290,7 @@ func (c *RemoteClient) putMD5(sum []byte) error {
|
||||||
|
|
||||||
// remove the hash value for a deleted state
|
// remove the hash value for a deleted state
|
||||||
func (c *RemoteClient) deleteMD5() error {
|
func (c *RemoteClient) deleteMD5() error {
|
||||||
if c.lockTable == "" {
|
if c.ddbTable == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ func (c *RemoteClient) deleteMD5() error {
|
||||||
Key: map[string]*dynamodb.AttributeValue{
|
Key: map[string]*dynamodb.AttributeValue{
|
||||||
"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
|
"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 {
|
if _, err := c.dynClient.DeleteItem(params); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -312,7 +312,7 @@ func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
|
||||||
"LockID": {S: aws.String(c.lockPath())},
|
"LockID": {S: aws.String(c.lockPath())},
|
||||||
},
|
},
|
||||||
ProjectionExpression: aws.String("LockID, Info"),
|
ProjectionExpression: aws.String("LockID, Info"),
|
||||||
TableName: aws.String(c.lockTable),
|
TableName: aws.String(c.ddbTable),
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := c.dynClient.GetItem(getParams)
|
resp, err := c.dynClient.GetItem(getParams)
|
||||||
|
@ -335,7 +335,7 @@ func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RemoteClient) Unlock(id string) error {
|
func (c *RemoteClient) Unlock(id string) error {
|
||||||
if c.lockTable == "" {
|
if c.ddbTable == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ func (c *RemoteClient) Unlock(id string) error {
|
||||||
Key: map[string]*dynamodb.AttributeValue{
|
Key: map[string]*dynamodb.AttributeValue{
|
||||||
"LockID": {S: aws.String(c.lockPath())},
|
"LockID": {S: aws.String(c.lockPath())},
|
||||||
},
|
},
|
||||||
TableName: aws.String(c.lockTable),
|
TableName: aws.String(c.ddbTable),
|
||||||
}
|
}
|
||||||
_, err = c.dynClient.DeleteItem(params)
|
_, err = c.dynClient.DeleteItem(params)
|
||||||
|
|
||||||
|
|
|
@ -47,17 +47,17 @@ func TestRemoteClientLocks(t *testing.T) {
|
||||||
keyName := "testState"
|
keyName := "testState"
|
||||||
|
|
||||||
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
createS3Bucket(t, b1.s3Client, bucketName)
|
createS3Bucket(t, b1.s3Client, bucketName)
|
||||||
|
@ -85,17 +85,17 @@ func TestForceUnlock(t *testing.T) {
|
||||||
keyName := "testState"
|
keyName := "testState"
|
||||||
|
|
||||||
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
createS3Bucket(t, b1.s3Client, bucketName)
|
createS3Bucket(t, b1.s3Client, bucketName)
|
||||||
|
@ -162,9 +162,9 @@ func TestRemoteClient_clientMD5(t *testing.T) {
|
||||||
keyName := "testState"
|
keyName := "testState"
|
||||||
|
|
||||||
b := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
createS3Bucket(t, b.s3Client, bucketName)
|
createS3Bucket(t, b.s3Client, bucketName)
|
||||||
|
@ -210,9 +210,9 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
||||||
keyName := "testState"
|
keyName := "testState"
|
||||||
|
|
||||||
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
"key": keyName,
|
"key": keyName,
|
||||||
"lock_table": bucketName,
|
"dynamodb_table": bucketName,
|
||||||
}).(*Backend)
|
}).(*Backend)
|
||||||
|
|
||||||
createS3Bucket(t, b1.s3Client, bucketName)
|
createS3Bucket(t, b1.s3Client, bucketName)
|
||||||
|
@ -238,7 +238,7 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
|
||||||
t.Fatal(err)
|
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
|
// client2 will write the "incorrect" state, simulating s3 eventually consistency delays
|
||||||
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
"bucket": bucketName,
|
"bucket": bucketName,
|
||||||
|
|
|
@ -93,9 +93,10 @@ The following configuration options or environment variables are supported:
|
||||||
* `secret_key` / `AWS_SECRET_ACCESS_KEY` - (Optional) AWS secret access key.
|
* `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
|
* `kms_key_id` - (Optional) The ARN of a KMS Key to use for encrypting
|
||||||
the state.
|
the state.
|
||||||
* `lock_table` - (Optional) The name of a DynamoDB table to use for state
|
* `lock_table` - (Optional, Deprecated) Use `dynamodb_table` instead.
|
||||||
locking. The table must have a primary key named LockID. If not present,
|
* `dynamodb_table` - (Optional) The name of a DynamoDB table to use for state
|
||||||
locking will be disabled.
|
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
|
* `profile` - (Optional) This is the AWS profile name as set in the
|
||||||
shared credentials file.
|
shared credentials file.
|
||||||
* `shared_credentials_file` - (Optional) This is the path to the
|
* `shared_credentials_file` - (Optional) This is the path to the
|
||||||
|
@ -103,4 +104,7 @@ The following configuration options or environment variables are supported:
|
||||||
`~/.aws/credentials` will be used.
|
`~/.aws/credentials` will be used.
|
||||||
* `token` - (Optional) Use this to set an MFA token. It can also be
|
* `token` - (Optional) Use this to set an MFA token. It can also be
|
||||||
sourced from the `AWS_SESSION_TOKEN` environment variable.
|
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.
|
||||||
|
|
Loading…
Reference in New Issue