Add support for aws_subnet and aws_default_subnet

main
Elie 2021-01-07 17:53:17 +01:00
parent 5da54e7767
commit 06abff67ba
No known key found for this signature in database
GPG Key ID: 399AF69092C727B6
31 changed files with 344280 additions and 1 deletions

View File

@ -51,6 +51,7 @@ As AWS documentation recommends, the below policy is granting only the permissio
"ec2:DescribeVpcAttribute",
"ec2:DescribeVpcClassicLink",
"ec2:DescribeVpcClassicLinkDnsSupport",
"ec2:DescribeSubnets",
"iam:GetPolicy",
"iam:GetPolicyVersion",
"iam:GetRole",
@ -194,6 +195,8 @@ As AWS documentation recommends, the below policy is granting only the permissio
## VPC
- [x] aws_default_subnet
- [x] aws_subnet
- [x] aws_default_vpc
- [x] aws_vpc
- [x] aws_security_group

View File

@ -39,6 +39,7 @@ func (d DriftCTL) Run() *analyser.Analysis {
middlewares.NewIamPolicyAttachmentSanitizer(),
middlewares.AwsInstanceEIP{},
middlewares.NewAwsDefaultVPC(),
middlewares.NewAwsDefaultSubnet(),
)
logrus.Debug("Ready to run middlewares")

View File

@ -38,5 +38,7 @@ func Deserializers() []deserializer.CTYDeserializer {
awsdeserializer.NewVPCSecurityGroupRuleDeserializer(),
awsdeserializer.NewDefaultVPCDeserializer(),
awsdeserializer.NewVPCDeserializer(),
awsdeserializer.NewDefaultSubnetDeserializer(),
awsdeserializer.NewSubnetDeserializer(),
}
}

View File

@ -0,0 +1,53 @@
package middlewares
import (
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
)
// Default subnet should not be shown as unmanaged as they are present by default
// This middleware ignores default subnet from unmanaged resources if they are not managed by IaC
type AwsDefaultSubnet struct{}
func NewAwsDefaultSubnet() AwsDefaultSubnet {
return AwsDefaultSubnet{}
}
func (m AwsDefaultSubnet) Execute(remoteResources, resourcesFromState *[]resource.Resource) error {
newRemoteResources := make([]resource.Resource, 0)
for _, remoteResource := range *remoteResources {
existInState := false
// Ignore all resources other than default Subnet
if remoteResource.TerraformType() != aws.AwsDefaultSubnetResourceType {
newRemoteResources = append(newRemoteResources, remoteResource)
continue
}
for _, stateResource := range *resourcesFromState {
if resource.IsSameResource(remoteResource, stateResource) {
existInState = true
break
}
}
if existInState {
newRemoteResources = append(newRemoteResources, remoteResource)
}
if !existInState {
logrus.WithFields(logrus.Fields{
"id": remoteResource.TerraformId(),
"type": remoteResource.TerraformType(),
}).Debug("Ignoring default Subnet as it is not managed by IaC")
}
}
*remoteResources = newRemoteResources
return nil
}

View File

