Merge branch 'main' into change_Sqs_to_SQS

main
William BEUIL 2021-07-08 17:17:32 +02:00 committed by GitHub
commit 6972f95994
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 597 additions and 1374628 deletions

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 CloudfrontDistributionEnumerator struct {
repository repository.CloudfrontRepository
factory resource.ResourceFactory
}
func NewCloudfrontDistributionEnumerator(repo repository.CloudfrontRepository, factory resource.ResourceFactory) *CloudfrontDistributionEnumerator {
return &CloudfrontDistributionEnumerator{
repository: repo,
factory: factory,
}
}
func (e *CloudfrontDistributionEnumerator) SupportedType() resource.ResourceType {
return aws.AwsCloudfrontDistributionResourceType
}
func (e *CloudfrontDistributionEnumerator) Enumerate() ([]resource.Resource, error) {
distributions, err := e.repository.ListAllDistributions()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(e.SupportedType()))
}
results := make([]resource.Resource, len(distributions))
for _, distribution := range distributions {
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
*distribution.Id,
map[string]interface{}{},
),
)
}
return results, err
}

View File

@ -1,61 +0,0 @@
package aws
import (
"github.com/aws/aws-sdk-go/service/cloudfront"
"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"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
)
type CloudfrontDistributionSupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.CloudfrontRepository
runner *terraform.ParallelResourceReader
}
func NewCloudfrontDistributionSupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer, repository repository.CloudfrontRepository) *CloudfrontDistributionSupplier {
return &CloudfrontDistributionSupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
}
}
func (s *CloudfrontDistributionSupplier) Resources() ([]resource.Resource, error) {
distributions, err := s.repository.ListAllDistributions()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, aws.AwsCloudfrontDistributionResourceType)
}
for _, distribution := range distributions {
d := *distribution
s.runner.Run(func() (cty.Value, error) {
return s.readCloudfrontDistribution(d)
})
}
resources, err := s.runner.Wait()
if err != nil {
return nil, err
}
return s.deserializer.Deserialize(aws.AwsCloudfrontDistributionResourceType, resources)
}
func (s *CloudfrontDistributionSupplier) readCloudfrontDistribution(distribution cloudfront.DistributionSummary) (cty.Value, error) {
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: *distribution.Id,
Ty: aws.AwsCloudfrontDistributionResourceType,
})
if err != nil {
logrus.Error(err)
return cty.NilVal, err
}
return *val, nil
}

View File

