feat: split dynamodb table supplier

main
sundowndev 2021-07-08 15:59:34 +02:00
parent 97af9a43b9
commit cff7a2fee3
14 changed files with 202 additions and 515441 deletions

View File

@ -0,0 +1,38 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
)
type DynamoDBTableDetailsFetcher struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
}
func NewDynamoDBTableDetailsFetcher(provider terraform.ResourceReader, deserializer *resource.Deserializer) *DynamoDBTableDetailsFetcher {
return &DynamoDBTableDetailsFetcher{
reader: provider,
deserializer: deserializer,
}
}
func (r *DynamoDBTableDetailsFetcher) ReadDetails(res resource.Resource) (resource.Resource, error) {
ctyVal, err := r.reader.ReadResource(terraform.ReadResourceArgs{
Ty: resource.ResourceType(res.TerraformType()),
ID: res.TerraformId(),
Attributes: map[string]string{
"table_name": res.TerraformId(),
},
})
if err != nil {
return nil, err
}
deserializedRes, err := r.deserializer.DeserializeOne(aws.AwsDynamodbTableResourceType, *ctyVal)
if err != nil {
return nil, err
}
return deserializedRes, nil
}

View File

@ -0,0 +1,46 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
)
type DynamoDBTableEnumerator struct {
repository repository.DynamoDBRepository
factory resource.ResourceFactory
}
func NewDynamoDBTableEnumerator(repository repository.DynamoDBRepository, factory resource.ResourceFactory) *DynamoDBTableEnumerator {
return &DynamoDBTableEnumerator{
repository,
factory,
}
}
func (e *DynamoDBTableEnumerator) SupportedType() resource.ResourceType {
return aws.AwsDynamodbTableResourceType
}
func (e *DynamoDBTableEnumerator) Enumerate() ([]resource.Resource, error) {
tables, err := e.repository.ListAllTables()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(e.SupportedType()))
}
results := make([]resource.Resource, len(tables))
for _, table := range tables {
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
*table,
map[string]interface{}{},
),
)
}
return results, nil
}

View File

@ -1,65 +0,0 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
)
type DynamoDBTableSupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.DynamoDBRepository
runner *terraform.ParallelResourceReader
}
func NewDynamoDBTableSupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer, repository repository.DynamoDBRepository) *DynamoDBTableSupplier {
return &DynamoDBTableSupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
}
}
func (s *DynamoDBTableSupplier) Resources() ([]resource.Resource, error) {
tables, err := s.repository.ListAllTables()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, aws.AwsDynamodbTableResourceType)
}
for _, table := range tables {
table := table
s.runner.Run(func() (cty.Value, error) {
return s.readTable(table)
})
}
retrieve, err := s.runner.Wait()
if err != nil {
return nil, err
}
return s.deserializer.Deserialize(aws.AwsDynamodbTableResourceType, retrieve)
}
func (s *DynamoDBTableSupplier) readTable(tableName *string) (cty.Value, error) {
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: *tableName,
Ty: aws.AwsDynamodbTableResourceType,
Attributes: map[string]string{
"table_name": *tableName,
},
})
if err != nil {
logrus.Error(err)
return cty.NilVal, err
}
return *val, nil
}

View File