@ -7,7 +7,7 @@ import (
)
// Default VPC should not be shown as unmanaged as they are present by default
// This middleware ignores default VPC from unmanaged resources of they are not managed IaC
// This middleware ignores default VPC from unmanaged resources if they are not managed by IaC
type AwsDefaultVPC struct{}
func NewAwsDefaultVPC() AwsDefaultVPC {

View File

@ -57,6 +57,7 @@ func Init(alerter *alerter.Alerter) error {
resource.AddSupplier(NewIamRolePolicyAttachmentSupplier(provider.Runner().SubRunner(), iam.New(provider.session)))
resource.AddSupplier(NewVPCSecurityGroupRuleSupplier(provider.Runner().SubRunner(), ec2.New(provider.session)))
resource.AddSupplier(NewVPCSupplier(provider.Runner(), ec2.New(provider.session)))
resource.AddSupplier(NewSubnetSupplier(provider.Runner(), ec2.New(provider.session)))
return nil
}

View File

@ -0,0 +1,115 @@
package aws
import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/cloudskiff/driftctl/pkg"
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
"github.com/zclconf/go-cty/cty"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/sirupsen/logrus"
)
type SubnetSupplier struct {
reader terraform.ResourceReader
defaultSubnetDeserializer deserializer.CTYDeserializer
subnetDeserializer deserializer.CTYDeserializer
client ec2iface.EC2API
defaultSubnetRunner *terraform.ParallelResourceReader
subnetRunner *terraform.ParallelResourceReader
}
func NewSubnetSupplier(runner *pkg.ParallelRunner, client ec2iface.EC2API) *SubnetSupplier {
return &SubnetSupplier{
terraform.Provider(terraform.AWS),
awsdeserializer.NewDefaultSubnetDeserializer(),
awsdeserializer.NewSubnetDeserializer(),
client,
terraform.NewParallelResourceReader(runner.SubRunner()),
terraform.NewParallelResourceReader(runner.SubRunner()),
}
}
func (s SubnetSupplier) Resources() ([]resource.Resource, error) {
input := ec2.DescribeSubnetsInput{}
var subnets []*ec2.Subnet
var defaultSubnets []*ec2.Subnet
err := s.client.DescribeSubnetsPages(&input,
func(resp *ec2.DescribeSubnetsOutput, lastPage bool) bool {
for _, subnet := range resp.Subnets {
if subnet.DefaultForAz != nil && *subnet.DefaultForAz {
defaultSubnets = append(defaultSubnets, subnet)
continue
}
subnets = append(subnets, subnet)
}
return !lastPage
},
)
if err != nil {
logrus.Error(err)
return nil, err
}
for _, item := range subnets {
res := *item
s.subnetRunner.Run(func() (cty.Value, error) {
return s.readSubnet(res)
})
}
for _, item := range defaultSubnets {
res := *item
s.defaultSubnetRunner.Run(func() (cty.Value, error) {
return s.readSubnet(res)
})
}
// Retrieve results from terraform provider
defaultSubnetResources, err := s.defaultSubnetRunner.Wait()
if err != nil {
return nil, err
}
subnetResources, err := s.subnetRunner.Wait()
if err != nil {
return nil, err
}
// Deserialize
deserializedDefaultSubnets, err := s.defaultSubnetDeserializer.Deserialize(defaultSubnetResources)
if err != nil {
return nil, err
}
deserializedSubnets, err := s.subnetDeserializer.Deserialize(subnetResources)
if err != nil {
return nil, err
}
resources := make([]resource.Resource, 0, len(subnetResources)+len(deserializedDefaultSubnets))
resources = append(resources, deserializedDefaultSubnets...)
resources = append(resources, deserializedSubnets...)
return resources, nil
}
func (s SubnetSupplier) readSubnet(subnet ec2.Subnet) (cty.Value, error) {
var Ty resource.ResourceType = aws.AwsSubnetResourceType
if subnet.DefaultForAz != nil && *subnet.DefaultForAz {
Ty = aws.AwsDefaultSubnetResourceType
}
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: *subnet.SubnetId,
Ty: Ty,
})
if err != nil {
logrus.Error(err)
return cty.NilVal, err
}
return *val, nil
}

View File

@ -0,0 +1,127 @@
package aws
import (
"context"
"testing"
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/aws"
"github.com/cloudskiff/driftctl/test/goldenfile"
mocks2 "github.com/cloudskiff/driftctl/test/mocks"
"github.com/stretchr/testify/mock"
"github.com/cloudskiff/driftctl/mocks"
"github.com/cloudskiff/driftctl/pkg"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
)
func TestSubnetSupplier_Resources(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *mocks.FakeEC2)
err error
}{
{
test: "no Subnet",
dirName: "subnet_empty",
mocks: func(client *mocks.FakeEC2) {
client.On("DescribeSubnetsPages",
&ec2.DescribeSubnetsInput{},
mock.MatchedBy(func(callback func(res *ec2.DescribeSubnetsOutput, lastPage bool) bool) bool {
callback(&ec2.DescribeSubnetsOutput{}, true)
return true
})).Return(nil)
},
err: nil,
},
{
test: "mixed default Subnet and Subnet",
dirName: "subnet",
mocks: func(client *mocks.FakeEC2) {
client.On("DescribeSubnetsPages",
&ec2.DescribeSubnetsInput{},
mock.MatchedBy(func(callback func(res *ec2.DescribeSubnetsOutput, lastPage bool) bool) bool {
callback(&ec2.DescribeSubnetsOutput{
Subnets: []*ec2.Subnet{
{
SubnetId: aws.String("subnet-44fe0c65"), // us-east-1a
DefaultForAz: aws.Bool(true),
},
{
SubnetId: aws.String("subnet-65e16628"), // us-east-1b
DefaultForAz: aws.Bool(true),
},
{
SubnetId: aws.String("subnet-afa656f0"), // us-east-1c
DefaultForAz: aws.Bool(true),
},
{
SubnetId: aws.String("subnet-05810d3f933925f6d"), // subnet1
DefaultForAz: aws.Bool(false),
},
},
}, false)
callback(&ec2.DescribeSubnetsOutput{
Subnets: []*ec2.Subnet{
{
SubnetId: aws.String("subnet-0b13f1e0eacf67424"), // subnet2
DefaultForAz: aws.Bool(false),
},
{
SubnetId: aws.String("subnet-0c9b78001fe186e22"), // subnet3
DefaultForAz: aws.Bool(false),
},
},
}, true)
return true
})).Return(nil)
},
err: nil,
},
}
for _, c := range cases {
shouldUpdate := c.dirName == *goldenfile.Update
if shouldUpdate {
provider, err := NewTerraFormProvider()
if err != nil {
t.Fatal(err)
}
terraform.AddProvider(terraform.AWS, provider)
resource.AddSupplier(NewSubnetSupplier(provider.Runner(), ec2.New(provider.session)))
}
t.Run(c.test, func(tt *testing.T) {
fakeEC2 := mocks.FakeEC2{}
c.mocks(&fakeEC2)
provider := mocks2.NewMockedGoldenTFProvider(c.dirName, terraform.Provider(terraform.AWS), shouldUpdate)
SubnetDeserializer := awsdeserializer.NewSubnetDeserializer()
defaultSubnetDeserializer := awsdeserializer.NewDefaultSubnetDeserializer()
s := &SubnetSupplier{
provider,
defaultSubnetDeserializer,
SubnetDeserializer,
&fakeEC2,
terraform.NewParallelResourceReader(pkg.NewParallelRunner(context.TODO(), 10)),
terraform.NewParallelResourceReader(pkg.NewParallelRunner(context.TODO(), 10)),
}
got, err := s.Resources()
if c.err != err {
tt.Errorf("Expected error %+v got %+v", c.err, err)
}
mock.AssertExpectationsForObjects(tt)
deserializers := []deserializer.CTYDeserializer{SubnetDeserializer, defaultSubnetDeserializer}
test.CtyTestDiffMixed(got, c.dirName, provider, deserializers, shouldUpdate, tt)
})
}
}

View File

@ -0,0 +1,20 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "3.19.0"
constraints = "3.19.0"
hashes = [
"h1:+7Vi7p13+cnrxjXbfJiTimGSFR97xCaQwkkvWcreLns=",
"zh:185a5259153eb9ee4699d4be43b3d509386b473683392034319beee97d470c3b",
"zh:2d9a0a01f93e8d16539d835c02b8b6e1927b7685f4076e96cb07f7dd6944bc6c",
"zh:703f6da36b1b5f3497baa38fccaa7765fb8a2b6440344e4c97172516b49437dd",
"zh:770855565462abadbbddd98cb357d2f1a8f30f68a358cb37cbd5c072cb15b377",
"zh:8008db43149fe4345301f81e15e6d9ddb47aa5e7a31648f9b290af96ad86e92a",
"zh:8cdd27d375da6dcb7687f1fed126b7c04efce1671066802ee876dbbc9c66ec79",
"zh:be22ae185005690d1a017c1b909e0d80ab567e239b4f06ecacdba85080667c1c",
"zh:d2d02e72dbd80f607636cd6237a6c862897caabc635c7b50c0cb243d11246723",
"zh:d8f125b66a1eda2555c0f9bbdf12036a5f8d073499a22ca9e4812b68067fea31",
"zh:f5a98024c64d5d2973ff15b093725a074c0cb4afde07ef32c542e69f17ac90bc",
]
}

View File

@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiYXJuIjoic3RyaW5nIiwiYXNzaWduX2lwdjZfYWRkcmVzc19vbl9jcmVhdGlvbiI6ImJvb2wiLCJhdmFpbGFiaWxpdHlfem9uZSI6InN0cmluZyIsImF2YWlsYWJpbGl0eV96b25lX2lkIjoic3RyaW5nIiwiY2lkcl9ibG9jayI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoic3RyaW5nIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOiJib29sIiwib3V0cG9zdF9hcm4iOiJzdHJpbmciLCJvd25lcl9pZCI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInRpbWVvdXRzIjpbIm9iamVjdCIseyJjcmVhdGUiOiJzdHJpbmciLCJkZWxldGUiOiJzdHJpbmcifV0sInZwY19pZCI6InN0cmluZyJ9XQ==",
"Val": "eyJhcm4iOiJhcm46YXdzOmVjMjp1cy1lYXN0LTE6OTI5MzI3MDY1MzMzOnN1Ym5ldC9zdWJuZXQtNDRmZTBjNjUiLCJhc3NpZ25faXB2Nl9hZGRyZXNzX29uX2NyZWF0aW9uIjpmYWxzZSwiYXZhaWxhYmlsaXR5X3pvbmUiOiJ1cy1lYXN0LTFhIiwiYXZhaWxhYmlsaXR5X3pvbmVfaWQiOiJ1c2UxLWF6MiIsImNpZHJfYmxvY2siOiIxNzIuMzEuODAuMC8yMCIsImlkIjoic3VibmV0LTQ0ZmUwYzY1IiwiaXB2Nl9jaWRyX2Jsb2NrIjoiIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoiIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOnRydWUsIm91dHBvc3RfYXJuIjoiIiwib3duZXJfaWQiOiI5MjkzMjcwNjUzMzMiLCJ0YWdzIjp7fSwidGltZW91dHMiOnsiY3JlYXRlIjpudWxsLCJkZWxldGUiOm51bGx9LCJ2cGNfaWQiOiJ2cGMtNDFkMWQxM2IifQ==",
"Err": null
}

View File