@ -1,99 +0,0 @@
package aws
import (
"context"
"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"
"github.com/aws/aws-sdk-go/service/cloudfront"
"github.com/aws/aws-sdk-go/aws/awserr"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/parallel"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/goldenfile"
testmocks "github.com/cloudskiff/driftctl/test/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestCloudfrontDistributionSupplier_Resources(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *repository.MockCloudfrontRepository)
err error
}{
{
test: "no cloudfront distribution",
dirName: "cloudfront_distribution_empty",
mocks: func(client *repository.MockCloudfrontRepository) {
client.On("ListAllDistributions").Return([]*cloudfront.DistributionSummary{}, nil)
},
err: nil,
},
{
test: "one cloudfront distribution",
dirName: "cloudfront_distribution_one",
mocks: func(client *repository.MockCloudfrontRepository) {
client.On("ListAllDistributions").Return([]*cloudfront.DistributionSummary{
{Id: aws.String("E1M9CNS0XSHI19")},
}, nil)
},
err: nil,
},
{
test: "cannot list cloudfront distributions",
dirName: "cloudfront_distribution_empty",
mocks: func(client *repository.MockCloudfrontRepository) {
client.On("ListAllDistributions").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsCloudfrontDistributionResourceType),
},
}
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(NewCloudfrontDistributionSupplier(provider, deserializer, repository.NewCloudfrontRepository(provider.session, cache.New(0))))
}
t.Run(c.test, func(tt *testing.T) {
fakeCloudfront := repository.MockCloudfrontRepository{}
c.mocks(&fakeCloudfront)
provider := testmocks.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
s := &CloudfrontDistributionSupplier{
provider,
deserializer,
&fakeCloudfront,
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

@ -99,6 +99,10 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddDetailsFetcher(aws.AwsSubnetResourceType, common.NewGenericDetailsFetcher(aws.AwsSubnetResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewEC2DefaultSubnetEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsDefaultSubnetResourceType, common.NewGenericDetailsFetcher(aws.AwsDefaultSubnetResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewVPCSecurityGroupEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsSecurityGroupResourceType, common.NewGenericDetailsFetcher(aws.AwsSecurityGroupResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewVPCDefaultSecurityGroupEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsDefaultSecurityGroupResourceType, common.NewGenericDetailsFetcher(aws.AwsDefaultSecurityGroupResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewKMSKeyEnumerator(kmsRepository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsKmsKeyResourceType, common.NewGenericDetailsFetcher(aws.AwsKmsKeyResourceType, provider, deserializer))
@ -112,11 +116,8 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddEnumerator(NewRoute53RecordEnumerator(route53repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsRoute53RecordResourceType, common.NewGenericDetailsFetcher(aws.AwsRoute53RecordResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewVPCSecurityGroupEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsSecurityGroupResourceType, common.NewGenericDetailsFetcher(aws.AwsSecurityGroupResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewVPCDefaultSecurityGroupEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsDefaultSecurityGroupResourceType, common.NewGenericDetailsFetcher(aws.AwsDefaultSecurityGroupResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewCloudfrontDistributionEnumerator(cloudfrontRepository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsCloudfrontDistributionResourceType, common.NewGenericDetailsFetcher(aws.AwsCloudfrontDistributionResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewSQSQueueEnumerator(sqsRepository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsSqsQueueResourceType, common.NewGenericDetailsFetcher(aws.AwsSqsQueueResourceType, provider, deserializer))
@ -125,6 +126,10 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddEnumerator(NewSNSTopicEnumerator(snsRepository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsSnsTopicResourceType, NewSNSTopicDetailsFetcher(provider, deserializer))
remoteLibrary.AddEnumerator(NewSNSTopicPolicyEnumerator(snsRepository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsSnsTopicPolicyResourceType, NewSNSTopicPolicyDetailsFetcher(provider, deserializer))
remoteLibrary.AddEnumerator(NewSNSTopicSubscriptionEnumerator(snsRepository, factory, alerter))
remoteLibrary.AddDetailsFetcher(aws.AwsSnsTopicSubscriptionResourceType, NewSNSTopicSubscriptionDetailsFetcher(provider, deserializer))
supplierLibrary.AddSupplier(NewS3BucketAnalyticSupplier(provider, s3Repository, deserializer))
supplierLibrary.AddSupplier(NewLambdaFunctionSupplier(provider, deserializer, lambdaRepository))
@ -141,10 +146,7 @@ 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(NewSNSTopicPolicySupplier(provider, deserializer, snsRepository))
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider, alerter, deserializer, snsRepository))
supplierLibrary.AddSupplier(NewDynamoDBTableSupplier(provider, deserializer, dynamoDBRepository))
supplierLibrary.AddSupplier(NewCloudfrontDistributionSupplier(provider, deserializer, cloudfrontRepository))
supplierLibrary.AddSupplier(NewECRRepositorySupplier(provider, deserializer, ecrRepository))
supplierLibrary.AddSupplier(NewLambdaEventSourceMappingSupplier(provider, deserializer, lambdaRepository))

View File

@ -0,0 +1,36 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
"github.com/cloudskiff/driftctl/pkg/terraform"
)
type SNSTopicPolicyDetailsFetcher struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
}
func NewSNSTopicPolicyDetailsFetcher(provider terraform.ResourceReader, deserializer *resource.Deserializer) *SNSTopicPolicyDetailsFetcher {
return &SNSTopicPolicyDetailsFetcher{
reader: provider,
deserializer: deserializer,
}
}
func (r *SNSTopicPolicyDetailsFetcher) ReadDetails(topic resource.Resource) (resource.Resource, error) {
val, err := r.reader.ReadResource(terraform.ReadResourceArgs{
ID: topic.TerraformId(),
Ty: aws.AwsSnsTopicPolicyResourceType,
Attributes: map[string]string{
"topic_arn": topic.TerraformId(),
},
})
if err != nil {
logrus.Error(err)
return nil, err
}
return r.deserializer.DeserializeOne(aws.AwsSnsTopicPolicyResourceType, *val)
}

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 SNSTopicPolicyEnumerator struct {
repository repository.SNSRepository
factory resource.ResourceFactory
}
func NewSNSTopicPolicyEnumerator(repo repository.SNSRepository, factory resource.ResourceFactory) *SNSTopicPolicyEnumerator {
return &SNSTopicPolicyEnumerator{
repository: repo,
factory: factory,
}
}
func (e *SNSTopicPolicyEnumerator) SupportedType() resource.ResourceType {
return aws.AwsSnsTopicPolicyResourceType
}
func (e *SNSTopicPolicyEnumerator) Enumerate() ([]resource.Resource, error) {
topics, err := e.repository.ListAllTopics()
if err != nil {
return nil, remoteerror.NewResourceEnumerationErrorWithType(err, string(e.SupportedType()), aws.AwsSnsTopicResourceType)
}
results := make([]resource.Resource, len(topics))
for _, topic := range topics {
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
*topic.TopicArn,
map[string]interface{}{},
),
)
}
return results, err
}

View File

@ -1,66 +0,0 @@
package aws
import (
"github.com/aws/aws-sdk-go/service/sns"
"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 SNSTopicPolicySupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.SNSRepository
runner *terraform.ParallelResourceReader
}
func NewSNSTopicPolicySupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer, repository repository.SNSRepository) *SNSTopicPolicySupplier {
return &SNSTopicPolicySupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
}
}
func (s *SNSTopicPolicySupplier) Resources() ([]resource.Resource, error) {
topics, err := s.repository.ListAllTopics()
if err != nil {
return nil, remoteerror.NewResourceEnumerationErrorWithType(err, aws.AwsSnsTopicPolicyResourceType, aws.AwsSnsTopicResourceType)
}
for _, topic := range topics {
topic := *topic
s.runner.Run(func() (cty.Value, error) {
return s.readTopicPolicy(topic)
})
}
retrieve, err := s.runner.Wait()
if err != nil {
return nil, err
}
return s.deserializer.Deserialize(aws.AwsSnsTopicPolicyResourceType, retrieve)
}
func (s *SNSTopicPolicySupplier) readTopicPolicy(topic sns.Topic) (cty.Value, error) {
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: *topic.TopicArn,
Ty: aws.AwsSnsTopicPolicyResourceType,
Attributes: map[string]string{
"topic_arn": *topic.TopicArn,
},
})
if err != nil {
logrus.Error(err)
return cty.NilVal, err
}
return *val, nil
}

View File

@ -1,103 +0,0 @@
package aws
import (
"context"
"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"
"github.com/aws/aws-sdk-go/service/sns"
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 TestSNSTopicPolicySupplier_Resources(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *repository.MockSNSRepository)
err error
}{
{
test: "no SNS Topic policy",
dirName: "sns_topic_policy_empty",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllTopics").Return([]*sns.Topic{}, nil)
},
err: nil,
},
{
test: "Multiple SNSTopicPolicy",
dirName: "sns_topic_policy_multiple",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllTopics").Return([]*sns.Topic{
{TopicArn: aws.String("arn:aws:sns:us-east-1:526954929923:my-topic-with-policy")},
{TopicArn: aws.String("arn:aws:sns:us-east-1:526954929923:my-topic-with-policy2")},
}, nil)
},
err: nil,
},
{
test: "cannot list SNSTopic",
dirName: "sns_topic_policy_topic_list",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllTopics").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
err: remoteerror.NewResourceEnumerationErrorWithType(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsSnsTopicPolicyResourceType, resourceaws.AwsSnsTopicResourceType),
},
}
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(NewSNSTopicPolicySupplier(provider, deserializer, repository.NewSNSRepository(provider.session, cache.New(0))))
}
t.Run(c.test, func(tt *testing.T) {
fakeClient := repository.MockSNSRepository{}
c.mocks(&fakeClient)
provider := mocks2.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
s := &SNSTopicPolicySupplier{
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

@ -0,0 +1,41 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
"github.com/cloudskiff/driftctl/pkg/terraform"
)
type SNSTopicSubscriptionDetailsFetcher struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
}
func NewSNSTopicSubscriptionDetailsFetcher(provider terraform.ResourceReader, deserializer *resource.Deserializer) *SNSTopicSubscriptionDetailsFetcher {
return &SNSTopicSubscriptionDetailsFetcher{
reader: provider,
deserializer: deserializer,
}
}
func (r *SNSTopicSubscriptionDetailsFetcher) ReadDetails(res resource.Resource) (resource.Resource, error) {
ctyVal, err := r.reader.ReadResource(terraform.ReadResourceArgs{
ID: res.TerraformId(),
Ty: aws.AwsSnsTopicSubscriptionResourceType,
Attributes: map[string]string{
"SubscriptionId": res.TerraformId(),
},
})
if err != nil {
logrus.Error(err)
return nil, err
}
deserializedRes, err := r.deserializer.DeserializeOne(aws.AwsSnsTopicSubscriptionResourceType, *ctyVal)
if err != nil {
return nil, err
}
return deserializedRes, nil
}

View File

@ -0,0 +1,85 @@
package aws
import (
"fmt"
awssdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/cloudskiff/driftctl/pkg/alerter"
"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 wrongArnTopicAlert struct {
arn string
endpoint *string
}
func NewWrongArnTopicAlert(arn string, endpoint *string) *wrongArnTopicAlert {
return &wrongArnTopicAlert{arn: arn, endpoint: endpoint}
}
func (p *wrongArnTopicAlert) Message() string {
return fmt.Sprintf("%s with incorrect subscription arn (%s) for endpoint \"%s\" will be ignored",
aws.AwsSnsTopicSubscriptionResourceType,
p.arn,
awssdk.StringValue(p.endpoint))
}
func (p *wrongArnTopicAlert) ShouldIgnoreResource() bool {
return false
}
type SNSTopicSubscriptionEnumerator struct {
repository repository.SNSRepository
factory resource.ResourceFactory
alerter alerter.AlerterInterface
}
func NewSNSTopicSubscriptionEnumerator(
repo repository.SNSRepository,
factory resource.ResourceFactory,
alerter alerter.AlerterInterface,
) *SNSTopicSubscriptionEnumerator {
return &SNSTopicSubscriptionEnumerator{
repo,
factory,
alerter,
}
}
func (e *SNSTopicSubscriptionEnumerator) SupportedType() resource.ResourceType {
return aws.AwsSnsTopicSubscriptionResourceType
}
func (e *SNSTopicSubscriptionEnumerator) Enumerate() ([]resource.Resource, error) {
allSubscriptions, err := e.repository.ListAllSubscriptions()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(e.SupportedType()))
}
results := make([]resource.Resource, len(allSubscriptions))
for _, subscription := range allSubscriptions {
if subscription.SubscriptionArn == nil || !arn.IsARN(*subscription.SubscriptionArn) {
e.alerter.SendAlert(
fmt.Sprintf("%s.%s", e.SupportedType(), *subscription.SubscriptionArn),
NewWrongArnTopicAlert(*subscription.SubscriptionArn, subscription.Endpoint),
)
continue
}
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
*subscription.SubscriptionArn,
map[string]interface{}{},
),
)
}
return results, nil
}

