Merge branch 'main' into refact/vpc_deepmode

main
sundowndev 2021-07-05 11:18:10 +02:00
commit 90b0bcde33
55 changed files with 771 additions and 128734 deletions

1
go.sum
View File

@ -545,6 +545,7 @@ github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=

View File

@ -0,0 +1,49 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
tf "github.com/cloudskiff/driftctl/pkg/remote/terraform"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
)
type EC2AmiEnumerator struct {
repository repository.EC2Repository
factory resource.ResourceFactory
providerConfig tf.TerraformProviderConfig
}
func NewEC2AmiEnumerator(repo repository.EC2Repository, factory resource.ResourceFactory, providerConfig tf.TerraformProviderConfig) *EC2AmiEnumerator {
return &EC2AmiEnumerator{
repository: repo,
factory: factory,
providerConfig: providerConfig,
}
}
func (e *EC2AmiEnumerator) SupportedType() resource.ResourceType {
return aws.AwsAmiResourceType
}
func (e *EC2AmiEnumerator) Enumerate() ([]resource.Resource, error) {
images, err := e.repository.ListAllImages()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(e.SupportedType()))
}
results := make([]resource.Resource, len(images))
for _, image := range images {
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
*image.ImageId,
map[string]interface{}{},
),
)
}
return results, err
}

View File

@ -1,64 +0,0 @@
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"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/aws/aws-sdk-go/aws"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
)
type EC2AmiSupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.EC2Repository
runner *terraform.ParallelResourceReader
}
func NewEC2AmiSupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer, repository repository.EC2Repository) *EC2AmiSupplier {
return &EC2AmiSupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
}
}
func (s *EC2AmiSupplier) Resources() ([]resource.Resource, error) {
images, err := s.repository.ListAllImages()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, resourceaws.AwsAmiResourceType)
}
results := make([]cty.Value, 0)
if len(images) > 0 {
for _, image := range images {
id := aws.StringValue(image.ImageId)
s.runner.Run(func() (cty.Value, error) {
return s.readAMI(id)
})
}
results, err = s.runner.Wait()
if err != nil {
return nil, err
}
}
return s.deserializer.Deserialize(resourceaws.AwsAmiResourceType, results)
}
func (s *EC2AmiSupplier) readAMI(id string) (cty.Value, error) {
resImage, err := s.reader.ReadResource(terraform.ReadResourceArgs{
Ty: resourceaws.AwsAmiResourceType,
ID: id,
})
if err != nil {
logrus.Warnf("Error reading image %s[%s]: %+v", id, resourceaws.AwsAmiResourceType, err)
return cty.NilVal, err
}
return *resImage, nil
}

View File

@ -1,101 +0,0 @@
package aws
import (
"context"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
testresource "github.com/cloudskiff/driftctl/test/resource"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
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/stretchr/testify/assert"
"github.com/cloudskiff/driftctl/test/goldenfile"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/mocks"
)
func TestEC2AmiSupplier_Resources(t *testing.T) {
tests := []struct {
test string
dirName string
mock func(mock *repository.MockEC2Repository)
err error
}{
{
test: "no amis",
dirName: "ec2_ami_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllImages").Return([]*ec2.Image{}, nil)
},
err: nil,
},
{
test: "with amis",
dirName: "ec2_ami_multiple",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllImages").Return([]*ec2.Image{
{ImageId: aws.String("ami-03a578b46f4c3081b")},
{ImageId: aws.String("ami-025962fd8b456731f")},
}, nil)
},
err: nil,
},
{
test: "cannot list amis",
dirName: "ec2_ami_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllImages").Return([]*ec2.Image{}, awserr.NewRequestFailure(nil, 403, ""))
},
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsAmiResourceType),
},
}
for _, tt := range tests {
shouldUpdate := tt.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(NewEC2AmiSupplier(provider, deserializer, repository.NewEC2Repository(provider.session, cache.New(0))))
}
t.Run(tt.test, func(t *testing.T) {
provider := mocks.NewMockedGoldenTFProvider(tt.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
client := &repository.MockEC2Repository{}
tt.mock(client)
s := &EC2AmiSupplier{
provider,
deserializer,
client,
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
}
got, err := s.Resources()
assert.Equal(t, tt.err, err)
test.CtyTestDiff(got, tt.dirName, provider, deserializer, shouldUpdate, t)
})
}
}

View File

