Handle invalid route crash in middlewares

main
Elie 2021-02-03 16:24:55 +01:00
parent 44e9ba3d31
commit a8f0300405
No known key found for this signature in database
GPG Key ID: 399AF69092C727B6
7 changed files with 144 additions and 13 deletions

18
mocks/AlerterInterface.go Normal file
View File

@ -0,0 +1,18 @@
// Code generated by mockery v2.3.0. DO NOT EDIT.
package mocks
import (
alerter "github.com/cloudskiff/driftctl/pkg/alerter"
mock "github.com/stretchr/testify/mock"
)
// AlerterInterface is an autogenerated mock type for the AlerterInterface type
type AlerterInterface struct {
mock.Mock
}
// SendAlert provides a mock function with given fields: key, alert
func (_m *AlerterInterface) SendAlert(key string, alert alerter.Alert) {
_m.Called(key, alert)
}

View File

@ -6,6 +6,10 @@ import (
"github.com/cloudskiff/driftctl/pkg/resource"
)
type AlerterInterface interface {
SendAlert(key string, alert Alert)
}
type Alerter struct {
alerts Alerts
alertsCh chan Alerts

View File

@ -15,12 +15,13 @@ import (
type DriftCTL struct {
remoteSupplier resource.Supplier
iacSupplier resource.Supplier
alerter *alerter.Alerter
analyzer analyser.Analyzer
filter *jmespath.JMESPath
}
func NewDriftCTL(remoteSupplier resource.Supplier, iacSupplier resource.Supplier, filter *jmespath.JMESPath, alerter *alerter.Alerter) *DriftCTL {
return &DriftCTL{remoteSupplier, iacSupplier, analyser.NewAnalyzer(alerter), filter}
return &DriftCTL{remoteSupplier, iacSupplier, alerter, analyser.NewAnalyzer(alerter), filter}
}
func (d DriftCTL) Run() *analyser.Analysis {
@ -42,7 +43,7 @@ func (d DriftCTL) Run() *analyser.Analysis {
middlewares.NewAwsDefaultInternetGateway(),
middlewares.NewAwsDefaultVPC(),
middlewares.NewAwsDefaultSubnet(),
middlewares.NewAwsRouteTableExpander(),
middlewares.NewAwsRouteTableExpander(d.alerter),
middlewares.NewAwsDefaultRouteTable(),
middlewares.NewAwsDefaultRoute(),
middlewares.NewAwsNatGatewayEipAssoc(),

View File

@ -1,17 +1,24 @@
package middlewares
import (
"fmt"
awssdk "github.com/aws/aws-sdk-go/aws"
"github.com/cloudskiff/driftctl/pkg/alerter"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
)
// Explodes routes found in aws_default_route_table.route and aws_route_table.route to dedicated resources
type AwsRouteTableExpander struct{}
type AwsRouteTableExpander struct {
alerter alerter.AlerterInterface
}
func NewAwsRouteTableExpander() AwsRouteTableExpander {
return AwsRouteTableExpander{}
func NewAwsRouteTableExpander(alerter alerter.AlerterInterface) AwsRouteTableExpander {
return AwsRouteTableExpander{
alerter,
}
}
func (m AwsRouteTableExpander) Execute(remoteResources, resourcesFromState *[]resource.Resource) error {
@ -51,13 +58,20 @@ func (m *AwsRouteTableExpander) handleTable(table *aws.AwsRouteTable, results *[
return nil
}
for _, route := range *table.Route {
routeId, err := aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock)
if err != nil {
m.alerter.SendAlert(aws.AwsRouteTableResourceType, alerter.Alert{
Message: fmt.Sprintf("Skipped invalid route found in state for %s.%s", aws.AwsRouteTableResourceType, table.Id),
})
continue
}
newRouteFromTable := &aws.AwsRoute{
DestinationCidrBlock: route.CidrBlock,
DestinationIpv6CidrBlock: route.Ipv6CidrBlock,
DestinationPrefixListId: awssdk.String(""),
EgressOnlyGatewayId: route.EgressOnlyGatewayId,
GatewayId: route.GatewayId,
Id: aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock),
Id: routeId,
InstanceId: route.InstanceId,
InstanceOwnerId: awssdk.String(""),
LocalGatewayId: route.LocalGatewayId,
@ -91,13 +105,20 @@ func (m *AwsRouteTableExpander) handleDefaultTable(table *aws.AwsDefaultRouteTab
return nil
}
for _, route := range *table.Route {
routeId, err := aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock)
if err != nil {
m.alerter.SendAlert(aws.AwsDefaultRouteTableResourceType, alerter.Alert{
Message: fmt.Sprintf("Skipped invalid route found in state for %s.%s", aws.AwsDefaultRouteTableResourceType, table.Id),
})
continue
}
newRouteFromTable := &aws.AwsRoute{
DestinationCidrBlock: route.CidrBlock,
DestinationIpv6CidrBlock: route.Ipv6CidrBlock,
DestinationPrefixListId: awssdk.String(""),
EgressOnlyGatewayId: route.EgressOnlyGatewayId,
GatewayId: route.GatewayId,
Id: aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock),
Id: routeId,
InstanceId: route.InstanceId,
InstanceOwnerId: awssdk.String(""),
NatGatewayId: route.NatGatewayId,

View File

@ -6,6 +6,8 @@ import (
awssdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/cloudskiff/driftctl/mocks"
"github.com/cloudskiff/driftctl/pkg/alerter"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
resource2 "github.com/cloudskiff/driftctl/test/resource"
@ -189,7 +191,8 @@ func TestAwsRouteTableExpander_Execute(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewAwsRouteTableExpander()
mockedAlerter := &mocks.AlerterInterface{}
m := NewAwsRouteTableExpander(mockedAlerter)
err := m.Execute(nil, &tt.input)
if err != nil {
t.Fatal(err)
@ -208,3 +211,85 @@ func TestAwsRouteTableExpander_Execute(t *testing.T) {
})
}
}
func TestAwsRouteTableExpander_ExecuteWithInvalidRoutes(t *testing.T) {
mockedAlerter := &mocks.AlerterInterface{}
mockedAlerter.On("SendAlert", aws.AwsRouteTableResourceType, alerter.Alert{
Message: "Skipped invalid route found in state for aws_route_table.table_from_state",
})
mockedAlerter.On("SendAlert", aws.AwsDefaultRouteTableResourceType, alerter.Alert{
Message: "Skipped invalid route found in state for aws_default_route_table.default_table_from_state",
})
input := []resource.Resource{
&aws.AwsRouteTable{
Id: "table_from_state",
Route: &[]struct {
CidrBlock *string `cty:"cidr_block"`
EgressOnlyGatewayId *string `cty:"egress_only_gateway_id"`
GatewayId *string `cty:"gateway_id"`
InstanceId *string `cty:"instance_id"`
Ipv6CidrBlock *string `cty:"ipv6_cidr_block"`
LocalGatewayId *string `cty:"local_gateway_id"`
NatGatewayId *string `cty:"nat_gateway_id"`
NetworkInterfaceId *string `cty:"network_interface_id"`
TransitGatewayId *string `cty:"transit_gateway_id"`
VpcEndpointId *string `cty:"vpc_endpoint_id"`
VpcPeeringConnectionId *string `cty:"vpc_peering_connection_id"`
}{
{
GatewayId: awssdk.String("igw-07b7844a8fd17a638"),
},
},
},
&aws.AwsDefaultRouteTable{
Id: "default_table_from_state",
Route: &[]struct {
CidrBlock *string `cty:"cidr_block"`
EgressOnlyGatewayId *string `cty:"egress_only_gateway_id"`
GatewayId *string `cty:"gateway_id"`
InstanceId *string `cty:"instance_id"`
Ipv6CidrBlock *string `cty:"ipv6_cidr_block"`
NatGatewayId *string `cty:"nat_gateway_id"`
NetworkInterfaceId *string `cty:"network_interface_id"`
TransitGatewayId *string `cty:"transit_gateway_id"`
VpcEndpointId *string `cty:"vpc_endpoint_id"`
VpcPeeringConnectionId *string `cty:"vpc_peering_connection_id"`
}{
{
GatewayId: awssdk.String("igw-07b7844a8fd17a638"),
},
},
},
}
expected := []resource.Resource{
&aws.AwsRouteTable{
Id: "table_from_state",
Route: nil,
},
&aws.AwsDefaultRouteTable{
Id: "default_table_from_state",
Route: nil,
},
}
m := NewAwsRouteTableExpander(mockedAlerter)
err := m.Execute(nil, &input)
if err != nil {
t.Fatal(err)
}
changelog, err := diff.Diff(expected, input)
if err != nil {
t.Fatal(err)
}
if len(changelog) > 0 {
for _, change := range changelog {
t.Errorf("%s got = %v, want %v", strings.Join(change.Path, "."), awsutil.Prettify(change.From), awsutil.Prettify(change.To))
}
}
mockedAlerter.AssertExpectations(t)
}

View File

@ -73,8 +73,10 @@ func (s RouteSupplier) readRoute(tableId string, route ec2.Route) (cty.Value, er
attributes["destination_ipv6_cidr_block"] = *route.DestinationIpv6CidrBlock
}
// We can ignore error there as remote will always return us a valid route
routeId, _ := aws.CalculateRouteID(&tableId, route.DestinationCidrBlock, route.DestinationIpv6CidrBlock)
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: aws.CalculateRouteID(&tableId, route.DestinationCidrBlock, route.DestinationIpv6CidrBlock),
ID: routeId,
Ty: Ty,
Attributes: flatmap.Flatten(attributes),
})

View File

@ -19,16 +19,16 @@ func (r *AwsRoute) String() string {
return output
}
func CalculateRouteID(tableId, CidrBlock, Ipv6CidrBlock *string) string {
func CalculateRouteID(tableId, CidrBlock, Ipv6CidrBlock *string) (string, error) {
if CidrBlock != nil && *CidrBlock != "" {
return fmt.Sprintf("r-%s%d", *tableId, hashcode.String(*CidrBlock))
return fmt.Sprintf("r-%s%d", *tableId, hashcode.String(*CidrBlock)), nil
}
if Ipv6CidrBlock != nil && *Ipv6CidrBlock != "" {
return fmt.Sprintf("r-%s%d", *tableId, hashcode.String(*Ipv6CidrBlock))
return fmt.Sprintf("r-%s%d", *tableId, hashcode.String(*Ipv6CidrBlock)), nil
}
panic("unable to build route ID")
return "", fmt.Errorf("invalid route detected for table %s", *tableId)
}
func (r *AwsRoute) NormalizeForState() (resource.Resource, error) {