View File

@ -1,97 +0,0 @@
package aws
import (
"fmt"
awssdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
"github.com/cloudskiff/driftctl/pkg/alerter"
"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"
"github.com/cloudskiff/driftctl/pkg/terraform"
)
type wrongArnTopicAlert struct {
arn string
endpoint *string
}
func (p *wrongArnTopicAlert) Message() string {
return fmt.Sprintf("%s with incorrect subscription arn (%s) for endpoint \"%s\" will be ignored",
aws.AwsSnsTopicSubscriptionResourceType,
p.arn,
awssdk.StringValue(p.endpoint))
}
func (p *wrongArnTopicAlert) ShouldIgnoreResource() bool {
return false
}
type SNSTopicSubscriptionSupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.SNSRepository
runner *terraform.ParallelResourceReader
alerter alerter.AlerterInterface
}
func NewSNSTopicSubscriptionSupplier(provider *AWSTerraformProvider, a alerter.AlerterInterface, deserializer *resource.Deserializer, repository repository.SNSRepository) *SNSTopicSubscriptionSupplier {
return &SNSTopicSubscriptionSupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
a,
}
}
func (s *SNSTopicSubscriptionSupplier) Resources() ([]resource.Resource, error) {
subscriptions, err := s.repository.ListAllSubscriptions()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, aws.AwsSnsTopicSubscriptionResourceType)
}
for _, subscription := range subscriptions {
subscription := subscription
s.runner.Run(func() (cty.Value, error) {
return s.readTopicSubscription(subscription, s.alerter)
})
}
retrieve, err := s.runner.Wait()
if err != nil {
return nil, err
}
return s.deserializer.Deserialize(aws.AwsSnsTopicSubscriptionResourceType, retrieve)
}
func (s *SNSTopicSubscriptionSupplier) readTopicSubscription(subscription *sns.Subscription, alertr alerter.AlerterInterface) (cty.Value, error) {
if subscription.SubscriptionArn != nil && !arn.IsARN(*subscription.SubscriptionArn) {
alertr.SendAlert(
fmt.Sprintf("%s.%s", aws.AwsSnsTopicSubscriptionResourceType, *subscription.SubscriptionArn),
&wrongArnTopicAlert{*subscription.SubscriptionArn, subscription.Endpoint},
)
return cty.NilVal, nil
}
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: *subscription.SubscriptionArn,
Ty: aws.AwsSnsTopicSubscriptionResourceType,
Attributes: map[string]string{
"SubscriptionId": *subscription.SubscriptionArn,
},
})
if err != nil {
logrus.Error(err)
return cty.NilVal, err
}
return *val, nil
}