@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiYXJuIjoic3RyaW5nIiwiYXNzaWduX2lwdjZfYWRkcmVzc19vbl9jcmVhdGlvbiI6ImJvb2wiLCJhdmFpbGFiaWxpdHlfem9uZSI6InN0cmluZyIsImF2YWlsYWJpbGl0eV96b25lX2lkIjoic3RyaW5nIiwiY2lkcl9ibG9jayI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoic3RyaW5nIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOiJib29sIiwib3V0cG9zdF9hcm4iOiJzdHJpbmciLCJvd25lcl9pZCI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInRpbWVvdXRzIjpbIm9iamVjdCIseyJjcmVhdGUiOiJzdHJpbmciLCJkZWxldGUiOiJzdHJpbmcifV0sInZwY19pZCI6InN0cmluZyJ9XQ==",
"Val": "eyJhcm4iOiJhcm46YXdzOmVjMjp1cy1lYXN0LTE6OTI5MzI3MDY1MzMzOnN1Ym5ldC9zdWJuZXQtNjVlMTY2MjgiLCJhc3NpZ25faXB2Nl9hZGRyZXNzX29uX2NyZWF0aW9uIjpmYWxzZSwiYXZhaWxhYmlsaXR5X3pvbmUiOiJ1cy1lYXN0LTFiIiwiYXZhaWxhYmlsaXR5X3pvbmVfaWQiOiJ1c2UxLWF6NCIsImNpZHJfYmxvY2siOiIxNzIuMzEuMTYuMC8yMCIsImlkIjoic3VibmV0LTY1ZTE2NjI4IiwiaXB2Nl9jaWRyX2Jsb2NrIjoiIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoiIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOnRydWUsIm91dHBvc3RfYXJuIjoiIiwib3duZXJfaWQiOiI5MjkzMjcwNjUzMzMiLCJ0YWdzIjp7fSwidGltZW91dHMiOnsiY3JlYXRlIjpudWxsLCJkZWxldGUiOm51bGx9LCJ2cGNfaWQiOiJ2cGMtNDFkMWQxM2IifQ==",
"Err": null
}

View File

@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiYXJuIjoic3RyaW5nIiwiYXNzaWduX2lwdjZfYWRkcmVzc19vbl9jcmVhdGlvbiI6ImJvb2wiLCJhdmFpbGFiaWxpdHlfem9uZSI6InN0cmluZyIsImF2YWlsYWJpbGl0eV96b25lX2lkIjoic3RyaW5nIiwiY2lkcl9ibG9jayI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoic3RyaW5nIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOiJib29sIiwib3V0cG9zdF9hcm4iOiJzdHJpbmciLCJvd25lcl9pZCI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInRpbWVvdXRzIjpbIm9iamVjdCIseyJjcmVhdGUiOiJzdHJpbmciLCJkZWxldGUiOiJzdHJpbmcifV0sInZwY19pZCI6InN0cmluZyJ9XQ==",
"Val": "eyJhcm4iOiJhcm46YXdzOmVjMjp1cy1lYXN0LTE6OTI5MzI3MDY1MzMzOnN1Ym5ldC9zdWJuZXQtYWZhNjU2ZjAiLCJhc3NpZ25faXB2Nl9hZGRyZXNzX29uX2NyZWF0aW9uIjpmYWxzZSwiYXZhaWxhYmlsaXR5X3pvbmUiOiJ1cy1lYXN0LTFjIiwiYXZhaWxhYmlsaXR5X3pvbmVfaWQiOiJ1c2UxLWF6NiIsImNpZHJfYmxvY2siOiIxNzIuMzEuMzIuMC8yMCIsImlkIjoic3VibmV0LWFmYTY1NmYwIiwiaXB2Nl9jaWRyX2Jsb2NrIjoiIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoiIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOnRydWUsIm91dHBvc3RfYXJuIjoiIiwib3duZXJfaWQiOiI5MjkzMjcwNjUzMzMiLCJ0YWdzIjp7fSwidGltZW91dHMiOnsiY3JlYXRlIjpudWxsLCJkZWxldGUiOm51bGx9LCJ2cGNfaWQiOiJ2cGMtNDFkMWQxM2IifQ==",
"Err": null
}

View File

@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiYXJuIjoic3RyaW5nIiwiYXNzaWduX2lwdjZfYWRkcmVzc19vbl9jcmVhdGlvbiI6ImJvb2wiLCJhdmFpbGFiaWxpdHlfem9uZSI6InN0cmluZyIsImF2YWlsYWJpbGl0eV96b25lX2lkIjoic3RyaW5nIiwiY2lkcl9ibG9jayI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoic3RyaW5nIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOiJib29sIiwib3V0cG9zdF9hcm4iOiJzdHJpbmciLCJvd25lcl9pZCI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInRpbWVvdXRzIjpbIm9iamVjdCIseyJjcmVhdGUiOiJzdHJpbmciLCJkZWxldGUiOiJzdHJpbmcifV0sInZwY19pZCI6InN0cmluZyJ9XQ==",
"Val": "eyJhcm4iOiJhcm46YXdzOmVjMjp1cy1lYXN0LTE6OTI5MzI3MDY1MzMzOnN1Ym5ldC9zdWJuZXQtMDU4MTBkM2Y5MzM5MjVmNmQiLCJhc3NpZ25faXB2Nl9hZGRyZXNzX29uX2NyZWF0aW9uIjpmYWxzZSwiYXZhaWxhYmlsaXR5X3pvbmUiOiJ1cy1lYXN0LTFkIiwiYXZhaWxhYmlsaXR5X3pvbmVfaWQiOiJ1c2UxLWF6MSIsImNpZHJfYmxvY2siOiIxMC4wLjAuMC8yNCIsImlkIjoic3VibmV0LTA1ODEwZDNmOTMzOTI1ZjZkIiwiaXB2Nl9jaWRyX2Jsb2NrIjoiIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoiIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOmZhbHNlLCJvdXRwb3N0X2FybiI6IiIsIm93bmVyX2lkIjoiOTI5MzI3MDY1MzMzIiwidGFncyI6e30sInRpbWVvdXRzIjp7ImNyZWF0ZSI6bnVsbCwiZGVsZXRlIjpudWxsfSwidnBjX2lkIjoidnBjLTBiZjQzYWM5YjVlZDI0M2Y3In0=",
"Err": null
}

View File

@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiYXJuIjoic3RyaW5nIiwiYXNzaWduX2lwdjZfYWRkcmVzc19vbl9jcmVhdGlvbiI6ImJvb2wiLCJhdmFpbGFiaWxpdHlfem9uZSI6InN0cmluZyIsImF2YWlsYWJpbGl0eV96b25lX2lkIjoic3RyaW5nIiwiY2lkcl9ibG9jayI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoic3RyaW5nIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOiJib29sIiwib3V0cG9zdF9hcm4iOiJzdHJpbmciLCJvd25lcl9pZCI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInRpbWVvdXRzIjpbIm9iamVjdCIseyJjcmVhdGUiOiJzdHJpbmciLCJkZWxldGUiOiJzdHJpbmcifV0sInZwY19pZCI6InN0cmluZyJ9XQ==",
"Val": "eyJhcm4iOiJhcm46YXdzOmVjMjp1cy1lYXN0LTE6OTI5MzI3MDY1MzMzOnN1Ym5ldC9zdWJuZXQtMGIxM2YxZTBlYWNmNjc0MjQiLCJhc3NpZ25faXB2Nl9hZGRyZXNzX29uX2NyZWF0aW9uIjpmYWxzZSwiYXZhaWxhYmlsaXR5X3pvbmUiOiJ1cy1lYXN0LTFlIiwiYXZhaWxhYmlsaXR5X3pvbmVfaWQiOiJ1c2UxLWF6MyIsImNpZHJfYmxvY2siOiIxMC4wLjEuMC8yNCIsImlkIjoic3VibmV0LTBiMTNmMWUwZWFjZjY3NDI0IiwiaXB2Nl9jaWRyX2Jsb2NrIjoiIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoiIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOmZhbHNlLCJvdXRwb3N0X2FybiI6IiIsIm93bmVyX2lkIjoiOTI5MzI3MDY1MzMzIiwidGFncyI6e30sInRpbWVvdXRzIjp7ImNyZWF0ZSI6bnVsbCwiZGVsZXRlIjpudWxsfSwidnBjX2lkIjoidnBjLTBiZjQzYWM5YjVlZDI0M2Y3In0=",
"Err": null
}

View File

@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiYXJuIjoic3RyaW5nIiwiYXNzaWduX2lwdjZfYWRkcmVzc19vbl9jcmVhdGlvbiI6ImJvb2wiLCJhdmFpbGFiaWxpdHlfem9uZSI6InN0cmluZyIsImF2YWlsYWJpbGl0eV96b25lX2lkIjoic3RyaW5nIiwiY2lkcl9ibG9jayI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrIjoic3RyaW5nIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoic3RyaW5nIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOiJib29sIiwib3V0cG9zdF9hcm4iOiJzdHJpbmciLCJvd25lcl9pZCI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInRpbWVvdXRzIjpbIm9iamVjdCIseyJjcmVhdGUiOiJzdHJpbmciLCJkZWxldGUiOiJzdHJpbmcifV0sInZwY19pZCI6InN0cmluZyJ9XQ==",
"Val": "eyJhcm4iOiJhcm46YXdzOmVjMjp1cy1lYXN0LTE6OTI5MzI3MDY1MzMzOnN1Ym5ldC9zdWJuZXQtMGM5Yjc4MDAxZmUxODZlMjIiLCJhc3NpZ25faXB2Nl9hZGRyZXNzX29uX2NyZWF0aW9uIjpmYWxzZSwiYXZhaWxhYmlsaXR5X3pvbmUiOiJ1cy1lYXN0LTFmIiwiYXZhaWxhYmlsaXR5X3pvbmVfaWQiOiJ1c2UxLWF6NSIsImNpZHJfYmxvY2siOiIxMC4wLjIuMC8yNCIsImlkIjoic3VibmV0LTBjOWI3ODAwMWZlMTg2ZTIyIiwiaXB2Nl9jaWRyX2Jsb2NrIjoiIiwiaXB2Nl9jaWRyX2Jsb2NrX2Fzc29jaWF0aW9uX2lkIjoiIiwibWFwX3B1YmxpY19pcF9vbl9sYXVuY2giOmZhbHNlLCJvdXRwb3N0X2FybiI6IiIsIm93bmVyX2lkIjoiOTI5MzI3MDY1MzMzIiwidGFncyI6e30sInRpbWVvdXRzIjp7ImNyZWF0ZSI6bnVsbCwiZGVsZXRlIjpudWxsfSwidnBjX2lkIjoidnBjLTBiZjQzYWM5YjVlZDI0M2Y3In0=",
"Err": null
}