@ -0,0 +1,49 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
tf "github.com/cloudskiff/driftctl/pkg/remote/terraform"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
)
type EC2EipAssociationEnumerator struct {
repository repository.EC2Repository
factory resource.ResourceFactory
providerConfig tf.TerraformProviderConfig
}
func NewEC2EipAssociationEnumerator(repo repository.EC2Repository, factory resource.ResourceFactory, providerConfig tf.TerraformProviderConfig) *EC2EipAssociationEnumerator {
return &EC2EipAssociationEnumerator{
repository: repo,
factory: factory,
providerConfig: providerConfig,
}
}
func (e *EC2EipAssociationEnumerator) SupportedType() resource.ResourceType {
return aws.AwsEipAssociationResourceType
}
func (e *EC2EipAssociationEnumerator) Enumerate() ([]resource.Resource, error) {
associationIds, err := e.repository.ListAllAddressesAssociation()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(e.SupportedType()))
}
results := make([]resource.Resource, len(associationIds))
for _, associationId := range associationIds {
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
associationId,
map[string]interface{}{},
),
)
}
return results, err
}

View File

@ -1,62 +0,0 @@
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"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
)
type EC2EipAssociationSupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.EC2Repository
runner *terraform.ParallelResourceReader
}
func NewEC2EipAssociationSupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer, repository repository.EC2Repository) *EC2EipAssociationSupplier {
return &EC2EipAssociationSupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner())}
}
func (s *EC2EipAssociationSupplier) Resources() ([]resource.Resource, error) {
associationIds, err := s.repository.ListAllAddressesAssociation()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, resourceaws.AwsEipAssociationResourceType)
}
results := make([]cty.Value, 0)
if len(associationIds) > 0 {
for _, assocId := range associationIds {
assocId := assocId
s.runner.Run(func() (cty.Value, error) {
return s.readEIPAssociation(assocId)
})
}
results, err = s.runner.Wait()
if err != nil {
return nil, err
}
}
return s.deserializer.Deserialize(resourceaws.AwsEipAssociationResourceType, results)
}
func (s *EC2EipAssociationSupplier) readEIPAssociation(assocId string) (cty.Value, error) {
resAssoc, err := s.reader.ReadResource(terraform.ReadResourceArgs{
Ty: resourceaws.AwsEipAssociationResourceType,
ID: assocId,
})
if err != nil {
logrus.Warnf("Error reading eip association %s[%s]: %+v", assocId, resourceaws.AwsEipAssociationResourceType, err)
return cty.NilVal, err
}
return *resAssoc, nil
}

View File

@ -1,97 +0,0 @@
package aws
import (
"context"
"testing"
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
testresource "github.com/cloudskiff/driftctl/test/resource"
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/stretchr/testify/assert"
"github.com/cloudskiff/driftctl/pkg/parallel"
"github.com/cloudskiff/driftctl/test/goldenfile"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/mocks"
)
func TestEC2EipAssociationSupplier_Resources(t *testing.T) {
tests := []struct {
test string
dirName string
mock func(mock *repository.MockEC2Repository)
err error
}{
{
test: "no eip associations",
dirName: "ec2_eip_association_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllAddressesAssociation").Return([]string{}, nil)
},
err: nil,
},
{
test: "with eip associations",
dirName: "ec2_eip_association_single",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllAddressesAssociation").Return([]string{
"eipassoc-0e9a7356e30f0c3d1",
}, nil)
},
err: nil,
},
{
test: "Cannot list eip associations",
dirName: "ec2_eip_association_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllAddressesAssociation").Return([]string{}, awserr.NewRequestFailure(nil, 403, ""))
},
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsEipAssociationResourceType),
},
}
for _, tt := range tests {
shouldUpdate := tt.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(NewEC2EipAssociationSupplier(provider, deserializer, repository.NewEC2Repository(provider.session, cache.New(0))))
}
t.Run(tt.test, func(t *testing.T) {
provider := mocks.NewMockedGoldenTFProvider(tt.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
client := &repository.MockEC2Repository{}
tt.mock(client)
s := &EC2EipAssociationSupplier{
provider,
deserializer,
client,
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
}
got, err := s.Resources()
assert.Equal(t, tt.err, err)
test.CtyTestDiff(got, tt.dirName, provider, deserializer, shouldUpdate, t)
})
}
}

View File

@ -0,0 +1,41 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/sirupsen/logrus"
)
type EC2InstanceDetailsFetcher struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
}
func NewEC2InstanceDetailsFetcher(provider terraform.ResourceReader, deserializer *resource.Deserializer) *EC2InstanceDetailsFetcher {
return &EC2InstanceDetailsFetcher{
reader: provider,
deserializer: deserializer,
}
}
func (r *EC2InstanceDetailsFetcher) ReadDetails(res resource.Resource) (resource.Resource, error) {
ctyVal, err := r.reader.ReadResource(terraform.ReadResourceArgs{
Ty: aws.AwsInstanceResourceType,
ID: res.TerraformId(),
})
if err != nil {
return nil, err
}
if ctyVal.IsNull() {
logrus.WithFields(logrus.Fields{
"id": res.TerraformId(),
}).Debug("Instance read returned nil (instance may be terminated), ignoring ...")
return nil, nil
}
deserializedRes, err := r.deserializer.DeserializeOne(aws.AwsInstanceResourceType, *ctyVal)
if err != nil {
return nil, err
}
return deserializedRes, nil
}

View File

@ -0,0 +1,49 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
tf "github.com/cloudskiff/driftctl/pkg/remote/terraform"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
)
type EC2InstanceEnumerator struct {
repository repository.EC2Repository
factory resource.ResourceFactory
providerConfig tf.TerraformProviderConfig
}
func NewEC2InstanceEnumerator(repo repository.EC2Repository, factory resource.ResourceFactory, providerConfig tf.TerraformProviderConfig) *EC2InstanceEnumerator {
return &EC2InstanceEnumerator{
repository: repo,
factory: factory,
providerConfig: providerConfig,
}
}
func (e *EC2InstanceEnumerator) SupportedType() resource.ResourceType {
return aws.AwsInstanceResourceType
}
func (e *EC2InstanceEnumerator) Enumerate() ([]resource.Resource, error) {
instances, err := e.repository.ListAllInstances()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(e.SupportedType()))
}
results := make([]resource.Resource, len(instances))
for _, instance := range instances {
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
*instance.InstanceId,
map[string]interface{}{},
),
)
}
return results, err
}

View File

@ -1,70 +0,0 @@
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"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/aws/aws-sdk-go/aws"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
)
type EC2InstanceSupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.EC2Repository
runner *terraform.ParallelResourceReader
}
func NewEC2InstanceSupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer, repository repository.EC2Repository) *EC2InstanceSupplier {
return &EC2InstanceSupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
}
}
func (s *EC2InstanceSupplier) Resources() ([]resource.Resource, error) {
instances, err := s.repository.ListAllInstances()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, resourceaws.AwsInstanceResourceType)
}
results := make([]cty.Value, 0)
if len(instances) > 0 {
for _, instance := range instances {
id := aws.StringValue(instance.InstanceId)
s.runner.Run(func() (cty.Value, error) {
return s.readInstance(id)
})
}
results, err = s.runner.Wait()
if err != nil {
return nil, err
}
}
return s.deserializer.Deserialize(resourceaws.AwsInstanceResourceType, results)
}
func (s *EC2InstanceSupplier) readInstance(id string) (cty.Value, error) {
resInstance, err := s.reader.ReadResource(terraform.ReadResourceArgs{
Ty: resourceaws.AwsInstanceResourceType,
ID: id,
})
if err != nil {
logrus.Warnf("Error reading instance %s: %+v", id, err)
return cty.NilVal, err
}
if resInstance.IsNull() {
logrus.WithFields(logrus.Fields{
"id": id,
}).Debug("Instance read returned nil (instance may be terminated), ignoring ...")
}
return *resInstance, nil
}

View File

@ -1,120 +0,0 @@
package aws
import (
"context"
"testing"
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
testresource "github.com/cloudskiff/driftctl/test/resource"
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/stretchr/testify/assert"
"github.com/cloudskiff/driftctl/pkg/parallel"
"github.com/cloudskiff/driftctl/test/goldenfile"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/mocks"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
)
func TestEC2InstanceSupplier_Resources(t *testing.T) {
tests := []struct {
test string
dirName string
mock func(mock *repository.MockEC2Repository)
err error
}{
{
test: "no instances",
dirName: "ec2_instance_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllInstances").Return([]*ec2.Instance{}, nil)
},
err: nil,
},
{
test: "with instances",
dirName: "ec2_instance_multiple",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllInstances").Return([]*ec2.Instance{
{
InstanceId: aws.String("i-0d3650a23f4e45dc0"),
},
{
InstanceId: aws.String("i-010376047a71419f1"),
},
}, nil)
},
err: nil,
},
{
test: "with terminated instances",
dirName: "ec2_instance_terminated",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllInstances").Return([]*ec2.Instance{
{
InstanceId: aws.String("i-0e1543baf4f2cd990"),
},
{
InstanceId: aws.String("i-0a3a7ed51ae2b4fa0"), // Nil
},
}, nil)
},
err: nil,
},
{
test: "Cannot list instances",
dirName: "ec2_instance_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllInstances").Return([]*ec2.Instance{}, awserr.NewRequestFailure(nil, 403, ""))
},
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsInstanceResourceType),
},
}
for _, tt := range tests {
shouldUpdate := tt.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(NewEC2InstanceSupplier(provider, deserializer, repository.NewEC2Repository(provider.session, cache.New(0))))
}
t.Run(tt.test, func(t *testing.T) {
provider := mocks.NewMockedGoldenTFProvider(tt.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
client := &repository.MockEC2Repository{}
tt.mock(client)
s := &EC2InstanceSupplier{
provider,
deserializer,
client,
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
}
got, err := s.Resources()
assert.Equal(t, tt.err, err)
test.CtyTestDiff(got, tt.dirName, provider, deserializer, shouldUpdate, t)
})
}
}