@ -1,104 +0,0 @@
package aws
import (
"context"
"errors"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
testresource "github.com/cloudskiff/driftctl/test/resource"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/cloudskiff/driftctl/pkg/parallel"
"github.com/cloudskiff/driftctl/test/goldenfile"
mocks2 "github.com/cloudskiff/driftctl/test/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
)
func TestDynamoDBTableSupplier_Resources(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *repository.MockDynamoDBRepository)
err error
}{
{
test: "no DynamoDB Table",
dirName: "dynamodb_table_empty",
mocks: func(client *repository.MockDynamoDBRepository) {
client.On("ListAllTables").Return([]*string{}, nil)
},
err: nil,
},
{
test: "Multiple DynamoDB Table",
dirName: "dynamodb_table_multiple",
mocks: func(client *repository.MockDynamoDBRepository) {
client.On("ListAllTables").Return([]*string{
aws.String("GameScores"),
aws.String("example"),
}, nil)
},
err: nil,
},
{
test: "cannot list DynamoDB Table",
dirName: "dynamodb_table_list",
mocks: func(client *repository.MockDynamoDBRepository) {
client.On("ListAllTables").Return(nil, awserr.NewRequestFailure(awserr.New("AccessDeniedException", "", errors.New("")), 400, ""))
},
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(awserr.New("AccessDeniedException", "", errors.New("")), 400, ""), resourceaws.AwsDynamodbTableResourceType),
},
}
for _, c := range cases {
shouldUpdate := c.dirName == *goldenfile.Update
providerLibrary := terraform.NewProviderLibrary()
supplierLibrary := resource.NewSupplierLibrary()
repo := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(repo)
factory := terraform.NewTerraformResourceFactory(repo)
deserializer := resource.NewDeserializer(factory)
if shouldUpdate {
provider, err := InitTestAwsProvider(providerLibrary)
if err != nil {
t.Fatal(err)
}
supplierLibrary.AddSupplier(NewDynamoDBTableSupplier(provider, deserializer, repository.NewDynamoDBRepository(provider.session, cache.New(0))))
}
t.Run(c.test, func(tt *testing.T) {
fakeClient := repository.MockDynamoDBRepository{}
c.mocks(&fakeClient)
provider := mocks2.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
s := &DynamoDBTableSupplier{
provider,
deserializer,
&fakeClient,
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
}
got, err := s.Resources()
assert.Equal(tt, c.err, err)
mock.AssertExpectationsForObjects(tt)
test.CtyTestDiff(got, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}

View File

@ -131,6 +131,9 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddEnumerator(NewSNSTopicSubscriptionEnumerator(snsRepository, factory, alerter))
remoteLibrary.AddDetailsFetcher(aws.AwsSnsTopicSubscriptionResourceType, NewSNSTopicSubscriptionDetailsFetcher(provider, deserializer))
remoteLibrary.AddEnumerator(NewDynamoDBTableEnumerator(dynamoDBRepository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsDynamodbTableResourceType, NewDynamoDBTableDetailsFetcher(provider, deserializer))
supplierLibrary.AddSupplier(NewS3BucketAnalyticSupplier(provider, s3Repository, deserializer))
supplierLibrary.AddSupplier(NewLambdaFunctionSupplier(provider, deserializer, lambdaRepository))
supplierLibrary.AddSupplier(NewDBSubnetGroupSupplier(provider, deserializer, rdsRepository))
@ -146,7 +149,6 @@ func Init(version string, alerter *alerter.Alerter,
supplierLibrary.AddSupplier(NewVPCSecurityGroupRuleSupplier(provider, deserializer, ec2repository))
supplierLibrary.AddSupplier(NewRouteSupplier(provider, deserializer, ec2repository))
supplierLibrary.AddSupplier(NewNatGatewaySupplier(provider, deserializer, ec2repository))
supplierLibrary.AddSupplier(NewDynamoDBTableSupplier(provider, deserializer, dynamoDBRepository))
supplierLibrary.AddSupplier(NewECRRepositorySupplier(provider, deserializer, ecrRepository))
supplierLibrary.AddSupplier(NewLambdaEventSourceMappingSupplier(provider, deserializer, lambdaRepository))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
package remote
import (
"errors"
"testing"
awssdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/cloudskiff/driftctl/mocks"
"github.com/cloudskiff/driftctl/pkg/remote/aws"
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
"github.com/cloudskiff/driftctl/pkg/remote/common"
"github.com/cloudskiff/driftctl/pkg/resource"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/goldenfile"
testresource "github.com/cloudskiff/driftctl/test/resource"
terraform2 "github.com/cloudskiff/driftctl/test/terraform"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestDynamoDBTable(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(repository *repository.MockDynamoDBRepository)
wantErr error
}{
{
test: "no DynamoDB Table",
dirName: "dynamodb_table_empty",
mocks: func(client *repository.MockDynamoDBRepository) {
client.On("ListAllTables").Return([]*string{}, nil)
},
wantErr: nil,
},
{
test: "Multiple DynamoDB Table",
dirName: "dynamodb_table_multiple",
mocks: func(client *repository.MockDynamoDBRepository) {
client.On("ListAllTables").Return([]*string{
awssdk.String("GameScores"),
awssdk.String("example"),
}, nil)
},
wantErr: nil,
},
{
test: "cannot list DynamoDB Table",
dirName: "dynamodb_table_list",
mocks: func(client *repository.MockDynamoDBRepository) {
client.On("ListAllTables").Return(nil, awserr.NewRequestFailure(awserr.New("AccessDeniedException", "", errors.New("")), 400, ""))
},
wantErr: nil,
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
for _, c := range tests {
t.Run(c.test, func(tt *testing.T) {
shouldUpdate := c.dirName == *goldenfile.Update
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
scanOptions := ScannerOptions{Deep: true}
providerLibrary := terraform.NewProviderLibrary()
remoteLibrary := common.NewRemoteLibrary()
// Initialize mocks
alerter := &mocks.AlerterInterface{}
alerter.On("SendAlert", mock.Anything, mock.Anything).Maybe().Return()
fakeRepo := &repository.MockDynamoDBRepository{}
c.mocks(fakeRepo)
var repo repository.DynamoDBRepository = fakeRepo
providerVersion := "3.19.0"
realProvider, err := terraform2.InitTestAwsProvider(providerLibrary, providerVersion)
if err != nil {
t.Fatal(err)
}
provider := terraform2.NewFakeTerraformProvider(realProvider)
provider.WithResponse(c.dirName)
// Replace mock by real resources if we are in update mode
if shouldUpdate {
err := realProvider.Init()
if err != nil {
t.Fatal(err)
}
provider.ShouldUpdate()
repo = repository.NewDynamoDBRepository(sess, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewDynamoDBTableEnumerator(repo, factory))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsDynamodbTableResourceType, aws.NewDynamoDBTableDetailsFetcher(provider, deserializer))
s := NewScanner(nil, remoteLibrary, alerter, scanOptions)
got, err := s.Resources()
assert.Equal(tt, c.wantErr, err)
if err != nil {
return
}
test.TestAgainstGoldenFile(got, resourceaws.AwsDynamodbTableResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}