View File

@ -1,133 +0,0 @@
package aws
import (
"context"
"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"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/cloudskiff/driftctl/pkg/alerter"
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 TestSNSTopicSubscriptionSupplier_Resources(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *repository.MockSNSRepository)
alerts alerter.Alerts
err error
}{
{
test: "no SNS Topic Subscription",
dirName: "sns_topic_subscription_empty",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return([]*sns.Subscription{}, nil)
},
err: nil,
},
{
test: "Multiple SNSTopic Subscription",
dirName: "sns_topic_subscription_multiple",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return([]*sns.Subscription{
{SubscriptionArn: aws.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic2:c0f794c5-a009-4db4-9147-4c55959787fa")},
{SubscriptionArn: aws.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic:b6e66147-2b31-4486-8d4b-2a2272264c8e")},
}, nil)
},
err: nil,
},
{
test: "Multiple SNSTopic Subscription with one pending and one incorrect",
dirName: "sns_topic_subscription_multiple",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return([]*sns.Subscription{
{SubscriptionArn: aws.String("PendingConfirmation"), Endpoint: aws.String("TEST")},
{SubscriptionArn: aws.String("Incorrect"), Endpoint: aws.String("INCORRECT")},
{SubscriptionArn: aws.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic2:c0f794c5-a009-4db4-9147-4c55959787fa")},
{SubscriptionArn: aws.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic:b6e66147-2b31-4486-8d4b-2a2272264c8e")},
}, nil)
},
alerts: map[string][]alerter.Alert{
"aws_sns_topic_subscription.PendingConfirmation": []alerter.Alert{
&wrongArnTopicAlert{"PendingConfirmation", aws.String("TEST")},
},
"aws_sns_topic_subscription.Incorrect": []alerter.Alert{
&wrongArnTopicAlert{"Incorrect", aws.String("INCORRECT")},
},
},
err: nil,
},
{
test: "cannot list SNSTopic subscription",
dirName: "sns_topic_subscription_list",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsSnsTopicSubscriptionResourceType),
},
}
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 {
a := alerter.NewAlerter()
provider, err := InitTestAwsProvider(providerLibrary)
if err != nil {
t.Fatal(err)
}
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider, a, deserializer, repository.NewSNSRepository(provider.session, cache.New(0))))
}
t.Run(c.test, func(tt *testing.T) {
a := alerter.NewAlerter()
fakeClient := repository.MockSNSRepository{}
c.mocks(&fakeClient)
provider := mocks2.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
s := &SNSTopicSubscriptionSupplier{
provider,
deserializer,
&fakeClient,
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
a,
}
got, err := s.Resources()
assert.Equal(tt, c.err, err)
if c.alerts == nil {
c.alerts = map[string][]alerter.Alert{}
}
assert.Equal(tt, c.alerts, a.Retrieve())
mock.AssertExpectationsForObjects(tt)
test.CtyTestDiff(got, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}

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

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,112 @@
package remote
import (
"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/aws/aws-sdk-go/service/cloudfront"
"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 TestCloudfrontDistribution(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(repository *repository.MockCloudfrontRepository)
wantErr error
}{
{
test: "no cloudfront distributions",
dirName: "aws_cloudfront_distribution_empty",
mocks: func(repository *repository.MockCloudfrontRepository) {
repository.On("ListAllDistributions").Return([]*cloudfront.DistributionSummary{}, nil)
},
},
{
test: "single cloudfront distribution",
dirName: "aws_cloudfront_distribution_single",
mocks: func(repository *repository.MockCloudfrontRepository) {
repository.On("ListAllDistributions").Return([]*cloudfront.DistributionSummary{
{Id: awssdk.String("E1M9CNS0XSHI19")},
}, nil)
},
},
{
test: "cannot list cloudfront distributions",
dirName: "aws_cloudfront_distribution_list",
mocks: func(repository *repository.MockCloudfrontRepository) {
repository.On("ListAllDistributions").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
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.MockCloudfrontRepository{}
c.mocks(fakeRepo)
var repo repository.CloudfrontRepository = 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.NewCloudfrontRepository(sess, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewCloudfrontDistributionEnumerator(repo, factory))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsCloudfrontDistributionResourceType, common.NewGenericDetailsFetcher(resourceaws.AwsCloudfrontDistributionResourceType, provider, deserializer))
s := NewScanner(nil, remoteLibrary, alerter, scanOptions)
got, err := s.Resources()
assert.Equal(tt, err, c.wantErr)
if err != nil {
return
}
test.TestAgainstGoldenFile(got, resourceaws.AwsCloudfrontDistributionResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}

View File

@ -8,6 +8,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/cloudskiff/driftctl/mocks"
"github.com/cloudskiff/driftctl/pkg/alerter"
"github.com/cloudskiff/driftctl/pkg/remote/aws"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
"github.com/cloudskiff/driftctl/pkg/remote/common"
@ -118,3 +119,217 @@ func TestScanSNSTopic(t *testing.T) {
})
}
}
func TestSNSTopicPolicyScan(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *repository.MockSNSRepository)
err error
}{
{
test: "no SNS Topic policy",
dirName: "sns_topic_policy_empty",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllTopics").Return([]*sns.Topic{}, nil)
},
err: nil,
},
{
test: "Multiple SNSTopicPolicy",
dirName: "sns_topic_policy_multiple",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllTopics").Return([]*sns.Topic{
{TopicArn: awssdk.String("arn:aws:sns:us-east-1:526954929923:my-topic-with-policy")},
{TopicArn: awssdk.String("arn:aws:sns:us-east-1:526954929923:my-topic-with-policy2")},
}, nil)
},
err: nil,
},
{
test: "cannot list SNSTopic",
dirName: "sns_topic_policy_topic_list",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllTopics").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
err: nil,
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
for _, c := range cases {
t.Run(c.test, func(tt *testing.T) {
shouldUpdate := c.dirName == *goldenfile.Update
session := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
alerter := &mocks.AlerterInterface{}
alerter.On("SendAlert", mock.Anything, mock.Anything).Maybe().Return()
scanOptions := ScannerOptions{Deep: true}
providerLibrary := terraform.NewProviderLibrary()
remoteLibrary := common.NewRemoteLibrary()
// Initialize mocks
fakeRepo := &repository.MockSNSRepository{}
c.mocks(fakeRepo)
var repo repository.SNSRepository = 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.NewSNSRepository(session, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewSNSTopicPolicyEnumerator(repo, factory))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsSnsTopicPolicyResourceType, aws.NewSNSTopicPolicyDetailsFetcher(provider, deserializer))
s := NewScanner(nil, remoteLibrary, alerter, scanOptions)
got, err := s.Resources()
assert.Equal(tt, c.err, err)
if err != nil {
return
}
test.TestAgainstGoldenFile(got, resourceaws.AwsSnsTopicPolicyResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}
func TestSNSTopicSubscriptionScan(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *repository.MockSNSRepository)
alerts alerter.Alerts
err error
}{
{
test: "no SNS Topic Subscription",
dirName: "sns_topic_subscription_empty",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return([]*sns.Subscription{}, nil)
},
alerts: map[string][]alerter.Alert{},
err: nil,
},
{
test: "Multiple SNSTopic Subscription",
dirName: "sns_topic_subscription_multiple",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return([]*sns.Subscription{
{SubscriptionArn: awssdk.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic2:c0f794c5-a009-4db4-9147-4c55959787fa")},
{SubscriptionArn: awssdk.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic:b6e66147-2b31-4486-8d4b-2a2272264c8e")},
}, nil)
},
alerts: map[string][]alerter.Alert{},
err: nil,
},
{
test: "Multiple SNSTopic Subscription with one pending and one incorrect",
dirName: "sns_topic_subscription_multiple",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return([]*sns.Subscription{
{SubscriptionArn: awssdk.String("PendingConfirmation"), Endpoint: awssdk.String("TEST")},
{SubscriptionArn: awssdk.String("Incorrect"), Endpoint: awssdk.String("INCORRECT")},
{SubscriptionArn: awssdk.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic2:c0f794c5-a009-4db4-9147-4c55959787fa")},
{SubscriptionArn: awssdk.String("arn:aws:sns:us-east-1:526954929923:user-updates-topic:b6e66147-2b31-4486-8d4b-2a2272264c8e")},
}, nil)
},
alerts: map[string][]alerter.Alert{
"aws_sns_topic_subscription.PendingConfirmation": []alerter.Alert{
aws.NewWrongArnTopicAlert("PendingConfirmation", awssdk.String("TEST")),
},
"aws_sns_topic_subscription.Incorrect": []alerter.Alert{
aws.NewWrongArnTopicAlert("Incorrect", awssdk.String("INCORRECT")),
},
},
err: nil,
},
{
test: "cannot list SNSTopic subscription",
dirName: "sns_topic_subscription_list",
mocks: func(client *repository.MockSNSRepository) {
client.On("ListAllSubscriptions").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
alerts: map[string][]alerter.Alert{
resourceaws.AwsSnsTopicSubscriptionResourceType: {
NewEnumerationAccessDeniedAlert("aws+tf", resourceaws.AwsSnsTopicSubscriptionResourceType, resourceaws.AwsSnsTopicSubscriptionResourceType),
},
},
err: nil,
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
for _, c := range cases {
t.Run(c.test, func(tt *testing.T) {
shouldUpdate := c.dirName == *goldenfile.Update
session := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
scanOptions := ScannerOptions{Deep: true}
providerLibrary := terraform.NewProviderLibrary()
remoteLibrary := common.NewRemoteLibrary()
// Initialize mocks
alerter := alerter.NewAlerter()
fakeRepo := &repository.MockSNSRepository{}
c.mocks(fakeRepo)
var repo repository.SNSRepository = 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.NewSNSRepository(session, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewSNSTopicSubscriptionEnumerator(repo, factory, alerter))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsSnsTopicSubscriptionResourceType, aws.NewSNSTopicSubscriptionDetailsFetcher(provider, deserializer))
s := NewScanner(nil, remoteLibrary, alerter, scanOptions)
got, err := s.Resources()
assert.Equal(tt, err, c.err)
if err != nil {
return
}
assert.Equal(tt, c.alerts, alerter.Retrieve())
test.TestAgainstGoldenFile(got, resourceaws.AwsSnsTopicSubscriptionResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}

View File

@ -0,0 +1 @@
[]

View File

@ -28,13 +28,13 @@ func (p *FakeTerraformProvider) ShouldUpdate() {
p.shouldUpdate = true
}
func (m *FakeTerraformProvider) Schema() map[string]providers.Schema {
if m.shouldUpdate {
schema := m.realProvider.Schema()
m.writeSchema(schema)
func (p *FakeTerraformProvider) Schema() map[string]providers.Schema {
if p.shouldUpdate {
schema := p.realProvider.Schema()
p.writeSchema(schema)
return schema
}
return m.readSchema()
return p.readSchema()
}
func (p *FakeTerraformProvider) WithResponse(response string) *FakeTerraformProvider {