func (a *AWS) GetStates() (states []string, err error) {
	log.WithFields(log.Fields{
		"bucket": a.bucket,
		"prefix": a.keyPrefix,
	}).Debug("Listing states from S3")
	result, err := a.svc.ListObjects(&s3.ListObjectsInput{
		Bucket: aws_sdk.String(a.bucket),
		Prefix: &a.keyPrefix,
	})
	if err != nil {
		return states, err
	}
	var keys []string
	for _, obj := range result.Contents {
		for _, ext := range a.fileExtension {
			if strings.HasSuffix(*obj.Key, ext) {
				keys = append(keys, *obj.Key)
			}
		}
	}
	states = keys
	log.WithFields(log.Fields{
		"bucket": a.bucket,
		"prefix": a.keyPrefix,
		"states": len(states),
	}).Debug("Found states from S3")
	return states, nil
}
GetStates returns a slice of State files in the S3 bucket
package state
import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"
	aws_sdk "github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/camptocamp/terraboard/config"
	"github.com/camptocamp/terraboard/internal/terraform/states/statefile"
	log "github.com/sirupsen/logrus"
)
type AWS struct {
	svc           s3iface.S3API
	dynamoSvc     dynamodbiface.DynamoDBAPI
	bucket        string
	dynamoTable   string
	keyPrefix     string
	fileExtension []string
	noLocks       bool
	noVersioning  bool
}
func NewAWS(aws config.AWSConfig, bucket config.S3BucketConfig, noLocks, noVersioning bool) *AWS {
	if bucket.Bucket == "" {
		return nil
	}
	sess := session.Must(session.NewSession())
	awsConfig := aws_sdk.NewConfig()
	var creds *credentials.Credentials
	if len(aws.APPRoleArn) > 0 {
		log.Debugf("Using %s role", aws.APPRoleArn)
		creds = stscreds.NewCredentials(sess, aws.APPRoleArn, func(p *stscreds.AssumeRoleProvider) {
			if aws.ExternalID != "" {
				p.ExternalID = aws_sdk.String(aws.ExternalID)
			}
		})
	} else {
		if aws.AccessKey == "" || aws.SecretAccessKey == "" {
			log.Fatal("Missing AccessKey or SecretAccessKey for AWS provider. Please check your configuration and retry")
		}
		creds = credentials.NewStaticCredentials(aws.AccessKey, aws.SecretAccessKey, aws.SessionToken)
	}
	awsConfig.WithCredentials(creds)
	if e := aws.Endpoint; e != "" {
		awsConfig.WithEndpoint(e)
	}
	if e := aws.Region; e != "" {
		awsConfig.WithRegion(e)
	}
	awsConfig.S3ForcePathStyle = &bucket.ForcePathStyle
	return &AWS{
		svc:           s3.New(sess, awsConfig),
		bucket:        bucket.Bucket,
		keyPrefix:     bucket.KeyPrefix,
		fileExtension: bucket.FileExtension,
		dynamoSvc:     dynamodbiface.DynamoDBAPI(dynamodb.New(sess, awsConfig)),
		dynamoTable:   aws.DynamoDBTable,
		noLocks:       noLocks,
		noVersioning:  noVersioning,
	}
}
func NewAWSCollection(c *config.Config) []*AWS {
	var awsInstances []*AWS
	for _, aws := range c.AWS {
		for _, bucket := range aws.S3 {
			if awsInstance := NewAWS(aws, bucket, c.Provider.NoLocks, c.Provider.NoVersioning); awsInstance != nil {
				awsInstances = append(awsInstances, awsInstance)
			}
		}
	}
	return awsInstances
}
func (a *AWS) GetLocks() (locks map[string]LockInfo, err error) {
	if a.noLocks {
		locks = make(map[string]LockInfo)
		return
	}
	if a.dynamoTable == "" {
		err = fmt.Errorf("no dynamoDB table provided, not getting locks")
		return
	}
	results, err := a.dynamoSvc.Scan(&dynamodb.ScanInput{
		TableName: &a.dynamoTable,
	})
	if err != nil {
		return locks, err
	}
	var lockList []Lock
	err = dynamodbattribute.UnmarshalListOfMaps(results.Items, &lockList)
	if err != nil {
		return locks, err
	}
	locks = make(map[string]LockInfo)
	infoPrefix := fmt.Sprintf("%s/", a.bucket)
	for _, lock := range lockList {
		if lock.Info != "" {
			var info LockInfo
			err = json.Unmarshal([]byte(lock.Info), &info)
			if err != nil {
				return locks, err
			}
			locks[strings.TrimPrefix(info.Path, infoPrefix)] = info
		}
	}
	return
}