Merge pull request #16932 from rv-jmaggio/master
Fixing issues with workspace_key_prefix for s3 backend
This commit is contained in:
commit
7c703f2ab2
|
@ -15,9 +15,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Backend) States() ([]string, error) {
|
func (b *Backend) States() ([]string, error) {
|
||||||
|
prefix := b.workspaceKeyPrefix + "/"
|
||||||
|
|
||||||
|
// List bucket root if there is no workspaceKeyPrefix
|
||||||
|
if b.workspaceKeyPrefix == "" {
|
||||||
|
prefix = ""
|
||||||
|
}
|
||||||
params := &s3.ListObjectsInput{
|
params := &s3.ListObjectsInput{
|
||||||
Bucket: &b.bucketName,
|
Bucket: &b.bucketName,
|
||||||
Prefix: aws.String(b.workspaceKeyPrefix + "/"),
|
Prefix: aws.String(prefix),
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := b.s3Client.ListObjects(params)
|
resp, err := b.s3Client.ListObjects(params)
|
||||||
|
@ -25,24 +31,31 @@ func (b *Backend) States() ([]string, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
envs := []string{backend.DefaultStateName}
|
wss := []string{backend.DefaultStateName}
|
||||||
for _, obj := range resp.Contents {
|
for _, obj := range resp.Contents {
|
||||||
env := b.keyEnv(*obj.Key)
|
ws := b.keyEnv(*obj.Key)
|
||||||
if env != "" {
|
if ws != "" {
|
||||||
envs = append(envs, env)
|
wss = append(wss, ws)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(envs[1:])
|
sort.Strings(wss[1:])
|
||||||
return envs, nil
|
return wss, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the env name from the S3 key
|
|
||||||
func (b *Backend) keyEnv(key string) string {
|
func (b *Backend) keyEnv(key string) string {
|
||||||
// we have 3 parts, the prefix, the env name, and the key name
|
if b.workspaceKeyPrefix == "" {
|
||||||
parts := strings.SplitN(key, "/", 3)
|
parts := strings.SplitN(key, "/", 2)
|
||||||
if len(parts) < 3 {
|
if len(parts) > 1 && parts[1] == b.keyName {
|
||||||
// no env here
|
return parts[0]
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.SplitAfter(key, b.workspaceKeyPrefix)
|
||||||
|
|
||||||
|
if len(parts) < 2 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +64,12 @@ func (b *Backend) keyEnv(key string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parts = strings.SplitN(parts[1], "/", 3)
|
||||||
|
|
||||||
|
if len(parts) < 3 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// not our key, so don't include it in our listing
|
// not our key, so don't include it in our listing
|
||||||
if parts[2] != b.keyName {
|
if parts[2] != b.keyName {
|
||||||
return ""
|
return ""
|
||||||
|
@ -177,7 +196,12 @@ func (b *Backend) path(name string) string {
|
||||||
return b.keyName
|
return b.keyName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.workspaceKeyPrefix != "" {
|
||||||
return strings.Join([]string{b.workspaceKeyPrefix, name, b.keyName}, "/")
|
return strings.Join([]string{b.workspaceKeyPrefix, name, b.keyName}, "/")
|
||||||
|
} else {
|
||||||
|
// Trim the leading / for no workspace prefix
|
||||||
|
return strings.Join([]string{b.workspaceKeyPrefix, name, b.keyName}, "/")[1:]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const errStateUnlock = `
|
const errStateUnlock = `
|
||||||
|
|
|
@ -249,6 +249,74 @@ func TestBackendExtraPaths(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKeyEnv(t *testing.T) {
|
||||||
|
testACC(t)
|
||||||
|
keyName := "some/paths/tfstate"
|
||||||
|
|
||||||
|
bucket0Name := fmt.Sprintf("terraform-remote-s3-test-%x-0", time.Now().Unix())
|
||||||
|
b0 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
|
"bucket": bucket0Name,
|
||||||
|
"key": keyName,
|
||||||
|
"encrypt": true,
|
||||||
|
"workspace_key_prefix": "",
|
||||||
|
}).(*Backend)
|
||||||
|
|
||||||
|
createS3Bucket(t, b0.s3Client, bucket0Name)
|
||||||
|
defer deleteS3Bucket(t, b0.s3Client, bucket0Name)
|
||||||
|
|
||||||
|
bucket1Name := fmt.Sprintf("terraform-remote-s3-test-%x-1", time.Now().Unix())
|
||||||
|
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
|
"bucket": bucket1Name,
|
||||||
|
"key": keyName,
|
||||||
|
"encrypt": true,
|
||||||
|
"workspace_key_prefix": "project/env:",
|
||||||
|
}).(*Backend)
|
||||||
|
|
||||||
|
createS3Bucket(t, b1.s3Client, bucket1Name)
|
||||||
|
defer deleteS3Bucket(t, b1.s3Client, bucket1Name)
|
||||||
|
|
||||||
|
bucket2Name := fmt.Sprintf("terraform-remote-s3-test-%x-2", time.Now().Unix())
|
||||||
|
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
|
||||||
|
"bucket": bucket2Name,
|
||||||
|
"key": keyName,
|
||||||
|
"encrypt": true,
|
||||||
|
}).(*Backend)
|
||||||
|
|
||||||
|
createS3Bucket(t, b2.s3Client, bucket2Name)
|
||||||
|
defer deleteS3Bucket(t, b2.s3Client, bucket2Name)
|
||||||
|
|
||||||
|
if err := testGetWorkspaceForKey(b0, "some/paths/tfstate", ""); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := testGetWorkspaceForKey(b0, "ws1/some/paths/tfstate", "ws1"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := testGetWorkspaceForKey(b1, "project/env:/ws1/some/paths/tfstate", "ws1"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := testGetWorkspaceForKey(b1, "project/env:/ws2/some/paths/tfstate", "ws2"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := testGetWorkspaceForKey(b2, "env:/ws3/some/paths/tfstate", "ws3"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.TestBackend(t, b0, nil)
|
||||||
|
backend.TestBackend(t, b1, nil)
|
||||||
|
backend.TestBackend(t, b2, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetWorkspaceForKey(b *Backend, key string, expected string) error {
|
||||||
|
if actual := b.keyEnv(key); actual != expected {
|
||||||
|
return fmt.Errorf("incorrect workspace for key[%q]. Expected[%q]: Actual[%q]", key, expected, actual)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func checkStateList(b backend.Backend, expected []string) error {
|
func checkStateList(b backend.Backend, expected []string) error {
|
||||||
states, err := b.States()
|
states, err := b.States()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue