backend/remote-state/gcloud: Refactor Backend.States().

The previous code listed all objects in the bucket and used local filtering
(using regular expressions) to find .tfstate objects. This new code sets
the delimiter to "/", which causes GCS to only return objects directly in
the given prefix, but not any sub"directories".

Fixes:
* https://github.com/golang/go/wiki/CodeReviewComments#doc-comments
* https://github.com/golang/go/wiki/CodeReviewComments#error-strings
This commit is contained in:
Florian Forster 2017-09-08 09:25:20 +02:00 committed by James Bardin
parent 97e1aa7ce9
commit fabba5c0c8
2 changed files with 22 additions and 25 deletions

View File

@ -3,6 +3,7 @@ package gcloud
import (
"context"
"fmt"
"strings"
"cloud.google.com/go/storage"
"github.com/hashicorp/terraform/backend"
@ -67,7 +68,7 @@ func (b *Backend) configure(ctx context.Context) error {
data := schema.FromContextBackendConfig(b.storageContext)
b.bucketName = data.Get("bucket").(string)
b.stateDir = data.Get("state_dir").(string)
b.stateDir = strings.TrimLeft(data.Get("state_dir").(string), "/")
var tokenSource oauth2.TokenSource

View File

@ -3,7 +3,7 @@ package gcloud
import (
"errors"
"fmt"
"regexp"
"path"
"sort"
"strings"
@ -15,42 +15,38 @@ import (
"google.golang.org/api/iterator"
)
// States returns a list of names for the states found on GCS. The default
// state is always returned as the first element in the slice.
func (b *Backend) States() ([]string, error) {
workspaces := []string{backend.DefaultStateName}
var stateRegex *regexp.Regexp
var err error
if b.stateDir == "" {
stateRegex = regexp.MustCompile(`^(.+)\.tfstate$`)
} else {
stateRegex, err = regexp.Compile(fmt.Sprintf("^%v/(.+)\\.tfstate$", regexp.QuoteMeta(b.stateDir)))
if err != nil {
return []string{}, fmt.Errorf("Failed to compile regex for querying states: %v", err)
}
}
states := []string{backend.DefaultStateName}
bucket := b.storageClient.Bucket(b.bucketName)
query := &storage.Query{
Prefix: b.stateDir,
}
files := bucket.Objects(b.storageContext, query)
objs := bucket.Objects(b.storageContext, &storage.Query{
Delimiter: "/",
Prefix: b.stateDir,
})
for {
attrs, err := files.Next()
attrs, err := objs.Next()
if err == iterator.Done {
break
}
if err != nil {
return []string{}, fmt.Errorf("Failed to query remote states: %v", err)
return nil, fmt.Errorf("querying Cloud Storage failed: %v", err)
}
matches := stateRegex.FindStringSubmatch(attrs.Name)
if len(matches) == 2 && matches[1] != backend.DefaultStateName {
workspaces = append(workspaces, matches[1])
name := path.Base(attrs.Name)
if !strings.HasSuffix(name, ".tfstate") {
continue
}
st := strings.TrimSuffix(name, ".tfstate")
if st != backend.DefaultStateName {
states = append(states, st)
}
}
sort.Strings(workspaces[1:])
return workspaces, nil
sort.Strings(states[1:])
return states, nil
}
func (b *Backend) DeleteState(name string) error {