fix: import managed api mappings in the state
parent
09f06be917
commit
f27d3b96ee
|
@ -123,6 +123,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) {
|
|||
middlewares.NewAwsApiGatewayRestApiPolicyExpander(d.resourceFactory),
|
||||
middlewares.NewAwsConsoleApiGatewayGatewayResponse(),
|
||||
middlewares.NewAwsApiGatewayDomainNamesReconciler(),
|
||||
middlewares.NewAwsApiGatewayBasePathMappingReconciler(),
|
||||
middlewares.NewAwsEbsEncryptionByDefaultReconciler(d.resourceFactory),
|
||||
middlewares.NewAwsALBTransformer(d.resourceFactory),
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/snyk/driftctl/pkg/resource"
|
||||
"github.com/snyk/driftctl/pkg/resource/aws"
|
||||
)
|
||||
|
||||
// AwsApiGatewayBasePathMappingReconciler is used to reconcile API Gateway base path mapping (v1 and v2)
|
||||
// from both remote and state resources because v1|v2 AWS SDK list endpoints return all mappings
|
||||
// without distinction.
|
||||
type AwsApiGatewayBasePathMappingReconciler struct{}
|
||||
|
||||
func NewAwsApiGatewayBasePathMappingReconciler() AwsApiGatewayBasePathMappingReconciler {
|
||||
return AwsApiGatewayBasePathMappingReconciler{}
|
||||
}
|
||||
|
||||
func (m AwsApiGatewayBasePathMappingReconciler) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error {
|
||||
newRemoteResources := make([]*resource.Resource, 0)
|
||||
managedApiMapping := make([]*resource.Resource, 0)
|
||||
unmanagedApiMapping := make([]*resource.Resource, 0)
|
||||
for _, res := range *remoteResources {
|
||||
// Ignore all resources other than aws_api_gateway_base_path_mapping and aws_apigatewayv2_api_mapping
|
||||
if res.ResourceType() != aws.AwsApiGatewayBasePathMappingResourceType &&
|
||||
res.ResourceType() != aws.AwsApiGatewayV2MappingResourceType {
|
||||
newRemoteResources = append(newRemoteResources, res)
|
||||
continue
|
||||
}
|
||||
|
||||
// Find a matching state resources
|
||||
existInState := false
|
||||
for _, stateResource := range *resourcesFromState {
|
||||
if res.Equal(stateResource) {
|
||||
existInState = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of the resource if it's managed in IaC
|
||||
if existInState {
|
||||
managedApiMapping = append(managedApiMapping, res)
|
||||
continue
|
||||
}
|
||||
|
||||
// If we're here, it means that we are left with unmanaged path mappings
|
||||
// in both v1 and v2 format. Let's group real and duplicate path mappings
|
||||
// in a slice
|
||||
unmanagedApiMapping = append(unmanagedApiMapping, res)
|
||||
}
|
||||
|
||||
// We only want to show to our end users unmanaged v1 path mappings
|
||||
// To do that, we're going to loop over unmanaged path mappings to delete duplicates
|
||||
// and leave after that only v1 path mappings (e.g. remove v2 ones)
|
||||
deduplicatedUnmanagedMappings := make([]*resource.Resource, 0, len(unmanagedApiMapping))
|
||||
for _, unmanaged := range unmanagedApiMapping {
|
||||
// Remove duplicates (e.g. same id, the opposite type)
|
||||
isDuplicate := false
|
||||
for _, managed := range managedApiMapping {
|
||||
if managed.ResourceId() == unmanaged.ResourceId() {
|
||||
isDuplicate = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isDuplicate {
|
||||
continue
|
||||
}
|
||||
|
||||
// Now keep only v1 path mappings
|
||||
if unmanaged.ResourceType() == aws.AwsApiGatewayBasePathMappingResourceType {
|
||||
deduplicatedUnmanagedMappings = append(deduplicatedUnmanagedMappings, unmanaged)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, add both managed and unmanaged resources to remote resources
|
||||
newRemoteResources = append(newRemoteResources, managedApiMapping...)
|
||||
newRemoteResources = append(newRemoteResources, deduplicatedUnmanagedMappings...)
|
||||
|
||||
*remoteResources = newRemoteResources
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/r3labs/diff/v2"
|
||||
"github.com/snyk/driftctl/pkg/resource"
|
||||
"github.com/snyk/driftctl/pkg/resource/aws"
|
||||
)
|
||||
|
||||
func TestAwsApiGatewayBasePathMappingReconciler_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourcesFromState []*resource.Resource
|
||||
remoteResources []*resource.Resource
|
||||
expected []*resource.Resource
|
||||
}{
|
||||
{
|
||||
name: "with managed resources",
|
||||
resourcesFromState: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
},
|
||||
remoteResources: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
},
|
||||
expected: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with unmanaged resources",
|
||||
resourcesFromState: []*resource.Resource{},
|
||||
remoteResources: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
},
|
||||
expected: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with deleted resources",
|
||||
resourcesFromState: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
},
|
||||
remoteResources: []*resource.Resource{},
|
||||
expected: []*resource.Resource{},
|
||||
},
|
||||
{
|
||||
name: "with a mix of managed, unmanaged and deleted resources",
|
||||
resourcesFromState: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping4",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
},
|
||||
remoteResources: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping3",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping3",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
},
|
||||
expected: []*resource.Resource{
|
||||
{
|
||||
Id: "mapping1",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping2",
|
||||
Type: aws.AwsApiGatewayV2MappingResourceType,
|
||||
},
|
||||
{
|
||||
Id: "mapping3",
|
||||
Type: aws.AwsApiGatewayBasePathMappingResourceType,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := NewAwsApiGatewayBasePathMappingReconciler()
|
||||
err := m.Execute(&tt.remoteResources, &tt.resourcesFromState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
changelog, err := diff.Diff(tt.expected, tt.remoteResources)
|
||||
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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,2 +1,6 @@
|
|||
*
|
||||
!aws_api_gateway_base_path_mapping
|
||||
|
||||
# We include drifts from aws_apigatewayv2_api_mapping as well to avoid regression regarding this bug:
|
||||
# https://github.com/snyk/driftctl/issues/1442
|
||||
!aws_apigatewayv2_api_mapping
|
||||
|
|
|
@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/aws" {
|
|||
version = "3.19.0"
|
||||
constraints = "3.19.0"
|
||||
hashes = [
|
||||
"h1:+7Vi7p13+cnrxjXbfJiTimGSFR97xCaQwkkvWcreLns=",
|
||||
"h1:xur9tF49NgsovNnmwmBR8RdpN8Fcg1TD4CKQPJD6n1A=",
|
||||
"zh:185a5259153eb9ee4699d4be43b3d509386b473683392034319beee97d470c3b",
|
||||
"zh:2d9a0a01f93e8d16539d835c02b8b6e1927b7685f4076e96cb07f7dd6944bc6c",
|
||||
|
@ -22,6 +23,7 @@ provider "registry.terraform.io/hashicorp/aws" {
|
|||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.1.0"
|
||||
hashes = [
|
||||
"h1:BZMEPucF+pbu9gsPk0G0BHx7YP04+tKdq2MrRDF1EDM=",
|
||||
"h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=",
|
||||
"zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc",
|
||||
"zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626",
|
||||
|
@ -41,6 +43,7 @@ provider "registry.terraform.io/hashicorp/tls" {
|
|||
version = "3.1.0"
|
||||
hashes = [
|
||||
"h1:XTU9f6sGMZHOT8r/+LWCz2BZOPH127FBTPjMMEAAu1U=",
|
||||
"h1:fUJX8Zxx38e2kBln+zWr1Tl41X+OuiE++REjrEyiOM4=",
|
||||
"zh:3d46616b41fea215566f4a957b6d3a1aa43f1f75c26776d72a98bdba79439db6",
|
||||
"zh:623a203817a6dafa86f1b4141b645159e07ec418c82fe40acd4d2a27543cbaa2",
|
||||
"zh:668217e78b210a6572e7b0ecb4134a6781cc4d738f4f5d09eb756085b082592e",
|
||||
|
|
Loading…
Reference in New Issue