Skip to content

Commit 57ab814

Browse files
authored
Merge pull request #35661 from bschaatsbergen/use-s3-conditional-writes
Introduce S3-native state locking
2 parents b6e6f65 + 1ccbcad commit 57ab814

File tree

6 files changed

+866
-28
lines changed

6 files changed

+866
-28
lines changed

internal/backend/remote-state/s3/backend.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type Backend struct {
4646
acl string
4747
kmsKeyID string
4848
ddbTable string
49+
useLockFile bool
4950
workspaceKeyPrefix string
5051
skipS3Checksum bool
5152
}
@@ -152,6 +153,11 @@ func (b *Backend) ConfigSchema() *configschema.Block {
152153
Optional: true,
153154
Description: "DynamoDB table for state locking and consistency",
154155
},
156+
"use_lockfile": {
157+
Type: cty.Bool,
158+
Optional: true,
159+
Description: "(Experimental) Whether to use a lockfile for locking the state file.",
160+
},
155161
"profile": {
156162
Type: cty.String,
157163
Optional: true,
@@ -822,6 +828,7 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics {
822828
b.serverSideEncryption = boolAttr(obj, "encrypt")
823829
b.kmsKeyID = stringAttr(obj, "kms_key_id")
824830
b.ddbTable = stringAttr(obj, "dynamodb_table")
831+
b.useLockFile = boolAttr(obj, "use_lockfile")
825832
b.skipS3Checksum = boolAttr(obj, "skip_s3_checksum")
826833

827834
if _, ok := stringAttrOk(obj, "kms_key_id"); ok {

internal/backend/remote-state/s3/backend_state.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ const (
2727
// defaultWorkspaceKeyPrefix is the default prefix for workspace storage.
2828
// The colon is used to reduce the chance of name conflicts with existing objects.
2929
defaultWorkspaceKeyPrefix = "env:"
30+
// lockFileSuffix defines the suffix for Terraform state lock files.
31+
lockFileSuffix = ".tflock"
3032
)
3133

3234
func (b *Backend) Workspaces() ([]string, error) {
@@ -163,6 +165,8 @@ func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
163165
kmsKeyID: b.kmsKeyID,
164166
ddbTable: b.ddbTable,
165167
skipS3Checksum: b.skipS3Checksum,
168+
lockFilePath: b.getLockFilePath(name),
169+
useLockFile: b.useLockFile,
166170
}
167171

168172
return client, nil
@@ -276,3 +280,9 @@ func newBucketRegionError(requestRegion, bucketRegion string) bucketRegionError
276280
func (err bucketRegionError) Error() string {
277281
return fmt.Sprintf("requested bucket from %q, actual location %q", err.requestRegion, err.bucketRegion)
278282
}
283+
284+
// getLockFilePath returns the path to the lock file for the given Terraform state.
285+
// For `default.tfstate`, the lock file is stored at `default.tfstate.tflock`.
286+
func (b *Backend) getLockFilePath(name string) string {
287+
return b.path(name) + lockFileSuffix
288+
}

0 commit comments

Comments
 (0)