View File

@ -0,0 +1,49 @@
package aws
import (
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
tf "github.com/cloudskiff/driftctl/pkg/remote/terraform"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
)
type EC2KeyPairEnumerator struct {
repository repository.EC2Repository
factory resource.ResourceFactory
providerConfig tf.TerraformProviderConfig
}
func NewEC2KeyPairEnumerator(repo repository.EC2Repository, factory resource.ResourceFactory, providerConfig tf.TerraformProviderConfig) *EC2KeyPairEnumerator {
return &EC2KeyPairEnumerator{
repository: repo,
factory: factory,
providerConfig: providerConfig,
}
}
func (e *EC2KeyPairEnumerator) SupportedType() resource.ResourceType {
return aws.AwsKeyPairResourceType
}
func (e *EC2KeyPairEnumerator) Enumerate() ([]resource.Resource, error) {
keyPairs, err := e.repository.ListAllKeyPairs()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(e.SupportedType()))
}
results := make([]resource.Resource, len(keyPairs))
for _, keyPair := range keyPairs {
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
*keyPair.KeyName,
map[string]interface{}{},
),
)
}
return results, err
}

View File

@ -1,64 +0,0 @@
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"
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/aws/aws-sdk-go/aws"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
)
type EC2KeyPairSupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository repository.EC2Repository
runner *terraform.ParallelResourceReader
}
func NewEC2KeyPairSupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer, repository repository.EC2Repository) *EC2KeyPairSupplier {
return &EC2KeyPairSupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
}
}
func (s *EC2KeyPairSupplier) Resources() ([]resource.Resource, error) {
keyPairs, err := s.repository.ListAllKeyPairs()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, resourceaws.AwsKeyPairResourceType)
}
results := make([]cty.Value, 0)
if len(keyPairs) > 0 {
for _, kp := range keyPairs {
name := aws.StringValue(kp.KeyName)
s.runner.Run(func() (cty.Value, error) {
return s.readKeyPair(name)
})
}
results, err = s.runner.Wait()
if err != nil {
return nil, err
}
}
return s.deserializer.Deserialize(resourceaws.AwsKeyPairResourceType, results)
}
func (s *EC2KeyPairSupplier) readKeyPair(name string) (cty.Value, error) {
resKp, err := s.reader.ReadResource(terraform.ReadResourceArgs{
Ty: resourceaws.AwsKeyPairResourceType,
ID: name,
})
if err != nil {
logrus.Warnf("Error reading key pair %s: %+v", name, err)
return cty.NilVal, err
}
return *resKp, nil
}

View File

@ -1,103 +0,0 @@
package aws
import (
"context"
"testing"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
testresource "github.com/cloudskiff/driftctl/test/resource"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/stretchr/testify/assert"
"github.com/cloudskiff/driftctl/pkg/parallel"
"github.com/cloudskiff/driftctl/test/goldenfile"
"github.com/aws/aws-sdk-go/aws"
"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/mocks"
)
func TestEC2KeyPairSupplier_Resources(t *testing.T) {
tests := []struct {
test string
dirName string
mock func(mock *repository.MockEC2Repository)
err error
}{
{
test: "no key pairs",
dirName: "ec2_key_pair_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllKeyPairs").Return([]*ec2.KeyPairInfo{}, nil)
},
err: nil,
},
{
test: "with key pairs",
dirName: "ec2_key_pair_multiple",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllKeyPairs").Return([]*ec2.KeyPairInfo{
{
KeyName: aws.String("test"),
},
{
KeyName: aws.String("bar"),
},
}, nil)
},
err: nil,
},
{
test: "cannot list key pairs",
dirName: "ec2_key_pair_empty",
mock: func(mock *repository.MockEC2Repository) {
mock.On("ListAllKeyPairs").Return([]*ec2.KeyPairInfo{}, awserr.NewRequestFailure(nil, 403, ""))
},
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsKeyPairResourceType),
},
}
for _, tt := range tests {
shouldUpdate := tt.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(NewEC2KeyPairSupplier(provider, deserializer, repository.NewEC2Repository(provider.session, cache.New(0))))
}
t.Run(tt.test, func(t *testing.T) {
provider := mocks.NewMockedGoldenTFProvider(tt.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
client := &repository.MockEC2Repository{}
tt.mock(client)
s := &EC2KeyPairSupplier{
provider,
deserializer,
client,
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
}
got, err := s.Resources()
assert.Equal(t, tt.err, err)
test.CtyTestDiff(got, tt.dirName, provider, deserializer, shouldUpdate, t)
})
}
}