View File

@ -0,0 +1,59 @@
[
{
"arn": "arn:aws:ec2:us-east-1:929327065333:subnet/subnet-44fe0c65",
"assign_ipv6_address_on_creation": false,
"availability_zone": "us-east-1a",
"availability_zone_id": "use1-az2",
"cidr_block": "172.31.80.0/20",
"id": "subnet-44fe0c65",
"ipv6_cidr_block": "",
"ipv6_cidr_block_association_id": "",
"map_public_ip_on_launch": true,
"outpost_arn": "",
"owner_id": "929327065333",
"tags": {},
"timeouts": {
"create": null,
"delete": null
},
"vpc_id": "vpc-41d1d13b"
},
{
"arn": "arn:aws:ec2:us-east-1:929327065333:subnet/subnet-65e16628",
"assign_ipv6_address_on_creation": false,
"availability_zone": "us-east-1b",
"availability_zone_id": "use1-az4",
"cidr_block": "172.31.16.0/20",
"id": "subnet-65e16628",
"ipv6_cidr_block": "",
"ipv6_cidr_block_association_id": "",
"map_public_ip_on_launch": true,
"outpost_arn": "",
"owner_id": "929327065333",
"tags": {},
"timeouts": {
"create": null,
"delete": null
},
"vpc_id": "vpc-41d1d13b"
},
{
"arn": "arn:aws:ec2:us-east-1:929327065333:subnet/subnet-afa656f0",
"assign_ipv6_address_on_creation": false,
"availability_zone": "us-east-1c",
"availability_zone_id": "use1-az6",
"cidr_block": "172.31.32.0/20",
"id": "subnet-afa656f0",
"ipv6_cidr_block": "",
"ipv6_cidr_block_association_id": "",
"map_public_ip_on_launch": true,
"outpost_arn": "",
"owner_id": "929327065333",
"tags": {},
"timeouts": {
"create": null,
"delete": null
},
"vpc_id": "vpc-41d1d13b"
}
]

View File

