diff --git a/backend/remote-state/s3/backend.go b/backend/remote-state/s3/backend.go index 0891ecab6..1a1e10bab 100644 --- a/backend/remote-state/s3/backend.go +++ b/backend/remote-state/s3/backend.go @@ -139,6 +139,13 @@ func New() backend.Backend { Description: "The permissions applied when assuming a role.", Default: "", }, + + "workspace_key_prefix": { + Type: schema.TypeString, + Optional: true, + Description: "The prefix applied to the non-default state path inside the bucket", + Default: "env:", + }, }, } @@ -160,6 +167,7 @@ type Backend struct { acl string kmsKeyID string ddbTable string + workspaceKeyPrefix string } func (b *Backend) configure(ctx context.Context) error { @@ -175,6 +183,7 @@ 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.workspaceKeyPrefix = data.Get("workspace_key_prefix").(string) b.ddbTable = data.Get("dynamodb_table").(string) if b.ddbTable == "" { diff --git a/backend/remote-state/s3/backend_state.go b/backend/remote-state/s3/backend_state.go index 3d7a3c4e5..f38b199b0 100644 --- a/backend/remote-state/s3/backend_state.go +++ b/backend/remote-state/s3/backend_state.go @@ -14,16 +14,10 @@ import ( "github.com/hashicorp/terraform/terraform" ) -const ( - // This will be used as directory name, the odd looking colon is simply to - // reduce the chance of name conflicts with existing objects. - keyEnvPrefix = "env:" -) - func (b *Backend) States() ([]string, error) { params := &s3.ListObjectsInput{ Bucket: &b.bucketName, - Prefix: aws.String(keyEnvPrefix + "/"), + Prefix: aws.String(b.workspaceKeyPrefix + "/"), } resp, err := b.s3Client.ListObjects(params) @@ -53,7 +47,7 @@ func (b *Backend) keyEnv(key string) string { } // shouldn't happen since we listed by prefix - if parts[0] != keyEnvPrefix { + if parts[0] != b.workspaceKeyPrefix { return "" } @@ -183,7 +177,7 @@ func (b *Backend) path(name string) string { return b.keyName } - return strings.Join([]string{keyEnvPrefix, name, b.keyName}, "/") + return strings.Join([]string{b.workspaceKeyPrefix, name, b.keyName}, "/") } const errStateUnlock = ` diff --git a/backend/remote-state/s3/backend_test.go b/backend/remote-state/s3/backend_test.go index bdc81e899..c5a1f5009 100644 --- a/backend/remote-state/s3/backend_test.go +++ b/backend/remote-state/s3/backend_test.go @@ -159,7 +159,7 @@ func TestBackendExtraPaths(t *testing.T) { } // put a state in an env directory name - client.path = keyEnvPrefix + "/error" + client.path = b.workspaceKeyPrefix + "/error" stateMgr.WriteState(terraform.NewState()) if err := stateMgr.PersistState(); err != nil { t.Fatal(err) @@ -169,7 +169,7 @@ func TestBackendExtraPaths(t *testing.T) { } // add state with the wrong key for an existing env - client.path = keyEnvPrefix + "/s2/notTestState" + client.path = b.workspaceKeyPrefix + "/s2/notTestState" stateMgr.WriteState(terraform.NewState()) if err := stateMgr.PersistState(); err != nil { t.Fatal(err) @@ -202,7 +202,7 @@ func TestBackendExtraPaths(t *testing.T) { s2 = s2Mgr.State() // add a state with a key that matches an existing environment dir name - client.path = keyEnvPrefix + "/s2/" + client.path = b.workspaceKeyPrefix + "/s2/" stateMgr.WriteState(terraform.NewState()) if err := stateMgr.PersistState(); err != nil { t.Fatal(err) diff --git a/website/docs/backends/types/s3.html.md b/website/docs/backends/types/s3.html.md index 51419cd77..b4b86ec7e 100644 --- a/website/docs/backends/types/s3.html.md +++ b/website/docs/backends/types/s3.html.md @@ -108,3 +108,6 @@ The following configuration options or environment variables are supported: * `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. + * `workspace_key_prefix` - (Optional) The prefix applied to the state path + inside the bucket. This is only relevant when using a non-default workspace. + This defaults to "env:"