Merge pull request #345 from cloudskiff/fix/sns_sub_pending

when sns subscription is pending prevent crash and show an alert
main
Elie 2021-03-17 18:08:14 +01:00 committed by GitHub
commit c24ce3cfe8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 7 deletions

View File

@ -68,7 +68,7 @@ func Init(alerter *alerter.Alerter, providerLibrary *terraform.ProviderLibrary,
supplierLibrary.AddSupplier(NewSqsQueuePolicySupplier(provider))
supplierLibrary.AddSupplier(NewSNSTopicSupplier(provider))
supplierLibrary.AddSupplier(NewSNSTopicPolicySupplier(provider))
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider))
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider, alerter))
supplierLibrary.AddSupplier(NewDynamoDBTableSupplier(provider))
supplierLibrary.AddSupplier(NewRoute53HealthCheckSupplier(provider))
supplierLibrary.AddSupplier(NewCloudfrontDistributionSupplier(provider))

View File

@ -1,12 +1,17 @@
package aws
import (
"fmt"
awssdk "github.com/aws/aws-sdk-go/aws"
"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/alerter"
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
@ -14,19 +19,35 @@ import (
"github.com/cloudskiff/driftctl/pkg/terraform"
)
type pendingTopicAlert struct {
endpoint *string
}
func (p *pendingTopicAlert) Message() string {
return fmt.Sprintf("%s with pending confirmation status for endpoint \"%s\" will be ignored",
aws.AwsSnsTopicSubscriptionResourceType,
awssdk.StringValue(p.endpoint))
}
func (p *pendingTopicAlert) ShouldIgnoreResource() bool {
return false
}
type SNSTopicSubscriptionSupplier struct {
reader terraform.ResourceReader
deserializer deserializer.CTYDeserializer
client repository.SNSRepository
runner *terraform.ParallelResourceReader
alerter alerter.AlerterInterface
}
func NewSNSTopicSubscriptionSupplier(provider *AWSTerraformProvider) *SNSTopicSubscriptionSupplier {
func NewSNSTopicSubscriptionSupplier(provider *AWSTerraformProvider, a alerter.AlerterInterface) *SNSTopicSubscriptionSupplier {
return &SNSTopicSubscriptionSupplier{
provider,
awsdeserializer.NewSNSTopicSubscriptionDeserializer(),
repository.NewSNSClient(provider.session),
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
a,
}
}
@ -38,7 +59,7 @@ func (s *SNSTopicSubscriptionSupplier) Resources() ([]resource.Resource, error)
for _, subscription := range subscriptions {
subscription := subscription
s.runner.Run(func() (cty.Value, error) {
return s.readTopicSubscription(subscription)
return s.readTopicSubscription(subscription, s.alerter)
})
}
@ -50,7 +71,15 @@ func (s *SNSTopicSubscriptionSupplier) Resources() ([]resource.Resource, error)
return s.deserializer.Deserialize(retrieve)
}
func (s *SNSTopicSubscriptionSupplier) readTopicSubscription(subscription *sns.Subscription) (cty.Value, error) {
func (s *SNSTopicSubscriptionSupplier) readTopicSubscription(subscription *sns.Subscription, alertr alerter.AlerterInterface) (cty.Value, error) {
if subscription.SubscriptionArn != nil && *subscription.SubscriptionArn == "PendingConfirmation" {
alertr.SendAlert(
fmt.Sprintf("%s.%s", aws.AwsSnsTopicSubscriptionResourceType, *subscription.SubscriptionArn),
&pendingTopicAlert{subscription.Endpoint},
)
return cty.NilVal, nil
}
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: *subscription.SubscriptionArn,
Ty: aws.AwsSnsTopicSubscriptionResourceType,

View File

@ -8,6 +8,7 @@ import (
"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"
@ -35,6 +36,7 @@ func TestSNSTopicSubscriptionSupplier_Resources(t *testing.T) {
test string
dirName string
mocks func(client *mocks.SNSRepository)
alerts alerter.Alerts
err error
}{
{
@ -56,6 +58,23 @@ func TestSNSTopicSubscriptionSupplier_Resources(t *testing.T) {
},
err: nil,
},
{
test: "Multiple SNSTopic Subscription with one pending",
dirName: "sns_topic_subscription_multiple",
mocks: func(client *mocks.SNSRepository) {
client.On("ListAllSubscriptions").Return([]*sns.Subscription{
{SubscriptionArn: aws.String("PendingConfirmation"), Endpoint: aws.String("TEST")},
{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{
&pendingTopicAlert{aws.String("TEST")},
},
},
err: nil,
},
{
test: "cannot list SNSTopic subscription",
dirName: "sns_topic_subscription_list",
@ -72,14 +91,16 @@ func TestSNSTopicSubscriptionSupplier_Resources(t *testing.T) {
supplierLibrary := resource.NewSupplierLibrary()
if shouldUpdate {
a := alerter.NewAlerter()
provider, err := InitTestAwsProvider(providerLibrary)
if err != nil {
t.Fatal(err)
}
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider))
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider, a))
}
t.Run(c.test, func(tt *testing.T) {
a := alerter.NewAlerter()
fakeClient := mocks.SNSRepository{}
c.mocks(&fakeClient)
provider := mocks2.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
@ -89,10 +110,15 @@ func TestSNSTopicSubscriptionSupplier_Resources(t *testing.T) {
topicSubscriptionDeserializer,
&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, topicSubscriptionDeserializer, shouldUpdate, tt)
})

View File

@ -23,6 +23,7 @@ func (s SNSTopicSubscriptionDeserializer) Deserialize(subscriptionsList []cty.Va
subscriptions := make([]resource.Resource, 0)
for _, value := range subscriptionsList {
value := value
subscription, err := decodeSNSTopicSubscription(value)
if err != nil {