@ -0,0 +1,59 @@
[
{
"arn": "arn:aws:ec2:us-east-1:929327065333:subnet/subnet-05810d3f933925f6d",
"assign_ipv6_address_on_creation": false,
"availability_zone": "us-east-1d",
"availability_zone_id": "use1-az1",
"cidr_block": "10.0.0.0/24",
"id": "subnet-05810d3f933925f6d",
"ipv6_cidr_block": "",
"ipv6_cidr_block_association_id": "",
"map_public_ip_on_launch": false,
"outpost_arn": "",
"owner_id": "929327065333",
"tags": {},
"timeouts": {
"create": null,
"delete": null
},
"vpc_id": "vpc-0bf43ac9b5ed243f7"
},
{
"arn": "arn:aws:ec2:us-east-1:929327065333:subnet/subnet-0b13f1e0eacf67424",
"assign_ipv6_address_on_creation": false,
"availability_zone": "us-east-1e",
"availability_zone_id": "use1-az3",
"cidr_block": "10.0.1.0/24",
"id": "subnet-0b13f1e0eacf67424",
"ipv6_cidr_block": "",
"ipv6_cidr_block_association_id": "",
"map_public_ip_on_launch": false,
"outpost_arn": "",
"owner_id": "929327065333",
"tags": {},
"timeouts": {
"create": null,
"delete": null
},
"vpc_id": "vpc-0bf43ac9b5ed243f7"
},
{
"arn": "arn:aws:ec2:us-east-1:929327065333:subnet/subnet-0c9b78001fe186e22",
"assign_ipv6_address_on_creation": false,
"availability_zone": "us-east-1f",
"availability_zone_id": "use1-az5",
"cidr_block": "10.0.2.0/24",
"id": "subnet-0c9b78001fe186e22",
"ipv6_cidr_block": "",
"ipv6_cidr_block_association_id": "",
"map_public_ip_on_launch": false,
"outpost_arn": "",
"owner_id": "929327065333",
"tags": {},
"timeouts": {
"create": null,
"delete": null
},
"vpc_id": "vpc-0bf43ac9b5ed243f7"
}
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
provider "aws" {
region = "us-east-1"
}
terraform {
required_providers {
aws = "3.19.0"
}
}
resource "aws_vpc" "vpc_for_subnets" {
cidr_block = "10.0.0.0/16"
}
resource "aws_default_subnet" "default-a" {
availability_zone = "us-east-1a"
}
resource "aws_default_subnet" "default-b" {
availability_zone = "us-east-1b"
}
resource "aws_default_subnet" "default-c" {
availability_zone = "us-east-1c"
}
resource "aws_subnet" "subnet1" {
vpc_id = aws_vpc.vpc_for_subnets.id
cidr_block = "10.0.0.0/24"
}
resource "aws_subnet" "subnet2" {
vpc_id = aws_vpc.vpc_for_subnets.id
cidr_block = "10.0.1.0/24"
}
resource "aws_subnet" "subnet3" {
vpc_id = aws_vpc.vpc_for_subnets.id
cidr_block = "10.0.2.0/24"
}

View File

@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
// GENERATED, DO NOT EDIT THIS FILE
package aws
const AwsDefaultSubnetResourceType = "aws_default_subnet"
type AwsDefaultSubnet struct {
Arn *string `cty:"arn" computed:"true"`
AssignIpv6AddressOnCreation *bool `cty:"assign_ipv6_address_on_creation" computed:"true"`
AvailabilityZone *string `cty:"availability_zone"`
AvailabilityZoneId *string `cty:"availability_zone_id" computed:"true"`
CidrBlock *string `cty:"cidr_block" computed:"true"`
Id string `cty:"id" computed:"true"`
Ipv6CidrBlock *string `cty:"ipv6_cidr_block" computed:"true"`
Ipv6CidrBlockAssociationId *string `cty:"ipv6_cidr_block_association_id" computed:"true"`
MapPublicIpOnLaunch *bool `cty:"map_public_ip_on_launch" computed:"true"`
OutpostArn *string `cty:"outpost_arn"`
OwnerId *string `cty:"owner_id" computed:"true"`
Tags map[string]string `cty:"tags"`
VpcId *string `cty:"vpc_id" computed:"true"`
Timeouts *struct {
Create *string `cty:"create"`
Delete *string `cty:"delete"`
} `cty:"timeouts" diff:"-"`
}
func (r *AwsDefaultSubnet) TerraformId() string {
return r.Id
}
func (r *AwsDefaultSubnet) TerraformType() string {
return AwsDefaultSubnetResourceType
}

View File

@ -0,0 +1,32 @@
// GENERATED, DO NOT EDIT THIS FILE
package aws
const AwsSubnetResourceType = "aws_subnet"
type AwsSubnet struct {
Arn *string `cty:"arn" computed:"true"`
AssignIpv6AddressOnCreation *bool `cty:"assign_ipv6_address_on_creation"`
AvailabilityZone *string `cty:"availability_zone" computed:"true"`
AvailabilityZoneId *string `cty:"availability_zone_id" computed:"true"`
CidrBlock *string `cty:"cidr_block"`
Id string `cty:"id" computed:"true"`
Ipv6CidrBlock *string `cty:"ipv6_cidr_block"`
Ipv6CidrBlockAssociationId *string `cty:"ipv6_cidr_block_association_id" computed:"true"`
MapPublicIpOnLaunch *bool `cty:"map_public_ip_on_launch"`
OutpostArn *string `cty:"outpost_arn"`
OwnerId *string `cty:"owner_id" computed:"true"`
Tags map[string]string `cty:"tags"`
VpcId *string `cty:"vpc_id"`
Timeouts *struct {
Create *string `cty:"create"`
Delete *string `cty:"delete"`
} `cty:"timeouts" diff:"-"`
}
func (r *AwsSubnet) TerraformId() string {
return r.Id
}
func (r *AwsSubnet) TerraformType() string {
return AwsSubnetResourceType
}

View File

@ -0,0 +1,28 @@
package aws_test
import (
"testing"
"github.com/cloudskiff/driftctl/test/acceptance"
)
func TestAcc_AwsSubnet(t *testing.T) {
acceptance.Run(t, acceptance.AccTestCase{
Path: "./testdata/acc/aws_subnet",
Args: []string{"scan", "--filter", "Type=='aws_subnet' || Type=='aws_default_subnet'"},
Checks: []acceptance.AccCheck{
{
Env: map[string]string{
"AWS_REGION": "us-east-1",
},
Check: func(result *acceptance.ScanResult, stdout string, err error) {
if err != nil {
t.Fatal(err)
}
result.AssertInfrastructureIsInSync()
result.Equal(6, result.Summary().TotalManaged)
},
},
},
})
}

View File

@ -0,0 +1,43 @@
package deserializer
import (
"github.com/cloudskiff/driftctl/pkg/resource"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
)
type DefaultSubnetDeserializer struct {
}
func NewDefaultSubnetDeserializer() *DefaultSubnetDeserializer {
return &DefaultSubnetDeserializer{}
}
func (s *DefaultSubnetDeserializer) HandledType() resource.ResourceType {
return resourceaws.AwsDefaultSubnetResourceType
}
func (s DefaultSubnetDeserializer) Deserialize(rawList []cty.Value) ([]resource.Resource, error) {
resources := make([]resource.Resource, 0)
for _, rawResource := range rawList {
resource, err := decodeDefaultSubnet(&rawResource)
if err != nil {
logrus.Warnf("Error when deserializing resource %+v : %+v", rawResource, err)
return nil, err
}
resources = append(resources, resource)
}
return resources, nil
}
func decodeDefaultSubnet(raw *cty.Value) (*resourceaws.AwsDefaultSubnet, error) {
var decoded resourceaws.AwsDefaultSubnet
if err := gocty.FromCtyValue(*raw, &decoded); err != nil {
return nil, err
}
return &decoded, nil
}

View File

@ -0,0 +1,43 @@
package deserializer
import (
"github.com/cloudskiff/driftctl/pkg/resource"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
)
type SubnetDeserializer struct {
}
func NewSubnetDeserializer() *SubnetDeserializer {
return &SubnetDeserializer{}
}
func (s *SubnetDeserializer) HandledType() resource.ResourceType {
return resourceaws.AwsSubnetResourceType
}
func (s SubnetDeserializer) Deserialize(rawList []cty.Value) ([]resource.Resource, error) {
resources := make([]resource.Resource, 0)
for _, rawResource := range rawList {
resource, err := decodeSubnet(&rawResource)
if err != nil {
logrus.Warnf("Error when deserializing resource %+v : %+v", rawResource, err)
return nil, err
}
resources = append(resources, resource)
}
return resources, nil
}
func decodeSubnet(raw *cty.Value) (*resourceaws.AwsSubnet, error) {
var decoded resourceaws.AwsSubnet
if err := gocty.FromCtyValue(*raw, &decoded); err != nil {
return nil, err
}
return &decoded, nil
}

View File

@ -0,0 +1,20 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "3.19.0"
constraints = "3.19.0"
hashes = [
"h1:+7Vi7p13+cnrxjXbfJiTimGSFR97xCaQwkkvWcreLns=",
"zh:185a5259153eb9ee4699d4be43b3d509386b473683392034319beee97d470c3b",
"zh:2d9a0a01f93e8d16539d835c02b8b6e1927b7685f4076e96cb07f7dd6944bc6c",
"zh:703f6da36b1b5f3497baa38fccaa7765fb8a2b6440344e4c97172516b49437dd",
"zh:770855565462abadbbddd98cb357d2f1a8f30f68a358cb37cbd5c072cb15b377",
"zh:8008db43149fe4345301f81e15e6d9ddb47aa5e7a31648f9b290af96ad86e92a",
"zh:8cdd27d375da6dcb7687f1fed126b7c04efce1671066802ee876dbbc9c66ec79",
"zh:be22ae185005690d1a017c1b909e0d80ab567e239b4f06ecacdba85080667c1c",
"zh:d2d02e72dbd80f607636cd6237a6c862897caabc635c7b50c0cb243d11246723",
"zh:d8f125b66a1eda2555c0f9bbdf12036a5f8d073499a22ca9e4812b68067fea31",
"zh:f5a98024c64d5d2973ff15b093725a074c0cb4afde07ef32c542e69f17ac90bc",
]
}