View File

@ -60,7 +60,6 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddEnumerator(NewS3BucketEnumerator(s3Repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(aws.AwsS3BucketResourceType, NewS3BucketDetailsFetcher(provider, deserializer))
remoteLibrary.AddEnumerator(NewS3BucketInventoryEnumerator(s3Repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(aws.AwsS3BucketInventoryResourceType, NewS3BucketInventoryDetailsFetcher(provider, deserializer))
remoteLibrary.AddEnumerator(NewS3BucketNotificationEnumerator(s3Repository, factory, provider.Config))
@ -74,6 +73,14 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddDetailsFetcher(aws.AwsEbsSnapshotResourceType, common.NewGenericDetailsFetcher(aws.AwsEbsSnapshotResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewEC2EipEnumerator(ec2repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(aws.AwsEipResourceType, common.NewGenericDetailsFetcher(aws.AwsEipResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewEC2AmiEnumerator(ec2repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(aws.AwsAmiResourceType, common.NewGenericDetailsFetcher(aws.AwsAmiResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewEC2KeyPairEnumerator(ec2repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(aws.AwsKeyPairResourceType, common.NewGenericDetailsFetcher(aws.AwsKeyPairResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewEC2EipAssociationEnumerator(ec2repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(aws.AwsEipAssociationResourceType, common.NewGenericDetailsFetcher(aws.AwsEipAssociationResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewEC2InstanceEnumerator(ec2repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(aws.AwsInstanceResourceType, NewEC2InstanceDetailsFetcher(provider, deserializer))
remoteLibrary.AddEnumerator(NewVPCEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsVpcResourceType, common.NewGenericDetailFetcher(aws.AwsVpcResourceType, provider, deserializer))
@ -83,12 +90,8 @@ func Init(version string, alerter *alerter.Alerter,
supplierLibrary.AddSupplier(NewS3BucketAnalyticSupplier(provider, s3Repository, deserializer))
supplierLibrary.AddSupplier(NewS3BucketPolicySupplier(provider, s3Repository, deserializer))
supplierLibrary.AddSupplier(NewEC2EipAssociationSupplier(provider, deserializer, ec2repository))
supplierLibrary.AddSupplier(NewRoute53ZoneSupplier(provider, deserializer, route53repository))
supplierLibrary.AddSupplier(NewRoute53RecordSupplier(provider, deserializer, route53repository))
supplierLibrary.AddSupplier(NewEC2InstanceSupplier(provider, deserializer, ec2repository))
supplierLibrary.AddSupplier(NewEC2AmiSupplier(provider, deserializer, ec2repository))
supplierLibrary.AddSupplier(NewEC2KeyPairSupplier(provider, deserializer, ec2repository))
supplierLibrary.AddSupplier(NewLambdaFunctionSupplier(provider, deserializer, lambdaRepository))
supplierLibrary.AddSupplier(NewDBSubnetGroupSupplier(provider, deserializer, rdsRepository))
supplierLibrary.AddSupplier(NewDBInstanceSupplier(provider, deserializer, rdsRepository))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -297,6 +297,379 @@ func TestEC2Eip(t *testing.T) {
}
}
func TestEC2Ami(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(repository *repository.MockEC2Repository)
wantErr error
}{
{
test: "no amis",
dirName: "aws_ec2_ami_empty",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllImages").Return([]*ec2.Image{}, nil)
},
},
{
test: "multiple amis",
dirName: "aws_ec2_ami_multiple",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllImages").Return([]*ec2.Image{
{ImageId: awssdk.String("ami-03a578b46f4c3081b")},
{ImageId: awssdk.String("ami-025962fd8b456731f")},
}, nil)
},
},
{
test: "cannot list ami",
dirName: "aws_ec2_ami_list",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllImages").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
wantErr: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsAmiResourceType),
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
alerter := &mocks.AlerterInterface{}
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
fakeRepo := &repository.MockEC2Repository{}
c.mocks(fakeRepo)
var repo repository.EC2Repository = 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.NewEC2Repository(sess, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewEC2AmiEnumerator(repo, factory, tf.TerraformProviderConfig{
Name: "test",
DefaultAlias: "eu-west-3",
}))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsAmiResourceType, common.NewGenericDetailsFetcher(resourceaws.AwsAmiResourceType, 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.AwsAmiResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}
func TestEC2KeyPair(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(repository *repository.MockEC2Repository)
wantErr error
}{
{
test: "no key pairs",
dirName: "aws_ec2_key_pair_empty",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllKeyPairs").Return([]*ec2.KeyPairInfo{}, nil)
},
},
{
test: "multiple key pairs",
dirName: "aws_ec2_key_pair_multiple",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllKeyPairs").Return([]*ec2.KeyPairInfo{
{KeyName: awssdk.String("test")},
{KeyName: awssdk.String("bar")},
}, nil)
},
},
{
test: "cannot list key pairs",
dirName: "aws_ec2_key_pair_list",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllKeyPairs").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
wantErr: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsKeyPairResourceType),
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
alerter := &mocks.AlerterInterface{}
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
fakeRepo := &repository.MockEC2Repository{}
c.mocks(fakeRepo)
var repo repository.EC2Repository = 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.NewEC2Repository(sess, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewEC2KeyPairEnumerator(repo, factory, tf.TerraformProviderConfig{
Name: "test",
DefaultAlias: "eu-west-3",
}))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsKeyPairResourceType, common.NewGenericDetailsFetcher(resourceaws.AwsKeyPairResourceType, 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.AwsKeyPairResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}
func TestEC2EipAssociation(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(repository *repository.MockEC2Repository)
wantErr error
}{
{
test: "no eip associations",
dirName: "aws_ec2_eip_association_empty",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllAddressesAssociation").Return([]string{}, nil)
},
},
{
test: "single eip association",
dirName: "aws_ec2_eip_association_single",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllAddressesAssociation").Return([]string{
"eipassoc-0e9a7356e30f0c3d1",
}, nil)
},
},
{
test: "cannot list eip associations",
dirName: "aws_ec2_eip_association_list",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllAddressesAssociation").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
wantErr: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsEipAssociationResourceType),
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
alerter := &mocks.AlerterInterface{}
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
fakeRepo := &repository.MockEC2Repository{}
c.mocks(fakeRepo)
var repo repository.EC2Repository = 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.NewEC2Repository(sess, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewEC2EipAssociationEnumerator(repo, factory, tf.TerraformProviderConfig{
Name: "test",
DefaultAlias: "eu-west-3",
}))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsEipAssociationResourceType, common.NewGenericDetailsFetcher(resourceaws.AwsEipAssociationResourceType, 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.AwsEipAssociationResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}
func TestEC2Instance(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(repository *repository.MockEC2Repository)
wantErr error
}{
{
test: "no instances",
dirName: "aws_ec2_instance_empty",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllInstances").Return([]*ec2.Instance{}, nil)
},
},
{
test: "multiple instances",
dirName: "aws_ec2_instance_multiple",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllInstances").Return([]*ec2.Instance{
{InstanceId: awssdk.String("i-0d3650a23f4e45dc0")},
{InstanceId: awssdk.String("i-010376047a71419f1")},
}, nil)
},
},
{
test: "terminated instances",
dirName: "aws_ec2_instance_terminated",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllInstances").Return([]*ec2.Instance{
{InstanceId: awssdk.String("i-0e1543baf4f2cd990")},
{InstanceId: awssdk.String("i-0a3a7ed51ae2b4fa0")}, // Nil
}, nil)
},
},
{
test: "cannot list instances",
dirName: "aws_ec2_instance_list",
mocks: func(repository *repository.MockEC2Repository) {
repository.On("ListAllInstances").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
},
wantErr: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsInstanceResourceType),
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
alerter := &mocks.AlerterInterface{}
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
fakeRepo := &repository.MockEC2Repository{}
c.mocks(fakeRepo)
var repo repository.EC2Repository = 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.NewEC2Repository(sess, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewEC2InstanceEnumerator(repo, factory, tf.TerraformProviderConfig{
Name: "test",
DefaultAlias: "eu-west-3",
}))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsInstanceResourceType, aws.NewEC2InstanceDetailsFetcher(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.AwsInstanceResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}
func TestVPC(t *testing.T) {
tests := []struct {

View File

@ -0,0 +1,48 @@
package github
import (
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
tf "github.com/cloudskiff/driftctl/pkg/remote/terraform"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/github"
)
type GithubRepositoryEnumerator struct {
repository GithubRepository
factory resource.ResourceFactory
providerConfig tf.TerraformProviderConfig
}
func NewGithubRepositoryEnumerator(repo GithubRepository, factory resource.ResourceFactory, providerConfig tf.TerraformProviderConfig) *GithubRepositoryEnumerator {
return &GithubRepositoryEnumerator{
repository: repo,
factory: factory,
providerConfig: providerConfig,
}
}
func (g *GithubRepositoryEnumerator) SupportedType() resource.ResourceType {
return github.GithubRepositoryResourceType
}
func (g *GithubRepositoryEnumerator) Enumerate() ([]resource.Resource, error) {
ids, err := g.repository.ListRepositories()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, string(g.SupportedType()))
}
results := make([]resource.Resource, len(ids))
for _, id := range ids {
results = append(
results,
g.factory.CreateAbstractResource(
string(g.SupportedType()),
id,
map[string]interface{}{},
),
)
}
return results, err
}

View File

@ -1,57 +0,0 @@
package github
import (
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
"github.com/cloudskiff/driftctl/pkg/resource"
resourcegithub "github.com/cloudskiff/driftctl/pkg/resource/github"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
)
type GithubRepositorySupplier struct {
reader terraform.ResourceReader
deserializer *resource.Deserializer
repository GithubRepository
runner *terraform.ParallelResourceReader
}
func NewGithubRepositorySupplier(provider *GithubTerraformProvider, repository GithubRepository, deserializer *resource.Deserializer) *GithubRepositorySupplier {
return &GithubRepositorySupplier{
provider,
deserializer,
repository,
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
}
}
func (s GithubRepositorySupplier) Resources() ([]resource.Resource, error) {
resourceList, err := s.repository.ListRepositories()
if err != nil {
return nil, remoteerror.NewResourceEnumerationError(err, resourcegithub.GithubRepositoryResourceType)
}
for _, id := range resourceList {
id := id
s.runner.Run(func() (cty.Value, error) {
completeResource, err := s.reader.ReadResource(terraform.ReadResourceArgs{
Ty: resourcegithub.GithubRepositoryResourceType,
ID: id,
})
if err != nil {
logrus.Warnf("Error reading %s[%s]: %+v", id, resourcegithub.GithubRepositoryResourceType, err)
return cty.NilVal, err
}
return *completeResource, nil
})
}
results, err := s.runner.Wait()
if err != nil {
return nil, err
}
return s.deserializer.Deserialize(resourcegithub.GithubRepositoryResourceType, results)
}

View File

@ -1,85 +0,0 @@
package github
import (
"context"
"testing"
"github.com/cloudskiff/driftctl/pkg/parallel"
"github.com/cloudskiff/driftctl/pkg/resource"
resourcegithub "github.com/cloudskiff/driftctl/pkg/resource/github"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/goldenfile"
dritftctlmocks "github.com/cloudskiff/driftctl/test/mocks"
testresource "github.com/cloudskiff/driftctl/test/resource"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestGithubRepositorySupplier_Resources(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *MockGithubRepository)
err error
}{
{
test: "no github repos",
dirName: "github_repository_empty",
mocks: func(client *MockGithubRepository) {
client.On("ListRepositories").Return([]string{}, nil)
},
err: nil,
},
{
test: "Multiple github repos Table",
dirName: "github_repository_multiple",
mocks: func(client *MockGithubRepository) {
client.On("ListRepositories").Return([]string{
"driftctl",
"driftctl-demos",
}, nil)
},
err: nil,
},
}
for _, c := range cases {
shouldUpdate := c.dirName == *goldenfile.Update
providerLibrary := terraform.NewProviderLibrary()
supplierLibrary := resource.NewSupplierLibrary()
repo := testresource.InitFakeSchemaRepository(terraform.GITHUB, "4.4.0")
resourcegithub.InitResourcesMetadata(repo)
factory := terraform.NewTerraformResourceFactory(repo)
deserializer := resource.NewDeserializer(factory)
mockedRepo := MockGithubRepository{}
c.mocks(&mockedRepo)
if shouldUpdate {
provider, err := InitTestGithubProvider(providerLibrary)
if err != nil {
t.Fatal(err)
}
supplierLibrary.AddSupplier(NewGithubRepositorySupplier(provider, &mockedRepo, deserializer))
}
t.Run(c.test, func(tt *testing.T) {
provider := dritftctlmocks.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.GITHUB), shouldUpdate)
s := &GithubRepositorySupplier{
provider,
deserializer,
&mockedRepo,
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

@ -47,7 +47,9 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddEnumerator(NewGithubTeamEnumerator(repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(github.GithubTeamResourceType, common.NewGenericDetailsFetcher(github.GithubTeamResourceType, provider, deserializer))
supplierLibrary.AddSupplier(NewGithubRepositorySupplier(provider, repository, deserializer))
remoteLibrary.AddEnumerator(NewGithubRepositoryEnumerator(repository, factory, provider.Config))
remoteLibrary.AddDetailsFetcher(github.GithubRepositoryResourceType, common.NewGenericDetailsFetcher(github.GithubRepositoryResourceType, provider, deserializer))
supplierLibrary.AddSupplier(NewGithubMembershipSupplier(provider, repository, deserializer))
supplierLibrary.AddSupplier(NewGithubTeamMembershipSupplier(provider, repository, deserializer))
supplierLibrary.AddSupplier(NewGithubBranchProtectionSupplier(provider, repository, deserializer))

View File

@ -0,0 +1,100 @@
package remote
import (
"testing"
"github.com/cloudskiff/driftctl/mocks"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
"github.com/cloudskiff/driftctl/pkg/remote/common"
"github.com/cloudskiff/driftctl/pkg/remote/github"
tf "github.com/cloudskiff/driftctl/pkg/remote/terraform"
githubres "github.com/cloudskiff/driftctl/pkg/resource/github"
"github.com/cloudskiff/driftctl/pkg/terraform"
testresource "github.com/cloudskiff/driftctl/test/resource"
tftest "github.com/cloudskiff/driftctl/test/terraform"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/goldenfile"
"github.com/stretchr/testify/assert"
)
func TestScanGithubRepository(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(client *github.MockGithubRepository)
err error
}{
{
test: "no github repos",
dirName: "github_repository_empty",
mocks: func(client *github.MockGithubRepository) {
client.On("ListRepositories").Return([]string{}, nil)
},
err: nil,
},
{
test: "Multiple github repos Table",
dirName: "github_repository_multiple",
mocks: func(client *github.MockGithubRepository) {
client.On("ListRepositories").Return([]string{
"driftctl",
"driftctl-demos",
}, nil)
},
err: nil,
},
}
schemaRepository := testresource.InitFakeSchemaRepository("github", "4.4.0")
githubres.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
alerter := &mocks.AlerterInterface{}
for _, c := range tests {
t.Run(c.test, func(tt *testing.T) {
shouldUpdate := c.dirName == *goldenfile.Update
scanOptions := ScannerOptions{Deep: true}
providerLibrary := terraform.NewProviderLibrary()
remoteLibrary := common.NewRemoteLibrary()
mockedRepo := github.MockGithubRepository{}
c.mocks(&mockedRepo)
var repo github.GithubRepository = &mockedRepo
realProvider, err := tftest.InitTestGithubProvider(providerLibrary, "4.4.0")
if err != nil {
t.Fatal(err)
}
provider := tftest.NewFakeTerraformProvider(realProvider)
provider.WithResponse(c.dirName)
if shouldUpdate {
err := realProvider.Init()
if err != nil {
t.Fatal(err)
}
provider.ShouldUpdate()
repo = github.NewGithubRepository(realProvider.GetConfig(), cache.New(0))
}
remoteLibrary.AddEnumerator(github.NewGithubRepositoryEnumerator(repo, factory, tf.TerraformProviderConfig{
Name: "test",
}))
remoteLibrary.AddDetailsFetcher(githubres.GithubRepositoryResourceType, common.NewGenericDetailsFetcher(githubres.GithubRepositoryResourceType, provider, deserializer))
s := NewScanner(nil, remoteLibrary, alerter, scanOptions)
got, err := s.Resources()
assert.Equal(tt, err, c.err)
if err != nil {
return
}
test.TestAgainstGoldenFile(got, githubres.GithubRepositoryResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}

View File

@ -85,8 +85,7 @@ func TestScanGithubTeam(t *testing.T) {
}
remoteLibrary.AddEnumerator(github.NewGithubTeamEnumerator(repo, factory, tf.TerraformProviderConfig{
Name: "test",
DefaultAlias: "eu-west-3",
Name: "test",
}))
remoteLibrary.AddDetailsFetcher(githubres.GithubTeamResourceType, common.NewGenericDetailsFetcher(githubres.GithubTeamResourceType, provider, deserializer))