View File

@ -0,0 +1,40 @@
provider "aws" {
region = "us-east-1"
}
terraform {
required_providers {
aws = "3.19.0"
}
}
resource "aws_vpc" "vpc_for_subnets" {
cidr_block = "10.0.0.0/16"
}
resource "aws_default_subnet" "default-a" {
availability_zone = "us-east-1a"
}
resource "aws_default_subnet" "default-b" {
availability_zone = "us-east-1b"
}
resource "aws_default_subnet" "default-c" {
availability_zone = "us-east-1c"
}
resource "aws_subnet" "subnet1" {
vpc_id = aws_vpc.vpc_for_subnets.id
cidr_block = "10.0.0.0/24"
}
resource "aws_subnet" "subnet2" {
vpc_id = aws_vpc.vpc_for_subnets.id
cidr_block = "10.0.1.0/24"
}
resource "aws_subnet" "subnet3" {
vpc_id = aws_vpc.vpc_for_subnets.id
cidr_block = "10.0.2.0/24"
}

View File

@ -84,3 +84,7 @@ func (r *ScanResult) AssertDriftCountTotal(count int) {
}
r.Equal(count, driftCount)
}
func (r ScanResult) AssertInfrastructureIsInSync() {
r.Equal(true, r.Analysis.IsSync(), "Infrastructure is not in sync")
}

View File

@ -27,6 +27,7 @@ import (
type AccCheck struct {
PreExec func()
PostExec func()
Env map[string]string
Check func(result *ScanResult, stdout string, err error)
}
@ -210,7 +211,17 @@ func Run(t *testing.T, c AccTestCase) {
if check.PreExec != nil {
check.PreExec()
}
if len(check.Env) > 0 {
for key, value := range check.Env {
os.Setenv(key, value)
}
}
_, out, cmdErr := runDriftCtlCmd(driftctlCmd)
if len(check.Env) > 0 {
for key := range check.Env {
_ = os.Unsetenv(key)
}
}
check.Check(c.getResult(t), out, cmdErr)
if check.PostExec != nil {
check.PostExec()