Merge branch 'main' into go1.16
commit
0c06dfa26a
|
@ -12,6 +12,24 @@ When a crash occurs in driftctl, we do not send any crash reports.
|
|||
For debugging purposes, you can add `--error-reporting` when running driftctl and crash data will be sent to us via [Sentry](https://sentry.io)
|
||||
Details of reported data can be found [here](./cmd/flags/error-reporting.md)
|
||||
|
||||
#### Log level
|
||||
|
||||
By default driftctl logger only displays warning and error messages. You can set `LOG_LEVEL` environment variable to change the default level.
|
||||
Valid values are : trace,debug,info,warn,error,fatal,panic.
|
||||
|
||||
**Note:** In trace level, terraform provider logs will be shown.
|
||||
|
||||
Example
|
||||
|
||||
```shell
|
||||
$ LOG_LEVEL=debug driftctl scan
|
||||
DEBU[0000] New provider library created
|
||||
DEBU[0000] Found existing provider path=/home/driftctl/.driftctl/plugins/linux_amd64/terraform-provider-aws_v3.19.0_x5
|
||||
DEBU[0000] Starting gRPC client alias=us-east-1
|
||||
DEBU[0001] New gRPC client started alias=us-east-1
|
||||
...
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
- Commands
|
||||
|
@ -24,4 +42,4 @@ Details of reported data can be found [here](./cmd/flags/error-reporting.md)
|
|||
|
||||
## Issues
|
||||
|
||||
- [Known Issues & Limitations](LIMITATIONS.md)
|
||||
- [Known Issues & Limitations](LIMITATIONS.md)
|
||||
|
|
|
@ -63,6 +63,9 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
|||
"Effect": "Allow",
|
||||
"Resource": "*",
|
||||
"Action": [
|
||||
"cloudfront:GetDistribution",
|
||||
"cloudfront:ListDistributions",
|
||||
"cloudfront:ListTagsForResource",
|
||||
"ec2:DescribeAddresses",
|
||||
"ec2:DescribeImages",
|
||||
"ec2:DescribeInstanceAttribute",
|
||||
|
@ -107,6 +110,8 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
|||
"route53:ListHostedZones",
|
||||
"route53:ListResourceRecordSets",
|
||||
"route53:ListTagsForResource",
|
||||
"route53:ListHealthChecks",
|
||||
"route53:GetHealthCheck",
|
||||
"s3:GetAccelerateConfiguration",
|
||||
"s3:GetAnalyticsConfiguration",
|
||||
"s3:GetBucketAcl",
|
||||
|
@ -207,7 +212,7 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
|||
- [x] aws_route53_record
|
||||
- [x] aws_route53_zone
|
||||
- [ ] aws_route53_delegation_set
|
||||
- [ ] aws_route53_health_check
|
||||
- [x] aws_route53_health_check
|
||||
- [ ] aws_route53_query_log
|
||||
- [ ] aws_route53_vpc_association_authorization
|
||||
- [ ] aws_route53_zone_association
|
||||
|
@ -260,6 +265,7 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
|||
- [x] aws_sqs_queue_policy
|
||||
|
||||
## SNS
|
||||
|
||||
- [x] aws_sns_topic
|
||||
- [x] aws_sns_topic_policy
|
||||
- [x] aws_sns_topic_subscription
|
||||
|
@ -267,6 +273,11 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
|||
- [ ] aws_sns_sms_preferences
|
||||
|
||||
## DynamoDB
|
||||
|
||||
- [x] aws_dynamodb_table
|
||||
- [ ] aws_dynamodb_global_table
|
||||
- [ ] aws_dynamodb_table_item
|
||||
|
||||
## Cloudfront
|
||||
|
||||
- [x] aws_cloudfront_distribution
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,36 @@
|
|||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
cloudfront "github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// CloudfrontRepository is an autogenerated mock type for the CloudfrontRepository type
|
||||
type CloudfrontRepository struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// ListAllDistributions provides a mock function with given fields:
|
||||
func (_m *CloudfrontRepository) ListAllDistributions() ([]*cloudfront.DistributionSummary, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 []*cloudfront.DistributionSummary
|
||||
if rf, ok := ret.Get(0).(func() []*cloudfront.DistributionSummary); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*cloudfront.DistributionSummary)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,37 @@
|
|||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
route53 "github.com/aws/aws-sdk-go/service/route53"
|
||||
)
|
||||
|
||||
// Route53Repository is an autogenerated mock type for the Route53Repository type
|
||||
type Route53Repository struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// ListAllHealthChecks provides a mock function with given fields:
|
||||
func (_m *Route53Repository) ListAllHealthChecks() ([]*route53.HealthCheck, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 []*route53.HealthCheck
|
||||
if rf, ok := ret.Get(0).(func() []*route53.HealthCheck); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*route53.HealthCheck)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
|
@ -1,8 +1,53 @@
|
|||
package alerter
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type Alerts map[string][]Alert
|
||||
|
||||
type Alert struct {
|
||||
Message string `json:"message"`
|
||||
ShouldIgnoreResource bool `json:"-"`
|
||||
type Alert interface {
|
||||
Message() string
|
||||
ShouldIgnoreResource() bool
|
||||
}
|
||||
|
||||
type FakeAlert struct {
|
||||
Msg string
|
||||
IgnoreResource bool
|
||||
}
|
||||
|
||||
func (f *FakeAlert) Message() string {
|
||||
return f.Msg
|
||||
}
|
||||
|
||||
func (f *FakeAlert) ShouldIgnoreResource() bool {
|
||||
return f.IgnoreResource
|
||||
}
|
||||
|
||||
type SerializableAlert struct {
|
||||
Alert
|
||||
}
|
||||
|
||||
type SerializedAlert struct {
|
||||
Msg string `json:"message"`
|
||||
}
|
||||
|
||||
func (u *SerializedAlert) Message() string {
|
||||
return u.Msg
|
||||
}
|
||||
|
||||
func (u *SerializedAlert) ShouldIgnoreResource() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *SerializableAlert) UnmarshalJSON(bytes []byte) error {
|
||||
var res SerializedAlert
|
||||
|
||||
if err := json.Unmarshal(bytes, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Alert = &res
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SerializableAlert) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(SerializedAlert{Msg: s.Message()})
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ func (a *Alerter) IsResourceIgnored(res resource.Resource) bool {
|
|||
|
||||
func (a *Alerter) shouldBeIgnored(alert []Alert) bool {
|
||||
for _, a := range alert {
|
||||
if a.ShouldIgnoreResource {
|
||||
if a.ShouldIgnoreResource() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,18 +23,12 @@ func TestAlerter_Alert(t *testing.T) {
|
|||
name: "TestWithSingleAlert",
|
||||
alerts: Alerts{
|
||||
"fakeres.foobar": []Alert{
|
||||
{
|
||||
Message: "This is an alert",
|
||||
ShouldIgnoreResource: false,
|
||||
},
|
||||
&FakeAlert{"This is an alert", false},
|
||||
},
|
||||
},
|
||||
expected: Alerts{
|
||||
"fakeres.foobar": []Alert{
|
||||
{
|
||||
Message: "This is an alert",
|
||||
ShouldIgnoreResource: false,
|
||||
},
|
||||
&FakeAlert{"This is an alert", false},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -42,38 +36,20 @@ func TestAlerter_Alert(t *testing.T) {
|
|||
name: "TestWithMultipleAlerts",
|
||||
alerts: Alerts{
|
||||
"fakeres.foobar": []Alert{
|
||||
{
|
||||
Message: "This is an alert",
|
||||
ShouldIgnoreResource: false,
|
||||
},
|
||||
{
|
||||
Message: "This is a second alert",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"This is an alert", false},
|
||||
&FakeAlert{"This is a second alert", true},
|
||||
},
|
||||
"fakeres.barfoo": []Alert{
|
||||
{
|
||||
Message: "This is a third alert",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"This is a third alert", true},
|
||||
},
|
||||
},
|
||||
expected: Alerts{
|
||||
"fakeres.foobar": []Alert{
|
||||
{
|
||||
Message: "This is an alert",
|
||||
ShouldIgnoreResource: false,
|
||||
},
|
||||
{
|
||||
Message: "This is a second alert",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"This is an alert", false},
|
||||
&FakeAlert{"This is a second alert", true},
|
||||
},
|
||||
"fakeres.barfoo": []Alert{
|
||||
{
|
||||
Message: "This is a third alert",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"This is a third alert", true},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -116,24 +92,16 @@ func TestAlerter_IgnoreResources(t *testing.T) {
|
|||
name: "TestShouldNotBeIgnoredWithAlerts",
|
||||
alerts: Alerts{
|
||||
"fakeres": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&FakeAlert{"Should not be ignored", false},
|
||||
},
|
||||
"fakeres.foobar": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&FakeAlert{"Should not be ignored", false},
|
||||
},
|
||||
"fakeres.barfoo": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&FakeAlert{"Should not be ignored", false},
|
||||
},
|
||||
"other.resource": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&FakeAlert{"Should not be ignored", false},
|
||||
},
|
||||
},
|
||||
resource: &resource2.FakeResource{
|
||||
|
@ -146,21 +114,13 @@ func TestAlerter_IgnoreResources(t *testing.T) {
|
|||
name: "TestShouldBeIgnoredWithAlertsOnWildcard",
|
||||
alerts: Alerts{
|
||||
"fakeres": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"Should be ignored", true},
|
||||
},
|
||||
"other.foobaz": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"Should be ignored", true},
|
||||
},
|
||||
"other.resource": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&FakeAlert{"Should not be ignored", false},
|
||||
},
|
||||
},
|
||||
resource: &resource2.FakeResource{
|
||||
|
@ -173,21 +133,13 @@ func TestAlerter_IgnoreResources(t *testing.T) {
|
|||
name: "TestShouldBeIgnoredWithAlertsOnResource",
|
||||
alerts: Alerts{
|
||||
"fakeres": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"Should be ignored", true},
|
||||
},
|
||||
"other.foobaz": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&FakeAlert{"Should be ignored", true},
|
||||
},
|
||||
"other.resource": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&FakeAlert{"Should not be ignored", false},
|
||||
},
|
||||
},
|
||||
resource: &resource2.FakeResource{
|
||||
|
|
|
@ -43,13 +43,13 @@ type serializableDifference struct {
|
|||
}
|
||||
|
||||
type serializableAnalysis struct {
|
||||
Summary Summary `json:"summary"`
|
||||
Managed []resource.SerializableResource `json:"managed"`
|
||||
Unmanaged []resource.SerializableResource `json:"unmanaged"`
|
||||
Deleted []resource.SerializableResource `json:"deleted"`
|
||||
Differences []serializableDifference `json:"differences"`
|
||||
Coverage int `json:"coverage"`
|
||||
Alerts alerter.Alerts `json:"alerts"`
|
||||
Summary Summary `json:"summary"`
|
||||
Managed []resource.SerializableResource `json:"managed"`
|
||||
Unmanaged []resource.SerializableResource `json:"unmanaged"`
|
||||
Deleted []resource.SerializableResource `json:"deleted"`
|
||||
Differences []serializableDifference `json:"differences"`
|
||||
Coverage int `json:"coverage"`
|
||||
Alerts map[string][]alerter.SerializableAlert `json:"alerts"`
|
||||
}
|
||||
|
||||
func (a Analysis) MarshalJSON() ([]byte, error) {
|
||||
|
@ -69,9 +69,16 @@ func (a Analysis) MarshalJSON() ([]byte, error) {
|
|||
Changelog: di.Changelog,
|
||||
})
|
||||
}
|
||||
if len(a.alerts) > 0 {
|
||||
bla.Alerts = make(map[string][]alerter.SerializableAlert)
|
||||
for k, v := range a.alerts {
|
||||
for _, al := range v {
|
||||
bla.Alerts[k] = append(bla.Alerts[k], alerter.SerializableAlert{Alert: al})
|
||||
}
|
||||
}
|
||||
}
|
||||
bla.Summary = a.summary
|
||||
bla.Coverage = a.Coverage()
|
||||
bla.Alerts = a.alerts
|
||||
|
||||
return json.Marshal(bla)
|
||||
}
|
||||
|
@ -108,7 +115,16 @@ func (a *Analysis) UnmarshalJSON(bytes []byte) error {
|
|||
Changelog: di.Changelog,
|
||||
})
|
||||
}
|
||||
a.SetAlerts(bla.Alerts)
|
||||
if len(bla.Alerts) > 0 {
|
||||
a.alerts = make(alerter.Alerts)
|
||||
for k, v := range bla.Alerts {
|
||||
for _, al := range v {
|
||||
a.alerts[k] = append(a.alerts[k], &alerter.SerializedAlert{
|
||||
Msg: al.Message(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,34 @@ import (
|
|||
"github.com/r3labs/diff/v2"
|
||||
)
|
||||
|
||||
type UnmanagedSecurityGroupRulesAlert struct{}
|
||||
|
||||
func newUnmanagedSecurityGroupRulesAlert() *UnmanagedSecurityGroupRulesAlert {
|
||||
return &UnmanagedSecurityGroupRulesAlert{}
|
||||
}
|
||||
|
||||
func (u *UnmanagedSecurityGroupRulesAlert) Message() string {
|
||||
return "You have unmanaged security group rules that could be false positives, find out more at https://github.com/cloudskiff/driftctl/blob/main/doc/LIMITATIONS.md#terraform-resources"
|
||||
}
|
||||
|
||||
func (u *UnmanagedSecurityGroupRulesAlert) ShouldIgnoreResource() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type ComputedDiffAlert struct{}
|
||||
|
||||
func NewComputedDiffAlert() *ComputedDiffAlert {
|
||||
return &ComputedDiffAlert{}
|
||||
}
|
||||
|
||||
func (c *ComputedDiffAlert) Message() string {
|
||||
return "You have diffs on computed fields, check the documentation for potential false positive drifts"
|
||||
}
|
||||
|
||||
func (c *ComputedDiffAlert) ShouldIgnoreResource() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type Analyzer struct {
|
||||
alerter *alerter.Alerter
|
||||
}
|
||||
|
@ -80,17 +108,11 @@ func (a Analyzer) Analyze(remoteResources, resourcesFromState []resource.Resourc
|
|||
}
|
||||
|
||||
if a.hasUnmanagedSecurityGroupRules(filteredRemoteResource) {
|
||||
a.alerter.SendAlert("",
|
||||
alerter.Alert{
|
||||
Message: "You have unmanaged security group rules that could be false positives, find out more at https://github.com/cloudskiff/driftctl/blob/main/doc/LIMITATIONS.md#terraform-resources",
|
||||
})
|
||||
a.alerter.SendAlert("", newUnmanagedSecurityGroupRulesAlert())
|
||||
}
|
||||
|
||||
if haveComputedDiff {
|
||||
a.alerter.SendAlert("",
|
||||
alerter.Alert{
|
||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
||||
})
|
||||
a.alerter.SendAlert("", NewComputedDiffAlert())
|
||||
}
|
||||
|
||||
// Add remaining unmanaged resources
|
||||
|
|
|
@ -272,9 +272,7 @@ func TestAnalyze(t *testing.T) {
|
|||
},
|
||||
alerts: alerter.Alerts{
|
||||
"": {
|
||||
{
|
||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
||||
},
|
||||
NewComputedDiffAlert(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -351,9 +349,7 @@ func TestAnalyze(t *testing.T) {
|
|||
},
|
||||
alerts: alerter.Alerts{
|
||||
"": {
|
||||
{
|
||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
||||
},
|
||||
NewComputedDiffAlert(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -520,21 +516,13 @@ func TestAnalyze(t *testing.T) {
|
|||
},
|
||||
alerts: alerter.Alerts{
|
||||
"fakeres": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||
},
|
||||
"other.foobaz": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||
},
|
||||
"other.resource": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&alerter.FakeAlert{Msg: "Should not be ignored"},
|
||||
},
|
||||
},
|
||||
expected: Analysis{
|
||||
|
@ -656,26 +644,16 @@ func TestAnalyze(t *testing.T) {
|
|||
},
|
||||
alerts: alerter.Alerts{
|
||||
"fakeres": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||
},
|
||||
"other.foobaz": {
|
||||
{
|
||||
Message: "Should be ignored",
|
||||
ShouldIgnoreResource: true,
|
||||
},
|
||||
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||
},
|
||||
"other.resource": {
|
||||
{
|
||||
Message: "Should not be ignored",
|
||||
},
|
||||
&alerter.FakeAlert{Msg: "Should not be ignored"},
|
||||
},
|
||||
"": {
|
||||
{
|
||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
||||
},
|
||||
NewComputedDiffAlert(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -875,9 +853,7 @@ func TestAnalyze(t *testing.T) {
|
|||
},
|
||||
alerts: alerter.Alerts{
|
||||
"": {
|
||||
{
|
||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
||||
},
|
||||
NewComputedDiffAlert(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -916,9 +892,7 @@ func TestAnalyze(t *testing.T) {
|
|||
},
|
||||
alerts: alerter.Alerts{
|
||||
"": {
|
||||
{
|
||||
Message: "You have unmanaged security group rules that could be false positives, find out more at https://github.com/cloudskiff/driftctl/blob/main/doc/LIMITATIONS.md#terraform-resources",
|
||||
},
|
||||
newUnmanagedSecurityGroupRulesAlert(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1069,9 +1043,7 @@ func TestAnalysis_MarshalJSON(t *testing.T) {
|
|||
})
|
||||
analysis.SetAlerts(alerter.Alerts{
|
||||
"aws_iam_access_key": {
|
||||
{
|
||||
Message: "This is an alert",
|
||||
},
|
||||
&alerter.FakeAlert{Msg: "This is an alert"},
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -1151,8 +1123,8 @@ func TestAnalysis_UnmarshalJSON(t *testing.T) {
|
|||
},
|
||||
alerts: alerter.Alerts{
|
||||
"aws_iam_access_key": {
|
||||
{
|
||||
Message: "This is an alert",
|
||||
&alerter.SerializedAlert{
|
||||
Msg: "This is an alert",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1174,4 +1146,6 @@ func TestAnalysis_UnmarshalJSON(t *testing.T) {
|
|||
assert.Equal(t, 2, got.Summary().TotalDeleted)
|
||||
assert.Equal(t, 6, got.Summary().TotalResources)
|
||||
assert.Equal(t, 1, got.Summary().TotalDrifted)
|
||||
assert.Len(t, got.alerts, 1)
|
||||
assert.Equal(t, got.alerts["aws_iam_access_key"][0].Message(), "This is an alert")
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/remote"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/fatih/color"
|
||||
|
@ -93,12 +95,21 @@ func (c *Console) Write(analysis *analyser.Analysis) error {
|
|||
|
||||
c.writeSummary(analysis)
|
||||
|
||||
policy := false
|
||||
for _, alerts := range analysis.Alerts() {
|
||||
for _, alert := range alerts {
|
||||
fmt.Printf("%s\n", color.YellowString(alert.Message))
|
||||
fmt.Printf("%s\n", color.YellowString(alert.Message()))
|
||||
|
||||
if _, ok := alert.(*remote.EnumerationAccessDeniedAlert); ok {
|
||||
policy = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if policy {
|
||||
fmt.Println(color.YellowString("\nThe latest minimal read-only policy for driftctl is always available here, please update yours: https://github.com/cloudskiff/driftctl/blob/main/doc/cmd/scan/supported_resources/aws.md"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,12 @@ func TestConsole_Write(t *testing.T) {
|
|||
args: args{analysis: fakeAnalysisWithComputedFields()},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test console output with enumeration alerts",
|
||||
goldenfile: "output_access_denied_alert.txt",
|
||||
args: args{analysis: fakeAnalysisWithEnumerationError()},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -38,6 +38,14 @@ func TestJSON_Write(t *testing.T) {
|
|||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test json output with enumeration alerts",
|
||||
goldenfile: "output_access_denied_alert.json",
|
||||
args: args{
|
||||
analysis: fakeAnalysisWithEnumerationError(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote"
|
||||
testresource "github.com/cloudskiff/driftctl/test/resource"
|
||||
"github.com/r3labs/diff/v2"
|
||||
)
|
||||
|
@ -230,9 +231,19 @@ func fakeAnalysisWithComputedFields() *analyser.Analysis {
|
|||
}})
|
||||
a.SetAlerts(alerter.Alerts{
|
||||
"": []alerter.Alert{
|
||||
{
|
||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
||||
},
|
||||
analyser.NewComputedDiffAlert(),
|
||||
},
|
||||
})
|
||||
return &a
|
||||
}
|
||||
|
||||
func fakeAnalysisWithEnumerationError() *analyser.Analysis {
|
||||
a := analyser.Analysis{}
|
||||
a.SetAlerts(alerter.Alerts{
|
||||
"": []alerter.Alert{
|
||||
remote.NewEnumerationAccessDeniedAlert("aws_vpc", "aws_vpc"),
|
||||
remote.NewEnumerationAccessDeniedAlert("aws_sqs", "aws_sqs"),
|
||||
remote.NewEnumerationAccessDeniedAlert("aws_sns", "aws_sns"),
|
||||
},
|
||||
})
|
||||
return &a
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"summary": {
|
||||
"total_resources": 0,
|
||||
"total_drifted": 0,
|
||||
"total_unmanaged": 0,
|
||||
"total_deleted": 0,
|
||||
"total_managed": 0
|
||||
},
|
||||
"managed": null,
|
||||
"unmanaged": null,
|
||||
"deleted": null,
|
||||
"differences": null,
|
||||
"coverage": 0,
|
||||
"alerts": {
|
||||
"": [
|
||||
{
|
||||
"message": "Ignoring aws_vpc from drift calculation: Listing aws_vpc is forbidden."
|
||||
},
|
||||
{
|
||||
"message": "Ignoring aws_sqs from drift calculation: Listing aws_sqs is forbidden."
|
||||
},
|
||||
{
|
||||
"message": "Ignoring aws_sns from drift calculation: Listing aws_sns is forbidden."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
Found 0 resource(s)
|
||||
- 0% coverage
|
||||
Congrats! Your infrastructure is fully in sync.
|
||||
Ignoring aws_vpc from drift calculation: Listing aws_vpc is forbidden.
|
||||
Ignoring aws_sqs from drift calculation: Listing aws_sqs is forbidden.
|
||||
Ignoring aws_sns from drift calculation: Listing aws_sns is forbidden.
|
||||
|
||||
The latest minimal read-only policy for driftctl is always available here, please update yours: https://github.com/cloudskiff/driftctl/blob/main/doc/cmd/scan/supported_resources/aws.md
|
|
@ -54,6 +54,8 @@ func Deserializers() []deserializer.CTYDeserializer {
|
|||
awsdeserializer.NewSNSTopicPolicyDeserializer(),
|
||||
awsdeserializer.NewSNSTopicSubscriptionDeserializer(),
|
||||
awsdeserializer.NewDynamoDBTableDeserializer(),
|
||||
awsdeserializer.NewRoute53HealthCheckDeserializer(),
|
||||
awsdeserializer.NewCloudfrontDistributionDeserializer(),
|
||||
|
||||
ghdeserializer.NewGithubRepositoryDeserializer(),
|
||||
}
|
||||
|
|
|
@ -81,6 +81,8 @@ func TestTerraformStateReader_AWS_Resources(t *testing.T) {
|
|||
{name: "SNS Topic Policy", dirName: "sns_topic_policy", wantErr: false},
|
||||
{name: "SNS Topic Subscription", dirName: "sns_topic_subscription", wantErr: false},
|
||||
{name: "DynamoDB table", dirName: "dynamodb_table", wantErr: false},
|
||||
{name: "Route53 Health Check", dirName: "route53_health_check", wantErr: false},
|
||||
{name: "Cloudfront distribution", dirName: "cloudfront_distribution", wantErr: false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
[
|
||||
{
|
||||
"Aliases": null,
|
||||
"Arn": "arn:aws:cloudfront::047081014315:distribution/E1M9CNS0XSHI19",
|
||||
"CallerReference": "terraform-20210216101734792900000001",
|
||||
"Comment": null,
|
||||
"DefaultRootObject": "",
|
||||
"DomainName": "d1g0dw0i1wvlgd.cloudfront.net",
|
||||
"Enabled": false,
|
||||
"Etag": "E2CKBANLXUPWGQ",
|
||||
"HostedZoneId": "Z2FDTNDATAQYW2",
|
||||
"HttpVersion": "http2",
|
||||
"Id": "E1M9CNS0XSHI19",
|
||||
"InProgressValidationBatches": 0,
|
||||
"IsIpv6Enabled": false,
|
||||
"LastModifiedTime": "2021-02-16 10:17:35.404 +0000 UTC",
|
||||
"PriceClass": "PriceClass_All",
|
||||
"RetainOnDelete": false,
|
||||
"Status": "Deployed",
|
||||
"Tags": {},
|
||||
"TrustedSigners": [
|
||||
{
|
||||
"Enabled": false,
|
||||
"Items": []
|
||||
}
|
||||
],
|
||||
"WaitForDeployment": true,
|
||||
"WebAclId": "",
|
||||
"CustomErrorResponse": [],
|
||||
"DefaultCacheBehavior": [
|
||||
{
|
||||
"AllowedMethods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"CachedMethods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"Compress": false,
|
||||
"DefaultTtl": 86400,
|
||||
"FieldLevelEncryptionId": "",
|
||||
"MaxTtl": 31536000,
|
||||
"MinTtl": 0,
|
||||
"SmoothStreaming": false,
|
||||
"TargetOriginId": "S3-foo-cloudfront",
|
||||
"TrustedSigners": [],
|
||||
"ViewerProtocolPolicy": "allow-all",
|
||||
"ForwardedValues": [
|
||||
{
|
||||
"Headers": null,
|
||||
"QueryString": false,
|
||||
"QueryStringCacheKeys": [],
|
||||
"Cookies": [
|
||||
{
|
||||
"Forward": "none",
|
||||
"WhitelistedNames": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"LambdaFunctionAssociation": []
|
||||
}
|
||||
],
|
||||
"LoggingConfig": [],
|
||||
"OrderedCacheBehavior": [],
|
||||
"Origin": [
|
||||
{
|
||||
"DomainName": "foo-cloudfront.s3.eu-west-3.amazonaws.com",
|
||||
"OriginId": "S3-foo-cloudfront",
|
||||
"OriginPath": "",
|
||||
"CustomHeader": [],
|
||||
"CustomOriginConfig": [],
|
||||
"S3OriginConfig": []
|
||||
}
|
||||
],
|
||||
"OriginGroup": null,
|
||||
"Restrictions": [
|
||||
{
|
||||
"GeoRestriction": [
|
||||
{
|
||||
"Locations": null,
|
||||
"RestrictionType": "none"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"ViewerCertificate": [
|
||||
{
|
||||
"AcmCertificateArn": "",
|
||||
"CloudfrontDefaultCertificate": true,
|
||||
"IamCertificateId": "",
|
||||
"MinimumProtocolVersion": "TLSv1",
|
||||
"SslSupportMethod": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,121 @@
|
|||
{
|
||||
"version": 4,
|
||||
"terraform_version": "0.14.5",
|
||||
"serial": 596,
|
||||
"lineage": "cc4be827-a907-1623-961b-0fc1ce33973e",
|
||||
"outputs": {},
|
||||
"resources": [
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_cloudfront_distribution",
|
||||
"name": "foo_distribution",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 1,
|
||||
"attributes": {
|
||||
"aliases": null,
|
||||
"arn": "arn:aws:cloudfront::047081014315:distribution/E1M9CNS0XSHI19",
|
||||
"caller_reference": "terraform-20210216101734792900000001",
|
||||
"comment": null,
|
||||
"custom_error_response": [],
|
||||
"default_cache_behavior": [
|
||||
{
|
||||
"allowed_methods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"cached_methods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"compress": false,
|
||||
"default_ttl": 86400,
|
||||
"field_level_encryption_id": "",
|
||||
"forwarded_values": [
|
||||
{
|
||||
"cookies": [
|
||||
{
|
||||
"forward": "none",
|
||||
"whitelisted_names": null
|
||||
}
|
||||
],
|
||||
"headers": null,
|
||||
"query_string": false,
|
||||
"query_string_cache_keys": []
|
||||
}
|
||||
],
|
||||
"lambda_function_association": [],
|
||||
"max_ttl": 31536000,
|
||||
"min_ttl": 0,
|
||||
"smooth_streaming": false,
|
||||
"target_origin_id": "S3-foo-cloudfront",
|
||||
"trusted_signers": [],
|
||||
"viewer_protocol_policy": "allow-all"
|
||||
}
|
||||
],
|
||||
"default_root_object": "",
|
||||
"domain_name": "d1g0dw0i1wvlgd.cloudfront.net",
|
||||
"enabled": false,
|
||||
"etag": "E2CKBANLXUPWGQ",
|
||||
"hosted_zone_id": "Z2FDTNDATAQYW2",
|
||||
"http_version": "http2",
|
||||
"id": "E1M9CNS0XSHI19",
|
||||
"in_progress_validation_batches": 0,
|
||||
"is_ipv6_enabled": false,
|
||||
"last_modified_time": "2021-02-16 10:17:35.404 +0000 UTC",
|
||||
"logging_config": [],
|
||||
"ordered_cache_behavior": [],
|
||||
"origin": [
|
||||
{
|
||||
"custom_header": [],
|
||||
"custom_origin_config": [],
|
||||
"domain_name": "foo-cloudfront.s3.eu-west-3.amazonaws.com",
|
||||
"origin_id": "S3-foo-cloudfront",
|
||||
"origin_path": "",
|
||||
"s3_origin_config": []
|
||||
}
|
||||
],
|
||||
"origin_group": [],
|
||||
"price_class": "PriceClass_All",
|
||||
"restrictions": [
|
||||
{
|
||||
"geo_restriction": [
|
||||
{
|
||||
"locations": null,
|
||||
"restriction_type": "none"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"retain_on_delete": false,
|
||||
"status": "Deployed",
|
||||
"tags": {},
|
||||
"trusted_signers": [
|
||||
{
|
||||
"enabled": false,
|
||||
"items": []
|
||||
}
|
||||
],
|
||||
"viewer_certificate": [
|
||||
{
|
||||
"acm_certificate_arn": "",
|
||||
"cloudfront_default_certificate": true,
|
||||
"iam_certificate_id": "",
|
||||
"minimum_protocol_version": "TLSv1",
|
||||
"ssl_support_method": ""
|
||||
}
|
||||
],
|
||||
"wait_for_deployment": true,
|
||||
"web_acl_id": ""
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==",
|
||||
"dependencies": [
|
||||
"aws_s3_bucket.foo_cloudfront"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
[
|
||||
{
|
||||
"ChildHealthThreshold": 0,
|
||||
"ChildHealthchecks": [],
|
||||
"CloudwatchAlarmName": null,
|
||||
"CloudwatchAlarmRegion": null,
|
||||
"Disabled": false,
|
||||
"EnableSni": false,
|
||||
"FailureThreshold": 5,
|
||||
"Fqdn": "moadib.net",
|
||||
"Id": "70994c67-b616-4caa-89bc-557153b65845",
|
||||
"InsufficientDataHealthStatus": "",
|
||||
"InvertHealthcheck": false,
|
||||
"IpAddress": "",
|
||||
"MeasureLatency": false,
|
||||
"Port": 80,
|
||||
"ReferenceName": null,
|
||||
"Regions": [],
|
||||
"RequestInterval": 30,
|
||||
"ResourcePath": "/",
|
||||
"SearchString": "",
|
||||
"Tags": {
|
||||
"Name": "tf-test-health-check"
|
||||
},
|
||||
"Type": "HTTP"
|
||||
},
|
||||
{
|
||||
"ChildHealthThreshold": 0,
|
||||
"ChildHealthchecks": [],
|
||||
"CloudwatchAlarmName": null,
|
||||
"CloudwatchAlarmRegion": null,
|
||||
"Disabled": false,
|
||||
"EnableSni": true,
|
||||
"FailureThreshold": 5,
|
||||
"Fqdn": "moadib.net",
|
||||
"Id": "45b0a22b-c9db-4271-96b3-23ac49debbf3",
|
||||
"InsufficientDataHealthStatus": "",
|
||||
"InvertHealthcheck": false,
|
||||
"IpAddress": "",
|
||||
"MeasureLatency": false,
|
||||
"Port": 443,
|
||||
"ReferenceName": null,
|
||||
"Regions": [],
|
||||
"RequestInterval": 30,
|
||||
"ResourcePath": "/",
|
||||
"SearchString": "MoAdiB",
|
||||
"Tags": null,
|
||||
"Type": "HTTPS_STR_MATCH"
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"version": 4,
|
||||
"terraform_version": "0.14.5",
|
||||
"serial": 72,
|
||||
"lineage": "30081725-54a2-ce02-6ff5-45c4d961c652",
|
||||
"outputs": {},
|
||||
"resources": [
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_route53_health_check",
|
||||
"name": "http",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"child_health_threshold": 0,
|
||||
"child_healthchecks": null,
|
||||
"cloudwatch_alarm_name": null,
|
||||
"cloudwatch_alarm_region": null,
|
||||
"disabled": false,
|
||||
"enable_sni": false,
|
||||
"failure_threshold": 5,
|
||||
"fqdn": "moadib.net",
|
||||
"id": "70994c67-b616-4caa-89bc-557153b65845",
|
||||
"insufficient_data_health_status": "",
|
||||
"invert_healthcheck": false,
|
||||
"ip_address": "",
|
||||
"measure_latency": false,
|
||||
"port": 80,
|
||||
"reference_name": null,
|
||||
"regions": null,
|
||||
"request_interval": 30,
|
||||
"resource_path": "/",
|
||||
"search_string": "",
|
||||
"tags": {
|
||||
"Name": "tf-test-health-check"
|
||||
},
|
||||
"type": "HTTP"
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "bnVsbA=="
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_route53_health_check",
|
||||
"name": "https",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"child_health_threshold": 0,
|
||||
"child_healthchecks": null,
|
||||
"cloudwatch_alarm_name": null,
|
||||
"cloudwatch_alarm_region": null,
|
||||
"disabled": false,
|
||||
"enable_sni": true,
|
||||
"failure_threshold": 5,
|
||||
"fqdn": "moadib.net",
|
||||
"id": "45b0a22b-c9db-4271-96b3-23ac49debbf3",
|
||||
"insufficient_data_health_status": "",
|
||||
"invert_healthcheck": false,
|
||||
"ip_address": "",
|
||||
"measure_latency": false,
|
||||
"port": 443,
|
||||
"reference_name": null,
|
||||
"regions": null,
|
||||
"request_interval": 30,
|
||||
"resource_path": "/",
|
||||
"search_string": "MoAdiB",
|
||||
"tags": null,
|
||||
"type": "HTTPS_STR_MATCH"
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "bnVsbA=="
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -10,6 +10,23 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type invalidRouteAlert struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func newInvalidRouteAlert(awsRouteTableResourceType, tableId string) *invalidRouteAlert {
|
||||
message := fmt.Sprintf("Skipped invalid route found in state for %s.%s", awsRouteTableResourceType, tableId)
|
||||
return &invalidRouteAlert{message}
|
||||
}
|
||||
|
||||
func (i *invalidRouteAlert) Message() string {
|
||||
return i.message
|
||||
}
|
||||
|
||||
func (i *invalidRouteAlert) ShouldIgnoreResource() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Explodes routes found in aws_default_route_table.route and aws_route_table.route to dedicated resources
|
||||
type AwsRouteTableExpander struct {
|
||||
alerter alerter.AlerterInterface
|
||||
|
@ -60,9 +77,7 @@ func (m *AwsRouteTableExpander) handleTable(table *aws.AwsRouteTable, results *[
|
|||
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),
|
||||
})
|
||||
m.alerter.SendAlert(aws.AwsRouteTableResourceType, newInvalidRouteAlert(aws.AwsRouteTableResourceType, table.Id))
|
||||
continue
|
||||
}
|
||||
newRouteFromTable := &aws.AwsRoute{
|
||||
|
@ -107,9 +122,7 @@ func (m *AwsRouteTableExpander) handleDefaultTable(table *aws.AwsDefaultRouteTab
|
|||
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),
|
||||
})
|
||||
m.alerter.SendAlert(aws.AwsDefaultRouteTableResourceType, newInvalidRouteAlert(aws.AwsDefaultRouteTableResourceType, table.Id))
|
||||
continue
|
||||
}
|
||||
newRouteFromTable := &aws.AwsRoute{
|
||||
|
|
|
@ -7,7 +7,6 @@ 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"
|
||||
|
@ -215,12 +214,12 @@ 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",
|
||||
})
|
||||
mockedAlerter.On("SendAlert", aws.AwsRouteTableResourceType, newInvalidRouteAlert(
|
||||
"aws_route_table", "table_from_state",
|
||||
))
|
||||
mockedAlerter.On("SendAlert", aws.AwsDefaultRouteTableResourceType, newInvalidRouteAlert(
|
||||
"aws_default_route_table", "default_table_from_state",
|
||||
))
|
||||
|
||||
input := []resource.Resource{
|
||||
&aws.AwsRouteTable{
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
type CloudfrontDistributionSupplier struct {
|
||||
reader terraform.ResourceReader
|
||||
deserializer deserializer.CTYDeserializer
|
||||
client repository.CloudfrontRepository
|
||||
runner *terraform.ParallelResourceReader
|
||||
}
|
||||
|
||||
func NewCloudfrontDistributionSupplier(provider *AWSTerraformProvider) *CloudfrontDistributionSupplier {
|
||||
return &CloudfrontDistributionSupplier{
|
||||
provider,
|
||||
awsdeserializer.NewCloudfrontDistributionDeserializer(),
|
||||
repository.NewCloudfrontClient(provider.session),
|
||||
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
|
||||
}
|
||||
}
|
||||
|
||||
func (s CloudfrontDistributionSupplier) Resources() ([]resource.Resource, error) {
|
||||
distributions, err := s.client.ListAllDistributions()
|
||||
if err != nil {
|
||||
return nil, remoteerror.NewResourceEnumerationError(err, aws.AwsCloudfrontDistributionResourceType)
|
||||
}
|
||||
|
||||
for _, distribution := range distributions {
|
||||
d := *distribution
|
||||
s.runner.Run(func() (cty.Value, error) {
|
||||
return s.readCloudfrontDistribution(d)
|
||||
})
|
||||
}
|
||||
|
||||
resources, err := s.runner.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.deserializer.Deserialize(resources)
|
||||
}
|
||||
|
||||
func (s CloudfrontDistributionSupplier) readCloudfrontDistribution(distribution cloudfront.DistributionSummary) (cty.Value, error) {
|
||||
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
|
||||
ID: *distribution.Id,
|
||||
Ty: aws.AwsCloudfrontDistributionResourceType,
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return cty.NilVal, err
|
||||
}
|
||||
return *val, nil
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
|
||||
"github.com/cloudskiff/driftctl/mocks"
|
||||
"github.com/cloudskiff/driftctl/pkg/parallel"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
"github.com/cloudskiff/driftctl/test"
|
||||
"github.com/cloudskiff/driftctl/test/goldenfile"
|
||||
testmocks "github.com/cloudskiff/driftctl/test/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestCloudfrontDistributionSupplier_Resources(t *testing.T) {
|
||||
cases := []struct {
|
||||
test string
|
||||
dirName string
|
||||
mocks func(client *mocks.CloudfrontRepository)
|
||||
err error
|
||||
}{
|
||||
{
|
||||
test: "no cloudfront distribution",
|
||||
dirName: "cloudfront_distribution_empty",
|
||||
mocks: func(client *mocks.CloudfrontRepository) {
|
||||
client.On("ListAllDistributions").Return([]*cloudfront.DistributionSummary{}, nil)
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
test: "one cloudfront distribution",
|
||||
dirName: "cloudfront_distribution_one",
|
||||
mocks: func(client *mocks.CloudfrontRepository) {
|
||||
client.On("ListAllDistributions").Return([]*cloudfront.DistributionSummary{
|
||||
{Id: aws.String("E1M9CNS0XSHI19")},
|
||||
}, nil)
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
test: "cannot list cloudfront distributions",
|
||||
dirName: "cloudfront_distribution_empty",
|
||||
mocks: func(client *mocks.CloudfrontRepository) {
|
||||
client.On("ListAllDistributions").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
|
||||
},
|
||||
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsCloudfrontDistributionResourceType),
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
shouldUpdate := c.dirName == *goldenfile.Update
|
||||
providerLibrary := terraform.NewProviderLibrary()
|
||||
supplierLibrary := resource.NewSupplierLibrary()
|
||||
|
||||
if shouldUpdate {
|
||||
provider, err := InitTestAwsProvider(providerLibrary)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
supplierLibrary.AddSupplier(NewCloudfrontDistributionSupplier(provider))
|
||||
}
|
||||
|
||||
t.Run(c.test, func(tt *testing.T) {
|
||||
fakeCloudfront := mocks.CloudfrontRepository{}
|
||||
c.mocks(&fakeCloudfront)
|
||||
provider := testmocks.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
|
||||
cloudfrontDistributionDeserializer := awsdeserializer.NewCloudfrontDistributionDeserializer()
|
||||
s := &CloudfrontDistributionSupplier{
|
||||
provider,
|
||||
cloudfrontDistributionDeserializer,
|
||||
&fakeCloudfront,
|
||||
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
|
||||
}
|
||||
got, err := s.Resources()
|
||||
assert.Equal(tt, c.err, err)
|
||||
|
||||
mock.AssertExpectationsForObjects(tt)
|
||||
deserializers := []deserializer.CTYDeserializer{cloudfrontDistributionDeserializer}
|
||||
test.CtyTestDiffMixed(got, c.dirName, provider, deserializers, shouldUpdate, tt)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -67,6 +67,8 @@ func Init(alerter *alerter.Alerter, providerLibrary *terraform.ProviderLibrary,
|
|||
supplierLibrary.AddSupplier(NewSNSTopicPolicySupplier(provider))
|
||||
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider))
|
||||
supplierLibrary.AddSupplier(NewDynamoDBTableSupplier(provider))
|
||||
supplierLibrary.AddSupplier(NewRoute53HealthCheckSupplier(provider))
|
||||
supplierLibrary.AddSupplier(NewCloudfrontDistributionSupplier(provider))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront/cloudfrontiface"
|
||||
)
|
||||
|
||||
type CloudfrontRepository interface {
|
||||
ListAllDistributions() ([]*cloudfront.DistributionSummary, error)
|
||||
}
|
||||
|
||||
type cloudfrontRepository struct {
|
||||
client cloudfrontiface.CloudFrontAPI
|
||||
}
|
||||
|
||||
func NewCloudfrontClient(session *session.Session) *cloudfrontRepository {
|
||||
return &cloudfrontRepository{
|
||||
cloudfront.New(session),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *cloudfrontRepository) ListAllDistributions() ([]*cloudfront.DistributionSummary, error) {
|
||||
var distributions []*cloudfront.DistributionSummary
|
||||
input := cloudfront.ListDistributionsInput{}
|
||||
err := r.client.ListDistributionsPages(&input,
|
||||
func(resp *cloudfront.ListDistributionsOutput, lastPage bool) bool {
|
||||
if resp.DistributionList != nil {
|
||||
distributions = append(distributions, resp.DistributionList.Items...)
|
||||
}
|
||||
return !lastPage
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return distributions, nil
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/cloudskiff/driftctl/mocks"
|
||||
"github.com/r3labs/diff/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_cloudfrontRepository_ListAllDistributions(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mocks func(client *mocks.CloudfrontClient)
|
||||
want []*cloudfront.DistributionSummary
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "list multiple distributions",
|
||||
mocks: func(client *mocks.CloudfrontClient) {
|
||||
client.On("ListDistributionsPages",
|
||||
&cloudfront.ListDistributionsInput{},
|
||||
mock.MatchedBy(func(callback func(res *cloudfront.ListDistributionsOutput, lastPage bool) bool) bool {
|
||||
callback(&cloudfront.ListDistributionsOutput{
|
||||
DistributionList: &cloudfront.DistributionList{
|
||||
Items: []*cloudfront.DistributionSummary{
|
||||
{Id: aws.String("distribution1")},
|
||||
{Id: aws.String("distribution2")},
|
||||
{Id: aws.String("distribution3")},
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
callback(&cloudfront.ListDistributionsOutput{
|
||||
DistributionList: &cloudfront.DistributionList{
|
||||
Items: []*cloudfront.DistributionSummary{
|
||||
{Id: aws.String("distribution4")},
|
||||
{Id: aws.String("distribution5")},
|
||||
{Id: aws.String("distribution6")},
|
||||
},
|
||||
},
|
||||
}, true)
|
||||
return true
|
||||
})).Return(nil)
|
||||
},
|
||||
want: []*cloudfront.DistributionSummary{
|
||||
{Id: aws.String("distribution1")},
|
||||
{Id: aws.String("distribution2")},
|
||||
{Id: aws.String("distribution3")},
|
||||
{Id: aws.String("distribution4")},
|
||||
{Id: aws.String("distribution5")},
|
||||
{Id: aws.String("distribution6")},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &mocks.CloudfrontClient{}
|
||||
tt.mocks(client)
|
||||
r := &cloudfrontRepository{
|
||||
client: client,
|
||||
}
|
||||
got, err := r.ListAllDistributions()
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
changelog, err := diff.Diff(got, tt.want)
|
||||
assert.Nil(t, err)
|
||||
if len(changelog) > 0 {
|
||||
for _, change := range changelog {
|
||||
t.Errorf("%s: %s -> %s", strings.Join(change.Path, "."), change.From, change.To)
|
||||
}
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"github.com/aws/aws-sdk-go/service/route53/route53iface"
|
||||
)
|
||||
|
||||
type Route53Repository interface {
|
||||
ListAllHealthChecks() ([]*route53.HealthCheck, error)
|
||||
}
|
||||
|
||||
type route53Repository struct {
|
||||
client route53iface.Route53API
|
||||
}
|
||||
|
||||
func NewRoute53Repository(session *session.Session) *route53Repository {
|
||||
return &route53Repository{
|
||||
route53.New(session),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *route53Repository) ListAllHealthChecks() ([]*route53.HealthCheck, error) {
|
||||
var tables []*route53.HealthCheck
|
||||
input := &route53.ListHealthChecksInput{}
|
||||
err := r.client.ListHealthChecksPages(input, func(res *route53.ListHealthChecksOutput, lastPage bool) bool {
|
||||
tables = append(tables, res.HealthChecks...)
|
||||
return !lastPage
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tables, nil
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/cloudskiff/driftctl/mocks"
|
||||
"github.com/r3labs/diff/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_route53Repository_ListAllHealthChecks(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mocks func(client *mocks.Route53Client)
|
||||
want []*route53.HealthCheck
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "List with 2 pages",
|
||||
mocks: func(client *mocks.Route53Client) {
|
||||
client.On("ListHealthChecksPages",
|
||||
&route53.ListHealthChecksInput{},
|
||||
mock.MatchedBy(func(callback func(res *route53.ListHealthChecksOutput, lastPage bool) bool) bool {
|
||||
callback(&route53.ListHealthChecksOutput{
|
||||
HealthChecks: []*route53.HealthCheck{
|
||||
{Id: aws.String("1")},
|
||||
{Id: aws.String("2")},
|
||||
{Id: aws.String("3")},
|
||||
},
|
||||
}, false)
|
||||
callback(&route53.ListHealthChecksOutput{
|
||||
HealthChecks: []*route53.HealthCheck{
|
||||
{Id: aws.String("4")},
|
||||
{Id: aws.String("5")},
|
||||
{Id: aws.String("6")},
|
||||
},
|
||||
}, true)
|
||||
return true
|
||||
})).Return(nil)
|
||||
},
|
||||
want: []*route53.HealthCheck{
|
||||
{Id: aws.String("1")},
|
||||
{Id: aws.String("2")},
|
||||
{Id: aws.String("3")},
|
||||
{Id: aws.String("4")},
|
||||
{Id: aws.String("5")},
|
||||
{Id: aws.String("6")},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &mocks.Route53Client{}
|
||||
tt.mocks(client)
|
||||
r := &route53Repository{
|
||||
client: client,
|
||||
}
|
||||
got, err := r.ListAllHealthChecks()
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
changelog, err := diff.Diff(got, tt.want)
|
||||
assert.Nil(t, err)
|
||||
if len(changelog) > 0 {
|
||||
for _, change := range changelog {
|
||||
t.Errorf("%s: %s -> %s", strings.Join(change.Path, "."), change.From, change.To)
|
||||
}
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/aws/repository"
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
)
|
||||
|
||||
type Route53HealthCheckSupplier struct {
|
||||
reader terraform.ResourceReader
|
||||
deserializer deserializer.CTYDeserializer
|
||||
client repository.Route53Repository
|
||||
runner *terraform.ParallelResourceReader
|
||||
}
|
||||
|
||||
func NewRoute53HealthCheckSupplier(provider *AWSTerraformProvider) *Route53HealthCheckSupplier {
|
||||
return &Route53HealthCheckSupplier{
|
||||
provider,
|
||||
awsdeserializer.NewRoute53HealthCheckDeserializer(),
|
||||
repository.NewRoute53Repository(provider.session),
|
||||
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
|
||||
}
|
||||
}
|
||||
|
||||
func (s Route53HealthCheckSupplier) Resources() ([]resource.Resource, error) {
|
||||
healthChecks, err := s.client.ListAllHealthChecks()
|
||||
if err != nil {
|
||||
return nil, remoteerror.NewResourceEnumerationError(err, aws.AwsRoute53HealthCheckResourceType)
|
||||
}
|
||||
|
||||
for _, healthCheck := range healthChecks {
|
||||
healthCheck := healthCheck
|
||||
s.runner.Run(func() (cty.Value, error) {
|
||||
return s.readHealthCheck(healthCheck)
|
||||
})
|
||||
}
|
||||
|
||||
retrieve, err := s.runner.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.deserializer.Deserialize(retrieve)
|
||||
}
|
||||
|
||||
func (s Route53HealthCheckSupplier) readHealthCheck(healthCheck *route53.HealthCheck) (cty.Value, error) {
|
||||
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
|
||||
ID: *healthCheck.Id,
|
||||
Ty: aws.AwsRoute53HealthCheckResourceType,
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return cty.NilVal, err
|
||||
}
|
||||
return *val, nil
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/cloudskiff/driftctl/mocks"
|
||||
"github.com/cloudskiff/driftctl/pkg/parallel"
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
"github.com/cloudskiff/driftctl/test"
|
||||
"github.com/cloudskiff/driftctl/test/goldenfile"
|
||||
testmocks "github.com/cloudskiff/driftctl/test/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
)
|
||||
|
||||
func TestRoute53HealthCheckSupplier_Resources(t *testing.T) {
|
||||
cases := []struct {
|
||||
test string
|
||||
dirName string
|
||||
mocks func(client *mocks.Route53Repository)
|
||||
err error
|
||||
}{
|
||||
{
|
||||
test: "no health check",
|
||||
dirName: "route53_health_check_empty",
|
||||
mocks: func(client *mocks.Route53Repository) {
|
||||
client.On("ListAllHealthChecks").Return([]*route53.HealthCheck{}, nil)
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
test: "Multiple health check",
|
||||
dirName: "route53_health_check_multiple",
|
||||
mocks: func(client *mocks.Route53Repository) {
|
||||
client.On("ListAllHealthChecks").Return([]*route53.HealthCheck{
|
||||
{Id: aws.String("7001a9df-ded4-4802-9909-668eb80b972b")},
|
||||
{Id: aws.String("84fc318a-2e0d-41d6-b638-280e2f0f4e26")},
|
||||
}, nil)
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
test: "cannot list health check",
|
||||
dirName: "route53_health_check_empty",
|
||||
mocks: func(client *mocks.Route53Repository) {
|
||||
client.On("ListAllHealthChecks").Return(nil, awserr.NewRequestFailure(nil, 403, ""))
|
||||
},
|
||||
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsRoute53HealthCheckResourceType),
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
shouldUpdate := c.dirName == *goldenfile.Update
|
||||
|
||||
providerLibrary := terraform.NewProviderLibrary()
|
||||
supplierLibrary := resource.NewSupplierLibrary()
|
||||
|
||||
if shouldUpdate {
|
||||
provider, err := InitTestAwsProvider(providerLibrary)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
supplierLibrary.AddSupplier(NewRoute53HealthCheckSupplier(provider))
|
||||
}
|
||||
|
||||
t.Run(c.test, func(tt *testing.T) {
|
||||
fakeClient := mocks.Route53Repository{}
|
||||
c.mocks(&fakeClient)
|
||||
provider := testmocks.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
|
||||
deserializer := awsdeserializer.NewRoute53HealthCheckDeserializer()
|
||||
s := &Route53HealthCheckSupplier{
|
||||
provider,
|
||||
deserializer,
|
||||
&fakeClient,
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Typ": "WyJvYmplY3QiLHsiYWxpYXNlcyI6WyJzZXQiLCJzdHJpbmciXSwiYXJuIjoic3RyaW5nIiwiY2FsbGVyX3JlZmVyZW5jZSI6InN0cmluZyIsImNvbW1lbnQiOiJzdHJpbmciLCJjdXN0b21fZXJyb3JfcmVzcG9uc2UiOlsic2V0IixbIm9iamVjdCIseyJlcnJvcl9jYWNoaW5nX21pbl90dGwiOiJudW1iZXIiLCJlcnJvcl9jb2RlIjoibnVtYmVyIiwicmVzcG9uc2VfY29kZSI6Im51bWJlciIsInJlc3BvbnNlX3BhZ2VfcGF0aCI6InN0cmluZyJ9XV0sImRlZmF1bHRfY2FjaGVfYmVoYXZpb3IiOlsibGlzdCIsWyJvYmplY3QiLHsiYWxsb3dlZF9tZXRob2RzIjpbInNldCIsInN0cmluZyJdLCJjYWNoZWRfbWV0aG9kcyI6WyJzZXQiLCJzdHJpbmciXSwiY29tcHJlc3MiOiJib29sIiwiZGVmYXVsdF90dGwiOiJudW1iZXIiLCJmaWVsZF9sZXZlbF9lbmNyeXB0aW9uX2lkIjoic3RyaW5nIiwiZm9yd2FyZGVkX3ZhbHVlcyI6WyJsaXN0IixbIm9iamVjdCIseyJjb29raWVzIjpbImxpc3QiLFsib2JqZWN0Iix7ImZvcndhcmQiOiJzdHJpbmciLCJ3aGl0ZWxpc3RlZF9uYW1lcyI6WyJzZXQiLCJzdHJpbmciXX1dXSwiaGVhZGVycyI6WyJzZXQiLCJzdHJpbmciXSwicXVlcnlfc3RyaW5nIjoiYm9vbCIsInF1ZXJ5X3N0cmluZ19jYWNoZV9rZXlzIjpbImxpc3QiLCJzdHJpbmciXX1dXSwibGFtYmRhX2Z1bmN0aW9uX2Fzc29jaWF0aW9uIjpbInNldCIsWyJvYmplY3QiLHsiZXZlbnRfdHlwZSI6InN0cmluZyIsImluY2x1ZGVfYm9keSI6ImJvb2wiLCJsYW1iZGFfYXJuIjoic3RyaW5nIn1dXSwibWF4X3R0bCI6Im51bWJlciIsIm1pbl90dGwiOiJudW1iZXIiLCJzbW9vdGhfc3RyZWFtaW5nIjoiYm9vbCIsInRhcmdldF9vcmlnaW5faWQiOiJzdHJpbmciLCJ0cnVzdGVkX3NpZ25lcnMiOlsibGlzdCIsInN0cmluZyJdLCJ2aWV3ZXJfcHJvdG9jb2xfcG9saWN5Ijoic3RyaW5nIn1dXSwiZGVmYXVsdF9yb290X29iamVjdCI6InN0cmluZyIsImRvbWFpbl9uYW1lIjoic3RyaW5nIiwiZW5hYmxlZCI6ImJvb2wiLCJldGFnIjoic3RyaW5nIiwiaG9zdGVkX3pvbmVfaWQiOiJzdHJpbmciLCJodHRwX3ZlcnNpb24iOiJzdHJpbmciLCJpZCI6InN0cmluZyIsImluX3Byb2dyZXNzX3ZhbGlkYXRpb25fYmF0Y2hlcyI6Im51bWJlciIsImlzX2lwdjZfZW5hYmxlZCI6ImJvb2wiLCJsYXN0X21vZGlmaWVkX3RpbWUiOiJzdHJpbmciLCJsb2dnaW5nX2NvbmZpZyI6WyJsaXN0IixbIm9iamVjdCIseyJidWNrZXQiOiJzdHJpbmciLCJpbmNsdWRlX2Nvb2tpZXMiOiJib29sIiwicHJlZml4Ijoic3RyaW5nIn1dXSwib3JkZXJlZF9jYWNoZV9iZWhhdmlvciI6WyJsaXN0IixbIm9iamVjdCIseyJhbGxvd2VkX21ldGhvZHMiOlsic2V0Iiwic3RyaW5nIl0sImNhY2hlZF9tZXRob2RzIjpbInNldCIsInN0cmluZyJdLCJjb21wcmVzcyI6ImJvb2wiLCJkZWZhdWx0X3R0bCI6Im51bWJlciIsImZpZWxkX2xldmVsX2VuY3J5cHRpb25faWQiOiJzdHJpbmciLCJmb3J3YXJkZWRfdmFsdWVzIjpbImxpc3QiLFsib2JqZWN0Iix7ImNvb2tpZXMiOlsibGlzdCIsWyJvYmplY3QiLHsiZm9yd2FyZCI6InN0cmluZyIsIndoaXRlbGlzdGVkX25hbWVzIjpbInNldCIsInN0cmluZyJdfV1dLCJoZWFkZXJzIjpbInNldCIsInN0cmluZyJdLCJxdWVyeV9zdHJpbmciOiJib29sIiwicXVlcnlfc3RyaW5nX2NhY2hlX2tleXMiOlsibGlzdCIsInN0cmluZyJdfV1dLCJsYW1iZGFfZnVuY3Rpb25fYXNzb2NpYXRpb24iOlsic2V0IixbIm9iamVjdCIseyJldmVudF90eXBlIjoic3RyaW5nIiwiaW5jbHVkZV9ib2R5IjoiYm9vbCIsImxhbWJkYV9hcm4iOiJzdHJpbmcifV1dLCJtYXhfdHRsIjoibnVtYmVyIiwibWluX3R0bCI6Im51bWJlciIsInBhdGhfcGF0dGVybiI6InN0cmluZyIsInNtb290aF9zdHJlYW1pbmciOiJib29sIiwidGFyZ2V0X29yaWdpbl9pZCI6InN0cmluZyIsInRydXN0ZWRfc2lnbmVycyI6WyJsaXN0Iiwic3RyaW5nIl0sInZpZXdlcl9wcm90b2NvbF9wb2xpY3kiOiJzdHJpbmcifV1dLCJvcmlnaW4iOlsic2V0IixbIm9iamVjdCIseyJjdXN0b21faGVhZGVyIjpbInNldCIsWyJvYmplY3QiLHsibmFtZSI6InN0cmluZyIsInZhbHVlIjoic3RyaW5nIn1dXSwiY3VzdG9tX29yaWdpbl9jb25maWciOlsibGlzdCIsWyJvYmplY3QiLHsiaHR0cF9wb3J0IjoibnVtYmVyIiwiaHR0cHNfcG9ydCI6Im51bWJlciIsIm9yaWdpbl9rZWVwYWxpdmVfdGltZW91dCI6Im51bWJlciIsIm9yaWdpbl9wcm90b2NvbF9wb2xpY3kiOiJzdHJpbmciLCJvcmlnaW5fcmVhZF90aW1lb3V0IjoibnVtYmVyIiwib3JpZ2luX3NzbF9wcm90b2NvbHMiOlsic2V0Iiwic3RyaW5nIl19XV0sImRvbWFpbl9uYW1lIjoic3RyaW5nIiwib3JpZ2luX2lkIjoic3RyaW5nIiwib3JpZ2luX3BhdGgiOiJzdHJpbmciLCJzM19vcmlnaW5fY29uZmlnIjpbImxpc3QiLFsib2JqZWN0Iix7Im9yaWdpbl9hY2Nlc3NfaWRlbnRpdHkiOiJzdHJpbmcifV1dfV1dLCJvcmlnaW5fZ3JvdXAiOlsic2V0IixbIm9iamVjdCIseyJmYWlsb3Zlcl9jcml0ZXJpYSI6WyJsaXN0IixbIm9iamVjdCIseyJzdGF0dXNfY29kZXMiOlsic2V0IiwibnVtYmVyIl19XV0sIm1lbWJlciI6WyJsaXN0IixbIm9iamVjdCIseyJvcmlnaW5faWQiOiJzdHJpbmcifV1dLCJvcmlnaW5faWQiOiJzdHJpbmcifV1dLCJwcmljZV9jbGFzcyI6InN0cmluZyIsInJlc3RyaWN0aW9ucyI6WyJsaXN0IixbIm9iamVjdCIseyJnZW9fcmVzdHJpY3Rpb24iOlsibGlzdCIsWyJvYmplY3QiLHsibG9jYXRpb25zIjpbInNldCIsInN0cmluZyJdLCJyZXN0cmljdGlvbl90eXBlIjoic3RyaW5nIn1dXX1dXSwicmV0YWluX29uX2RlbGV0ZSI6ImJvb2wiLCJzdGF0dXMiOiJzdHJpbmciLCJ0YWdzIjpbIm1hcCIsInN0cmluZyJdLCJ0cnVzdGVkX3NpZ25lcnMiOlsibGlzdCIsWyJvYmplY3QiLHsiZW5hYmxlZCI6ImJvb2wiLCJpdGVtcyI6WyJsaXN0IixbIm9iamVjdCIseyJhd3NfYWNjb3VudF9udW1iZXIiOiJzdHJpbmciLCJrZXlfcGFpcl9pZHMiOlsic2V0Iiwic3RyaW5nIl19XV19XV0sInZpZXdlcl9jZXJ0aWZpY2F0ZSI6WyJsaXN0IixbIm9iamVjdCIseyJhY21fY2VydGlmaWNhdGVfYXJuIjoic3RyaW5nIiwiY2xvdWRmcm9udF9kZWZhdWx0X2NlcnRpZmljYXRlIjoiYm9vbCIsImlhbV9jZXJ0aWZpY2F0ZV9pZCI6InN0cmluZyIsIm1pbmltdW1fcHJvdG9jb2xfdmVyc2lvbiI6InN0cmluZyIsInNzbF9zdXBwb3J0X21ldGhvZCI6InN0cmluZyJ9XV0sIndhaXRfZm9yX2RlcGxveW1lbnQiOiJib29sIiwid2ViX2FjbF9pZCI6InN0cmluZyJ9XQ==",
|
||||
"Val": "eyJhbGlhc2VzIjpbXSwiYXJuIjoiYXJuOmF3czpjbG91ZGZyb250OjowNDcwODEwMTQzMTU6ZGlzdHJpYnV0aW9uL0UxTTlDTlMwWFNISTE5IiwiY2FsbGVyX3JlZmVyZW5jZSI6InRlcnJhZm9ybS0yMDIxMDIxNjEwMTczNDc5MjkwMDAwMDAwMSIsImNvbW1lbnQiOm51bGwsImN1c3RvbV9lcnJvcl9yZXNwb25zZSI6W10sImRlZmF1bHRfY2FjaGVfYmVoYXZpb3IiOlt7ImFsbG93ZWRfbWV0aG9kcyI6WyJHRVQiLCJIRUFEIl0sImNhY2hlZF9tZXRob2RzIjpbIkdFVCIsIkhFQUQiXSwiY29tcHJlc3MiOmZhbHNlLCJkZWZhdWx0X3R0bCI6ODY0MDAsImZpZWxkX2xldmVsX2VuY3J5cHRpb25faWQiOiIiLCJmb3J3YXJkZWRfdmFsdWVzIjpbeyJjb29raWVzIjpbeyJmb3J3YXJkIjoibm9uZSIsIndoaXRlbGlzdGVkX25hbWVzIjpbXX1dLCJoZWFkZXJzIjpbXSwicXVlcnlfc3RyaW5nIjpmYWxzZSwicXVlcnlfc3RyaW5nX2NhY2hlX2tleXMiOltdfV0sImxhbWJkYV9mdW5jdGlvbl9hc3NvY2lhdGlvbiI6W10sIm1heF90dGwiOjMxNTM2MDAwLCJtaW5fdHRsIjowLCJzbW9vdGhfc3RyZWFtaW5nIjpmYWxzZSwidGFyZ2V0X29yaWdpbl9pZCI6IlMzLWZvby1jbG91ZGZyb250IiwidHJ1c3RlZF9zaWduZXJzIjpbXSwidmlld2VyX3Byb3RvY29sX3BvbGljeSI6ImFsbG93LWFsbCJ9XSwiZGVmYXVsdF9yb290X29iamVjdCI6IiIsImRvbWFpbl9uYW1lIjoiZDFnMGR3MGkxd3ZsZ2QuY2xvdWRmcm9udC5uZXQiLCJlbmFibGVkIjpmYWxzZSwiZXRhZyI6IkUyQ0tCQU5MWFVQV0dRIiwiaG9zdGVkX3pvbmVfaWQiOiJaMkZEVE5EQVRBUVlXMiIsImh0dHBfdmVyc2lvbiI6Imh0dHAyIiwiaWQiOiJFMU05Q05TMFhTSEkxOSIsImluX3Byb2dyZXNzX3ZhbGlkYXRpb25fYmF0Y2hlcyI6MCwiaXNfaXB2Nl9lbmFibGVkIjpmYWxzZSwibGFzdF9tb2RpZmllZF90aW1lIjoiMjAyMS0wMi0xNiAxMDoxNzozNS40MDQgKzAwMDAgVVRDIiwibG9nZ2luZ19jb25maWciOltdLCJvcmRlcmVkX2NhY2hlX2JlaGF2aW9yIjpbXSwib3JpZ2luIjpbeyJjdXN0b21faGVhZGVyIjpbXSwiY3VzdG9tX29yaWdpbl9jb25maWciOltdLCJkb21haW5fbmFtZSI6ImZvby1jbG91ZGZyb250LnMzLmV1LXdlc3QtMy5hbWF6b25hd3MuY29tIiwib3JpZ2luX2lkIjoiUzMtZm9vLWNsb3VkZnJvbnQiLCJvcmlnaW5fcGF0aCI6IiIsInMzX29yaWdpbl9jb25maWciOltdfV0sIm9yaWdpbl9ncm91cCI6bnVsbCwicHJpY2VfY2xhc3MiOiJQcmljZUNsYXNzX0FsbCIsInJlc3RyaWN0aW9ucyI6W3siZ2VvX3Jlc3RyaWN0aW9uIjpbeyJsb2NhdGlvbnMiOltdLCJyZXN0cmljdGlvbl90eXBlIjoibm9uZSJ9XX1dLCJyZXRhaW5fb25fZGVsZXRlIjpudWxsLCJzdGF0dXMiOiJEZXBsb3llZCIsInRhZ3MiOnt9LCJ0cnVzdGVkX3NpZ25lcnMiOlt7ImVuYWJsZWQiOmZhbHNlLCJpdGVtcyI6W119XSwidmlld2VyX2NlcnRpZmljYXRlIjpbeyJhY21fY2VydGlmaWNhdGVfYXJuIjoiIiwiY2xvdWRmcm9udF9kZWZhdWx0X2NlcnRpZmljYXRlIjp0cnVlLCJpYW1fY2VydGlmaWNhdGVfaWQiOiIiLCJtaW5pbXVtX3Byb3RvY29sX3ZlcnNpb24iOiJUTFN2MSIsInNzbF9zdXBwb3J0X21ldGhvZCI6IiJ9XSwid2FpdF9mb3JfZGVwbG95bWVudCI6bnVsbCwid2ViX2FjbF9pZCI6IiJ9",
|
||||
"Err": null
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
[
|
||||
{
|
||||
"aliases": [],
|
||||
"arn": "arn:aws:cloudfront::047081014315:distribution/E1M9CNS0XSHI19",
|
||||
"caller_reference": "terraform-20210216101734792900000001",
|
||||
"comment": null,
|
||||
"custom_error_response": [],
|
||||
"default_cache_behavior": [
|
||||
{
|
||||
"allowed_methods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"cached_methods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"compress": false,
|
||||
"default_ttl": 86400,
|
||||
"field_level_encryption_id": "",
|
||||
"forwarded_values": [
|
||||
{
|
||||
"cookies": [
|
||||
{
|
||||
"forward": "none",
|
||||
"whitelisted_names": []
|
||||
}
|
||||
],
|
||||
"headers": [],
|
||||
"query_string": false,
|
||||
"query_string_cache_keys": []
|
||||
}
|
||||
],
|
||||
"lambda_function_association": [],
|
||||
"max_ttl": 31536000,
|
||||
"min_ttl": 0,
|
||||
"smooth_streaming": false,
|
||||
"target_origin_id": "S3-foo-cloudfront",
|
||||
"trusted_signers": [],
|
||||
"viewer_protocol_policy": "allow-all"
|
||||
}
|
||||
],
|
||||
"default_root_object": "",
|
||||
"domain_name": "d1g0dw0i1wvlgd.cloudfront.net",
|
||||
"enabled": false,
|
||||
"etag": "E2CKBANLXUPWGQ",
|
||||
"hosted_zone_id": "Z2FDTNDATAQYW2",
|
||||
"http_version": "http2",
|
||||
"id": "E1M9CNS0XSHI19",
|
||||
"in_progress_validation_batches": 0,
|
||||
"is_ipv6_enabled": false,
|
||||
"last_modified_time": "2021-02-16 10:17:35.404 +0000 UTC",
|
||||
"logging_config": [],
|
||||
"ordered_cache_behavior": [],
|
||||
"origin": [
|
||||
{
|
||||
"custom_header": [],
|
||||
"custom_origin_config": [],
|
||||
"domain_name": "foo-cloudfront.s3.eu-west-3.amazonaws.com",
|
||||
"origin_id": "S3-foo-cloudfront",
|
||||
"origin_path": "",
|
||||
"s3_origin_config": []
|
||||
}
|
||||
],
|
||||
"origin_group": null,
|
||||
"price_class": "PriceClass_All",
|
||||
"restrictions": [
|
||||
{
|
||||
"geo_restriction": [
|
||||
{
|
||||
"locations": [],
|
||||
"restriction_type": "none"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"retain_on_delete": null,
|
||||
"status": "Deployed",
|
||||
"tags": {},
|
||||
"trusted_signers": [
|
||||
{
|
||||
"enabled": false,
|
||||
"items": []
|
||||
}
|
||||
],
|
||||
"viewer_certificate": [
|
||||
{
|
||||
"acm_certificate_arn": "",
|
||||
"cloudfront_default_certificate": true,
|
||||
"iam_certificate_id": "",
|
||||
"minimum_protocol_version": "TLSv1",
|
||||
"ssl_support_method": ""
|
||||
}
|
||||
],
|
||||
"wait_for_deployment": null,
|
||||
"web_acl_id": ""
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = "3.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "foo_cloudfront" {
|
||||
bucket = "foo-cloudfront"
|
||||
acl = "private"
|
||||
}
|
||||
|
||||
locals {
|
||||
s3_origin_id = "S3-foo-cloudfront"
|
||||
}
|
||||
|
||||
resource "aws_cloudfront_distribution" "foo_distribution" {
|
||||
enabled = false
|
||||
|
||||
origin {
|
||||
domain_name = aws_s3_bucket.foo_cloudfront.bucket_regional_domain_name
|
||||
origin_id = local.s3_origin_id
|
||||
}
|
||||
|
||||
default_cache_behavior {
|
||||
allowed_methods = ["GET", "HEAD"]
|
||||
cached_methods = ["GET", "HEAD"]
|
||||
target_origin_id = local.s3_origin_id
|
||||
viewer_protocol_policy = "allow-all"
|
||||
|
||||
forwarded_values {
|
||||
query_string = false
|
||||
|
||||
cookies {
|
||||
forward = "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restrictions {
|
||||
geo_restriction {
|
||||
restriction_type = "none"
|
||||
}
|
||||
}
|
||||
|
||||
viewer_certificate {
|
||||
cloudfront_default_certificate = true
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Typ": "WyJvYmplY3QiLHsiY2hpbGRfaGVhbHRoX3RocmVzaG9sZCI6Im51bWJlciIsImNoaWxkX2hlYWx0aGNoZWNrcyI6WyJzZXQiLCJzdHJpbmciXSwiY2xvdWR3YXRjaF9hbGFybV9uYW1lIjoic3RyaW5nIiwiY2xvdWR3YXRjaF9hbGFybV9yZWdpb24iOiJzdHJpbmciLCJkaXNhYmxlZCI6ImJvb2wiLCJlbmFibGVfc25pIjoiYm9vbCIsImZhaWx1cmVfdGhyZXNob2xkIjoibnVtYmVyIiwiZnFkbiI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaW5zdWZmaWNpZW50X2RhdGFfaGVhbHRoX3N0YXR1cyI6InN0cmluZyIsImludmVydF9oZWFsdGhjaGVjayI6ImJvb2wiLCJpcF9hZGRyZXNzIjoic3RyaW5nIiwibWVhc3VyZV9sYXRlbmN5IjoiYm9vbCIsInBvcnQiOiJudW1iZXIiLCJyZWZlcmVuY2VfbmFtZSI6InN0cmluZyIsInJlZ2lvbnMiOlsic2V0Iiwic3RyaW5nIl0sInJlcXVlc3RfaW50ZXJ2YWwiOiJudW1iZXIiLCJyZXNvdXJjZV9wYXRoIjoic3RyaW5nIiwic2VhcmNoX3N0cmluZyI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInR5cGUiOiJzdHJpbmcifV0=",
|
||||
"Val": "eyJjaGlsZF9oZWFsdGhfdGhyZXNob2xkIjowLCJjaGlsZF9oZWFsdGhjaGVja3MiOltdLCJjbG91ZHdhdGNoX2FsYXJtX25hbWUiOm51bGwsImNsb3Vkd2F0Y2hfYWxhcm1fcmVnaW9uIjpudWxsLCJkaXNhYmxlZCI6ZmFsc2UsImVuYWJsZV9zbmkiOmZhbHNlLCJmYWlsdXJlX3RocmVzaG9sZCI6NSwiZnFkbiI6Im1vYWRpYi5uZXQiLCJpZCI6IjcwMDFhOWRmLWRlZDQtNDgwMi05OTA5LTY2OGViODBiOTcyYiIsImluc3VmZmljaWVudF9kYXRhX2hlYWx0aF9zdGF0dXMiOiIiLCJpbnZlcnRfaGVhbHRoY2hlY2siOmZhbHNlLCJpcF9hZGRyZXNzIjoiIiwibWVhc3VyZV9sYXRlbmN5IjpmYWxzZSwicG9ydCI6ODAsInJlZmVyZW5jZV9uYW1lIjpudWxsLCJyZWdpb25zIjpbXSwicmVxdWVzdF9pbnRlcnZhbCI6MzAsInJlc291cmNlX3BhdGgiOiIvIiwic2VhcmNoX3N0cmluZyI6IiIsInRhZ3MiOnsiTmFtZSI6Imh0dHAtbW9hZGliLW5ldCJ9LCJ0eXBlIjoiSFRUUCJ9",
|
||||
"Err": null
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Typ": "WyJvYmplY3QiLHsiY2hpbGRfaGVhbHRoX3RocmVzaG9sZCI6Im51bWJlciIsImNoaWxkX2hlYWx0aGNoZWNrcyI6WyJzZXQiLCJzdHJpbmciXSwiY2xvdWR3YXRjaF9hbGFybV9uYW1lIjoic3RyaW5nIiwiY2xvdWR3YXRjaF9hbGFybV9yZWdpb24iOiJzdHJpbmciLCJkaXNhYmxlZCI6ImJvb2wiLCJlbmFibGVfc25pIjoiYm9vbCIsImZhaWx1cmVfdGhyZXNob2xkIjoibnVtYmVyIiwiZnFkbiI6InN0cmluZyIsImlkIjoic3RyaW5nIiwiaW5zdWZmaWNpZW50X2RhdGFfaGVhbHRoX3N0YXR1cyI6InN0cmluZyIsImludmVydF9oZWFsdGhjaGVjayI6ImJvb2wiLCJpcF9hZGRyZXNzIjoic3RyaW5nIiwibWVhc3VyZV9sYXRlbmN5IjoiYm9vbCIsInBvcnQiOiJudW1iZXIiLCJyZWZlcmVuY2VfbmFtZSI6InN0cmluZyIsInJlZ2lvbnMiOlsic2V0Iiwic3RyaW5nIl0sInJlcXVlc3RfaW50ZXJ2YWwiOiJudW1iZXIiLCJyZXNvdXJjZV9wYXRoIjoic3RyaW5nIiwic2VhcmNoX3N0cmluZyI6InN0cmluZyIsInRhZ3MiOlsibWFwIiwic3RyaW5nIl0sInR5cGUiOiJzdHJpbmcifV0=",
|
||||
"Val": "eyJjaGlsZF9oZWFsdGhfdGhyZXNob2xkIjowLCJjaGlsZF9oZWFsdGhjaGVja3MiOltdLCJjbG91ZHdhdGNoX2FsYXJtX25hbWUiOm51bGwsImNsb3Vkd2F0Y2hfYWxhcm1fcmVnaW9uIjpudWxsLCJkaXNhYmxlZCI6ZmFsc2UsImVuYWJsZV9zbmkiOnRydWUsImZhaWx1cmVfdGhyZXNob2xkIjo1LCJmcWRuIjoibW9hZGliLm5ldCIsImlkIjoiODRmYzMxOGEtMmUwZC00MWQ2LWI2MzgtMjgwZTJmMGY0ZTI2IiwiaW5zdWZmaWNpZW50X2RhdGFfaGVhbHRoX3N0YXR1cyI6IiIsImludmVydF9oZWFsdGhjaGVjayI6ZmFsc2UsImlwX2FkZHJlc3MiOiIiLCJtZWFzdXJlX2xhdGVuY3kiOmZhbHNlLCJwb3J0Ijo0NDMsInJlZmVyZW5jZV9uYW1lIjpudWxsLCJyZWdpb25zIjpbXSwicmVxdWVzdF9pbnRlcnZhbCI6MzAsInJlc291cmNlX3BhdGgiOiIvIiwic2VhcmNoX3N0cmluZyI6Ik1vQWRpQiIsInRhZ3MiOnt9LCJ0eXBlIjoiSFRUUFNfU1RSX01BVENIIn0=",
|
||||
"Err": null
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
[
|
||||
{
|
||||
"child_health_threshold": 0,
|
||||
"child_healthchecks": [],
|
||||
"cloudwatch_alarm_name": null,
|
||||
"cloudwatch_alarm_region": null,
|
||||
"disabled": false,
|
||||
"enable_sni": false,
|
||||
"failure_threshold": 5,
|
||||
"fqdn": "moadib.net",
|
||||
"id": "7001a9df-ded4-4802-9909-668eb80b972b",
|
||||
"insufficient_data_health_status": "",
|
||||
"invert_healthcheck": false,
|
||||
"ip_address": "",
|
||||
"measure_latency": false,
|
||||
"port": 80,
|
||||
"reference_name": null,
|
||||
"regions": [],
|
||||
"request_interval": 30,
|
||||
"resource_path": "/",
|
||||
"search_string": "",
|
||||
"tags": {
|
||||
"Name": "http-moadib-net"
|
||||
},
|
||||
"type": "HTTP"
|
||||
},
|
||||
{
|
||||
"child_health_threshold": 0,
|
||||
"child_healthchecks": [],
|
||||
"cloudwatch_alarm_name": null,
|
||||
"cloudwatch_alarm_region": null,
|
||||
"disabled": false,
|
||||
"enable_sni": true,
|
||||
"failure_threshold": 5,
|
||||
"fqdn": "moadib.net",
|
||||
"id": "84fc318a-2e0d-41d6-b638-280e2f0f4e26",
|
||||
"insufficient_data_health_status": "",
|
||||
"invert_healthcheck": false,
|
||||
"ip_address": "",
|
||||
"measure_latency": false,
|
||||
"port": 443,
|
||||
"reference_name": null,
|
||||
"regions": [],
|
||||
"request_interval": 30,
|
||||
"resource_path": "/",
|
||||
"search_string": "MoAdiB",
|
||||
"tags": {},
|
||||
"type": "HTTPS_STR_MATCH"
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -4,14 +4,30 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type EnumerationAccessDeniedAlert struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func NewEnumerationAccessDeniedAlert(supplierType, listedTypeError string) *EnumerationAccessDeniedAlert {
|
||||
message := fmt.Sprintf("Ignoring %s from drift calculation: Listing %s is forbidden.", supplierType, listedTypeError)
|
||||
return &EnumerationAccessDeniedAlert{message}
|
||||
}
|
||||
|
||||
func (e *EnumerationAccessDeniedAlert) Message() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func (e *EnumerationAccessDeniedAlert) ShouldIgnoreResource() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func HandleResourceEnumerationError(err error, alertr *alerter.Alerter) error {
|
||||
listError, ok := err.(*remoteerror.ResourceEnumerationError)
|
||||
if !ok {
|
||||
|
@ -24,12 +40,11 @@ func HandleResourceEnumerationError(err error, alertr *alerter.Alerter) error {
|
|||
}
|
||||
|
||||
if reqerr.StatusCode() == 403 || (reqerr.StatusCode() == 400 && strings.Contains(reqerr.Code(), "AccessDenied")) {
|
||||
message := fmt.Sprintf("Ignoring %s from drift calculation: Listing %s is forbidden.", listError.SupplierType(), listError.ListedTypeError())
|
||||
logrus.Debugf(message)
|
||||
alertr.SendAlert(listError.SupplierType(), alerter.Alert{
|
||||
Message: message,
|
||||
ShouldIgnoreResource: true,
|
||||
})
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"supplier_type": listError.SupplierType(),
|
||||
"listed_type": listError.ListedTypeError(),
|
||||
}).Debugf("Got an access denied error")
|
||||
alertr.SendAlert(listError.SupplierType(), NewEnumerationAccessDeniedAlert(listError.SupplierType(), listError.ListedTypeError()))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -25,13 +25,13 @@ func TestHandleListAwsError(t *testing.T) {
|
|||
{
|
||||
name: "Handled error 403",
|
||||
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(awserr.New("", "", errors.New("")), 403, ""), resourceaws.AwsVpcResourceType),
|
||||
wantAlerts: alerter.Alerts{"aws_vpc": []alerter.Alert{alerter.Alert{Message: "Ignoring aws_vpc from drift calculation: Listing aws_vpc is forbidden.", ShouldIgnoreResource: true}}},
|
||||
wantAlerts: alerter.Alerts{"aws_vpc": []alerter.Alert{NewEnumerationAccessDeniedAlert("aws_vpc", "aws_vpc")}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Handled error AccessDenied",
|
||||
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(awserr.New("AccessDeniedException", "", errors.New("")), 403, ""), resourceaws.AwsDynamodbTableResourceType),
|
||||
wantAlerts: alerter.Alerts{"aws_dynamodb_table": []alerter.Alert{alerter.Alert{Message: "Ignoring aws_dynamodb_table from drift calculation: Listing aws_dynamodb_table is forbidden.", ShouldIgnoreResource: true}}},
|
||||
wantAlerts: alerter.Alerts{"aws_dynamodb_table": []alerter.Alert{NewEnumerationAccessDeniedAlert("aws_dynamodb_table", "aws_dynamodb_table")}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
// GENERATED, DO NOT EDIT THIS FILE
|
||||
package aws
|
||||
|
||||
const AwsCloudfrontDistributionResourceType = "aws_cloudfront_distribution"
|
||||
|
||||
type AwsCloudfrontDistribution struct {
|
||||
Aliases *[]string `cty:"aliases"`
|
||||
Arn *string `cty:"arn" computed:"true"`
|
||||
CallerReference *string `cty:"caller_reference" computed:"true"`
|
||||
Comment *string `cty:"comment"`
|
||||
DefaultRootObject *string `cty:"default_root_object"`
|
||||
DomainName *string `cty:"domain_name" computed:"true"`
|
||||
Enabled *bool `cty:"enabled"`
|
||||
Etag *string `cty:"etag" computed:"true" diff:"-"`
|
||||
HostedZoneId *string `cty:"hosted_zone_id" computed:"true"`
|
||||
HttpVersion *string `cty:"http_version"`
|
||||
Id string `cty:"id" computed:"true"`
|
||||
InProgressValidationBatches *int `cty:"in_progress_validation_batches" computed:"true"`
|
||||
IsIpv6Enabled *bool `cty:"is_ipv6_enabled"`
|
||||
LastModifiedTime *string `cty:"last_modified_time" computed:"true" diff:"-"`
|
||||
PriceClass *string `cty:"price_class"`
|
||||
RetainOnDelete *bool `cty:"retain_on_delete" diff:"-"`
|
||||
Status *string `cty:"status" computed:"true" diff:"-"`
|
||||
Tags map[string]string `cty:"tags"`
|
||||
TrustedSigners *[]struct {
|
||||
Enabled *bool `cty:"enabled" computed:"true"`
|
||||
Items *[]struct {
|
||||
AwsAccountNumber *string `cty:"aws_account_number" computed:"true"`
|
||||
KeyPairIds *[]string `cty:"key_pair_ids" computed:"true"`
|
||||
} `cty:"items" computed:"true"`
|
||||
} `cty:"trusted_signers" computed:"true"`
|
||||
WaitForDeployment *bool `cty:"wait_for_deployment" diff:"-"`
|
||||
WebAclId *string `cty:"web_acl_id"`
|
||||
CustomErrorResponse *[]struct {
|
||||
ErrorCachingMinTtl *int `cty:"error_caching_min_ttl"`
|
||||
ErrorCode *int `cty:"error_code"`
|
||||
ResponseCode *int `cty:"response_code"`
|
||||
ResponsePagePath *string `cty:"response_page_path"`
|
||||
} `cty:"custom_error_response"`
|
||||
DefaultCacheBehavior *[]struct {
|
||||
AllowedMethods *[]string `cty:"allowed_methods"`
|
||||
CachedMethods *[]string `cty:"cached_methods"`
|
||||
Compress *bool `cty:"compress"`
|
||||
DefaultTtl *int `cty:"default_ttl"`
|
||||
FieldLevelEncryptionId *string `cty:"field_level_encryption_id"`
|
||||
MaxTtl *int `cty:"max_ttl"`
|
||||
MinTtl *int `cty:"min_ttl"`
|
||||
SmoothStreaming *bool `cty:"smooth_streaming"`
|
||||
TargetOriginId *string `cty:"target_origin_id"`
|
||||
TrustedSigners *[]string `cty:"trusted_signers"`
|
||||
ViewerProtocolPolicy *string `cty:"viewer_protocol_policy"`
|
||||
ForwardedValues *[]struct {
|
||||
Headers *[]string `cty:"headers"`
|
||||
QueryString *bool `cty:"query_string"`
|
||||
QueryStringCacheKeys *[]string `cty:"query_string_cache_keys"`
|
||||
Cookies *[]struct {
|
||||
Forward *string `cty:"forward"`
|
||||
WhitelistedNames *[]string `cty:"whitelisted_names"`
|
||||
} `cty:"cookies"`
|
||||
} `cty:"forwarded_values"`
|
||||
LambdaFunctionAssociation *[]struct {
|
||||
EventType *string `cty:"event_type"`
|
||||
IncludeBody *bool `cty:"include_body"`
|
||||
LambdaArn *string `cty:"lambda_arn"`
|
||||
} `cty:"lambda_function_association"`
|
||||
} `cty:"default_cache_behavior"`
|
||||
LoggingConfig *[]struct {
|
||||
Bucket *string `cty:"bucket"`
|
||||
IncludeCookies *bool `cty:"include_cookies"`
|
||||
Prefix *string `cty:"prefix"`
|
||||
} `cty:"logging_config"`
|
||||
OrderedCacheBehavior *[]struct {
|
||||
AllowedMethods *[]string `cty:"allowed_methods"`
|
||||
CachedMethods *[]string `cty:"cached_methods"`
|
||||
Compress *bool `cty:"compress"`
|
||||
DefaultTtl *int `cty:"default_ttl"`
|
||||
FieldLevelEncryptionId *string `cty:"field_level_encryption_id"`
|
||||
MaxTtl *int `cty:"max_ttl"`
|
||||
MinTtl *int `cty:"min_ttl"`
|
||||
PathPattern *string `cty:"path_pattern"`
|
||||
SmoothStreaming *bool `cty:"smooth_streaming"`
|
||||
TargetOriginId *string `cty:"target_origin_id"`
|
||||
TrustedSigners *[]string `cty:"trusted_signers"`
|
||||
ViewerProtocolPolicy *string `cty:"viewer_protocol_policy"`
|
||||
ForwardedValues *[]struct {
|
||||
Headers *[]string `cty:"headers"`
|
||||
QueryString *bool `cty:"query_string"`
|
||||
QueryStringCacheKeys *[]string `cty:"query_string_cache_keys"`
|
||||
Cookies *[]struct {
|
||||
Forward *string `cty:"forward"`
|
||||
WhitelistedNames *[]string `cty:"whitelisted_names"`
|
||||
} `cty:"cookies"`
|
||||
} `cty:"forwarded_values"`
|
||||
LambdaFunctionAssociation *[]struct {
|
||||
EventType *string `cty:"event_type"`
|
||||
IncludeBody *bool `cty:"include_body"`
|
||||
LambdaArn *string `cty:"lambda_arn"`
|
||||
} `cty:"lambda_function_association"`
|
||||
} `cty:"ordered_cache_behavior"`
|
||||
Origin *[]struct {
|
||||
DomainName *string `cty:"domain_name"`
|
||||
OriginId *string `cty:"origin_id"`
|
||||
OriginPath *string `cty:"origin_path"`
|
||||
CustomHeader *[]struct {
|
||||
Name *string `cty:"name"`
|
||||
Value *string `cty:"value"`
|
||||
} `cty:"custom_header"`
|
||||
CustomOriginConfig *[]struct {
|
||||
HttpPort *int `cty:"http_port"`
|
||||
HttpsPort *int `cty:"https_port"`
|
||||
OriginKeepaliveTimeout *int `cty:"origin_keepalive_timeout"`
|
||||
OriginProtocolPolicy *string `cty:"origin_protocol_policy"`
|
||||
OriginReadTimeout *int `cty:"origin_read_timeout"`
|
||||
OriginSslProtocols *[]string `cty:"origin_ssl_protocols"`
|
||||
} `cty:"custom_origin_config"`
|
||||
S3OriginConfig *[]struct {
|
||||
OriginAccessIdentity *string `cty:"origin_access_identity"`
|
||||
} `cty:"s3_origin_config"`
|
||||
} `cty:"origin"`
|
||||
OriginGroup *[]struct {
|
||||
OriginId *string `cty:"origin_id"`
|
||||
FailoverCriteria *[]struct {
|
||||
StatusCodes *[]int `cty:"status_codes"`
|
||||
} `cty:"failover_criteria"`
|
||||
Member *[]struct {
|
||||
OriginId *string `cty:"origin_id"`
|
||||
} `cty:"member"`
|
||||
} `cty:"origin_group"`
|
||||
Restrictions *[]struct {
|
||||
GeoRestriction *[]struct {
|
||||
Locations *[]string `cty:"locations"`
|
||||
RestrictionType *string `cty:"restriction_type"`
|
||||
} `cty:"geo_restriction"`
|
||||
} `cty:"restrictions"`
|
||||
ViewerCertificate *[]struct {
|
||||
AcmCertificateArn *string `cty:"acm_certificate_arn"`
|
||||
CloudfrontDefaultCertificate *bool `cty:"cloudfront_default_certificate"`
|
||||
IamCertificateId *string `cty:"iam_certificate_id"`
|
||||
MinimumProtocolVersion *string `cty:"minimum_protocol_version"`
|
||||
SslSupportMethod *string `cty:"ssl_support_method"`
|
||||
} `cty:"viewer_certificate"`
|
||||
}
|
||||
|
||||
func (r *AwsCloudfrontDistribution) TerraformId() string {
|
||||
return r.Id
|
||||
}
|
||||
|
||||
func (r *AwsCloudfrontDistribution) TerraformType() string {
|
||||
return AwsCloudfrontDistributionResourceType
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package aws
|
||||
|
||||
import "github.com/cloudskiff/driftctl/pkg/resource"
|
||||
|
||||
func (r *AwsCloudfrontDistribution) NormalizeForState() (resource.Resource, error) {
|
||||
r.normalizeNilPtr()
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *AwsCloudfrontDistribution) NormalizeForProvider() (resource.Resource, error) {
|
||||
r.normalizeNilPtr()
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *AwsCloudfrontDistribution) normalizeNilPtr() {
|
||||
if r.Aliases != nil && len(*r.Aliases) == 0 {
|
||||
r.Aliases = nil
|
||||
}
|
||||
if r.OriginGroup != nil && len(*r.OriginGroup) == 0 {
|
||||
r.OriginGroup = nil
|
||||
}
|
||||
|
||||
// Way too dirty, we must find another way to normalize to nil fields in deeply nested struct
|
||||
// Here, this is for 3 fields, but in the CloudfrontDistribution resource there
|
||||
// could be more fields that we would need to do that...
|
||||
if r.DefaultCacheBehavior != nil {
|
||||
for i, b := range *r.DefaultCacheBehavior {
|
||||
if b.ForwardedValues != nil {
|
||||
for j, f := range *b.ForwardedValues {
|
||||
if f.Headers != nil && len(*f.Headers) == 0 {
|
||||
(*(*r.DefaultCacheBehavior)[i].ForwardedValues)[j].Headers = nil
|
||||
}
|
||||
if f.Cookies != nil {
|
||||
for k, c := range *f.Cookies {
|
||||
if c.WhitelistedNames != nil && len(*c.WhitelistedNames) == 0 {
|
||||
(*(*(*r.DefaultCacheBehavior)[i].ForwardedValues)[j].Cookies)[k].WhitelistedNames = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.Restrictions != nil {
|
||||
for i, v := range *r.Restrictions {
|
||||
if v.GeoRestriction != nil {
|
||||
for j, g := range *v.GeoRestriction {
|
||||
if g.Locations != nil && len(*g.Locations) == 0 {
|
||||
(*(*r.Restrictions)[i].GeoRestriction)[j].Locations = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||
awsresources "github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
"github.com/r3labs/diff/v2"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
"github.com/cloudskiff/driftctl/test/acceptance"
|
||||
"github.com/cloudskiff/driftctl/test/acceptance/awsutils"
|
||||
)
|
||||
|
||||
func TestAcc_Aws_CloudfrontDistribution(t *testing.T) {
|
||||
var mutatedDistribution string
|
||||
acceptance.Run(t, acceptance.AccTestCase{
|
||||
Path: "./testdata/acc/aws_cloudfront_distribution",
|
||||
Args: []string{"scan", "--filter", "Type=='aws_cloudfront_distribution'"},
|
||||
ShouldRefreshBeforeDestroy: true,
|
||||
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.AssertManagedCount(1)
|
||||
mutatedDistribution = result.Managed()[0].TerraformId()
|
||||
},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "us-east-1",
|
||||
},
|
||||
PreExec: func() {
|
||||
client := cloudfront.New(awsutils.Session())
|
||||
res, err := client.GetDistributionConfig(&cloudfront.GetDistributionConfigInput{
|
||||
Id: aws.String(mutatedDistribution),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res.DistributionConfig.SetIsIPV6Enabled(true)
|
||||
_, err = client.UpdateDistribution(&cloudfront.UpdateDistributionInput{
|
||||
Id: aws.String(mutatedDistribution),
|
||||
DistributionConfig: res.DistributionConfig,
|
||||
IfMatch: res.ETag,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
},
|
||||
Check: func(result *acceptance.ScanResult, stdout string, err error) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result.AssertDriftCountTotal(1)
|
||||
result.AssertResourceHasDrift(
|
||||
mutatedDistribution,
|
||||
awsresources.AwsCloudfrontDistributionResourceType,
|
||||
analyser.Change{
|
||||
Change: diff.Change{
|
||||
Type: diff.UPDATE,
|
||||
Path: []string{"IsIpv6Enabled"},
|
||||
From: false,
|
||||
To: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// GENERATED, DO NOT EDIT THIS FILE
|
||||
package aws
|
||||
|
||||
const AwsRoute53HealthCheckResourceType = "aws_route53_health_check"
|
||||
|
||||
type AwsRoute53HealthCheck struct {
|
||||
ChildHealthThreshold *int `cty:"child_health_threshold"`
|
||||
ChildHealthchecks *[]string `cty:"child_healthchecks"` // This became a slice ptr due to gocty
|
||||
CloudwatchAlarmName *string `cty:"cloudwatch_alarm_name"`
|
||||
CloudwatchAlarmRegion *string `cty:"cloudwatch_alarm_region"`
|
||||
Disabled *bool `cty:"disabled"`
|
||||
EnableSni *bool `cty:"enable_sni" computed:"true"`
|
||||
FailureThreshold *int `cty:"failure_threshold"`
|
||||
Fqdn *string `cty:"fqdn"`
|
||||
Id string `cty:"id" computed:"true"`
|
||||
InsufficientDataHealthStatus *string `cty:"insufficient_data_health_status"`
|
||||
InvertHealthcheck *bool `cty:"invert_healthcheck"`
|
||||
IpAddress *string `cty:"ip_address"`
|
||||
MeasureLatency *bool `cty:"measure_latency"`
|
||||
Port *int `cty:"port"`
|
||||
ReferenceName *string `cty:"reference_name"`
|
||||
Regions *[]string `cty:"regions"` // This became a slice ptr due to gocty
|
||||
RequestInterval *int `cty:"request_interval"`
|
||||
ResourcePath *string `cty:"resource_path"`
|
||||
SearchString *string `cty:"search_string"`
|
||||
Tags map[string]string `cty:"tags"`
|
||||
Type *string `cty:"type"`
|
||||
}
|
||||
|
||||
func (r *AwsRoute53HealthCheck) TerraformId() string {
|
||||
return r.Id
|
||||
}
|
||||
|
||||
func (r *AwsRoute53HealthCheck) TerraformType() string {
|
||||
return AwsRoute53HealthCheckResourceType
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
)
|
||||
|
||||
func (r *AwsRoute53HealthCheck) String() string {
|
||||
str := r.Id
|
||||
|
||||
name, hasName := r.Tags["Name"]
|
||||
if hasName {
|
||||
str = name
|
||||
}
|
||||
|
||||
if r.Fqdn != nil && *r.Fqdn != "" {
|
||||
str += fmt.Sprintf(" (fqdn: %s", *r.Fqdn)
|
||||
str = r.addPortAndResPathString(str)
|
||||
str += ")"
|
||||
}
|
||||
|
||||
if r.IpAddress != nil && *r.IpAddress != "" {
|
||||
str += fmt.Sprintf(" (ip: %s", *r.IpAddress)
|
||||
str = r.addPortAndResPathString(str)
|
||||
str += ")"
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func (r *AwsRoute53HealthCheck) addPortAndResPathString(str string) string {
|
||||
if r.Port != nil {
|
||||
str += fmt.Sprintf(", port: %d", *r.Port)
|
||||
}
|
||||
if r.ResourcePath != nil {
|
||||
str += fmt.Sprintf(", path: %s", *r.ResourcePath)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (r *AwsRoute53HealthCheck) NormalizeForState() (resource.Resource, error) {
|
||||
r.ChildHealthchecks = &[]string{}
|
||||
r.Regions = &[]string{}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *AwsRoute53HealthCheck) NormalizeForProvider() (resource.Resource, error) {
|
||||
return r, nil
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
)
|
||||
|
||||
func TestAwsRoute53HealthCheck_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
healthCheck *AwsRoute53HealthCheck
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Just id",
|
||||
healthCheck: &AwsRoute53HealthCheck{Id: "id"},
|
||||
want: "id",
|
||||
},
|
||||
{
|
||||
name: "Tag name with fqdn and respath",
|
||||
healthCheck: &AwsRoute53HealthCheck{
|
||||
Id: "id",
|
||||
Tags: map[string]string{"Name": "name"},
|
||||
Fqdn: aws.String("fq.dn"),
|
||||
ResourcePath: aws.String("/toto"),
|
||||
},
|
||||
want: "name (fqdn: fq.dn, path: /toto)",
|
||||
},
|
||||
{
|
||||
name: "Tag name with ip and port",
|
||||
healthCheck: &AwsRoute53HealthCheck{
|
||||
Id: "id",
|
||||
Tags: map[string]string{"Name": "name"},
|
||||
IpAddress: aws.String("10.0.0.10"),
|
||||
Port: aws.Int(443),
|
||||
},
|
||||
want: "name (ip: 10.0.0.10, port: 443)",
|
||||
},
|
||||
{
|
||||
name: "Tag name with ip, port ans respath",
|
||||
healthCheck: &AwsRoute53HealthCheck{
|
||||
Id: "id",
|
||||
Tags: map[string]string{"Name": "name"},
|
||||
IpAddress: aws.String("10.0.0.10"),
|
||||
Port: aws.Int(443),
|
||||
ResourcePath: aws.String("/toto"),
|
||||
},
|
||||
want: "name (ip: 10.0.0.10, port: 443, path: /toto)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := tt.healthCheck
|
||||
if got := r.String(); got != tt.want {
|
||||
t.Errorf("String() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||
awsresources "github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
"github.com/cloudskiff/driftctl/test/acceptance"
|
||||
"github.com/cloudskiff/driftctl/test/acceptance/awsutils"
|
||||
"github.com/r3labs/diff/v2"
|
||||
)
|
||||
|
||||
func TestAcc_AwsRoute53HealthCheck(t *testing.T) {
|
||||
var mutatedHealthCheckID string
|
||||
acceptance.Run(t, acceptance.AccTestCase{
|
||||
Path: "./testdata/acc/aws_route53_health_check",
|
||||
Args: []string{"scan", "--filter", "Type=='aws_route53_health_check'"},
|
||||
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.AssertManagedCount(2)
|
||||
|
||||
mutatedHealthCheckID = result.Managed()[0].TerraformId()
|
||||
},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "us-east-1",
|
||||
},
|
||||
PreExec: func() {
|
||||
client := route53.New(awsutils.Session())
|
||||
_, err := client.UpdateHealthCheck(&route53.UpdateHealthCheckInput{
|
||||
Disabled: aws.Bool(true),
|
||||
HealthCheckId: &mutatedHealthCheckID,
|
||||
ResourcePath: aws.String("/bad"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
},
|
||||
Check: func(result *acceptance.ScanResult, stdout string, err error) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result.AssertDriftCountTotal(2)
|
||||
result.AssertDeletedCount(0)
|
||||
result.AssertManagedCount(2)
|
||||
|
||||
result.AssertResourceHasDrift(
|
||||
mutatedHealthCheckID,
|
||||
awsresources.AwsRoute53HealthCheckResourceType,
|
||||
analyser.Change{
|
||||
Change: diff.Change{
|
||||
Type: diff.UPDATE,
|
||||
Path: []string{"Disabled"},
|
||||
From: false,
|
||||
To: true,
|
||||
},
|
||||
Computed: false,
|
||||
},
|
||||
)
|
||||
|
||||
result.AssertResourceHasDrift(
|
||||
mutatedHealthCheckID,
|
||||
awsresources.AwsRoute53HealthCheckResourceType,
|
||||
analyser.Change{
|
||||
Change: diff.Change{
|
||||
Type: diff.UPDATE,
|
||||
Path: []string{"ResourcePath"},
|
||||
From: "/",
|
||||
To: "/bad",
|
||||
},
|
||||
Computed: false,
|
||||
},
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
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 CloudfrontDistributionDeserializer struct {
|
||||
}
|
||||
|
||||
func NewCloudfrontDistributionDeserializer() *CloudfrontDistributionDeserializer {
|
||||
return &CloudfrontDistributionDeserializer{}
|
||||
}
|
||||
|
||||
func (s *CloudfrontDistributionDeserializer) HandledType() resource.ResourceType {
|
||||
return resourceaws.AwsCloudfrontDistributionResourceType
|
||||
}
|
||||
|
||||
func (s CloudfrontDistributionDeserializer) Deserialize(rawList []cty.Value) ([]resource.Resource, error) {
|
||||
resources := make([]resource.Resource, 0)
|
||||
for _, rawResource := range rawList {
|
||||
rawResource := rawResource
|
||||
resource, err := decodeCloudfrontDistribution(&rawResource)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"type": s.HandledType(),
|
||||
}).Warnf("Error when deserializing resource %+v : %+v", rawResource, err)
|
||||
return nil, err
|
||||
}
|
||||
resources = append(resources, resource)
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func decodeCloudfrontDistribution(raw *cty.Value) (*resourceaws.AwsCloudfrontDistribution, error) {
|
||||
var decoded resourceaws.AwsCloudfrontDistribution
|
||||
if err := gocty.FromCtyValue(*raw, &decoded); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decoded, nil
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
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 Route53HealthCheckDeserializer struct {
|
||||
}
|
||||
|
||||
func NewRoute53HealthCheckDeserializer() *Route53HealthCheckDeserializer {
|
||||
return &Route53HealthCheckDeserializer{}
|
||||
}
|
||||
|
||||
func (s *Route53HealthCheckDeserializer) HandledType() resource.ResourceType {
|
||||
return resourceaws.AwsRoute53HealthCheckResourceType
|
||||
}
|
||||
|
||||
func (s Route53HealthCheckDeserializer) Deserialize(rawList []cty.Value) ([]resource.Resource, error) {
|
||||
resources := make([]resource.Resource, 0)
|
||||
for _, rawResource := range rawList {
|
||||
rawResource := rawResource
|
||||
resource, err := decodeRoute53HealthCheck(&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 decodeRoute53HealthCheck(raw *cty.Value) (*resourceaws.AwsRoute53HealthCheck, error) {
|
||||
var decoded resourceaws.AwsRoute53HealthCheck
|
||||
if err := gocty.FromCtyValue(*raw, &decoded); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decoded, nil
|
||||
}
|
37
pkg/resource/aws/testdata/acc/aws_cloudfront_distribution/.terraform.lock.hcl
vendored
Normal file
37
pkg/resource/aws/testdata/acc/aws_cloudfront_distribution/.terraform.lock.hcl
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
# 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:xur9tF49NgsovNnmwmBR8RdpN8Fcg1TD4CKQPJD6n1A=",
|
||||
"zh:185a5259153eb9ee4699d4be43b3d509386b473683392034319beee97d470c3b",
|
||||
"zh:2d9a0a01f93e8d16539d835c02b8b6e1927b7685f4076e96cb07f7dd6944bc6c",
|
||||
"zh:703f6da36b1b5f3497baa38fccaa7765fb8a2b6440344e4c97172516b49437dd",
|
||||
"zh:770855565462abadbbddd98cb357d2f1a8f30f68a358cb37cbd5c072cb15b377",
|
||||
"zh:8008db43149fe4345301f81e15e6d9ddb47aa5e7a31648f9b290af96ad86e92a",
|
||||
"zh:8cdd27d375da6dcb7687f1fed126b7c04efce1671066802ee876dbbc9c66ec79",
|
||||
"zh:be22ae185005690d1a017c1b909e0d80ab567e239b4f06ecacdba85080667c1c",
|
||||
"zh:d2d02e72dbd80f607636cd6237a6c862897caabc635c7b50c0cb243d11246723",
|
||||
"zh:d8f125b66a1eda2555c0f9bbdf12036a5f8d073499a22ca9e4812b68067fea31",
|
||||
"zh:f5a98024c64d5d2973ff15b093725a074c0cb4afde07ef32c542e69f17ac90bc",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.0.1"
|
||||
hashes = [
|
||||
"h1:0QaSbRBgBi8vI/8IRwec1INdOqBxXbgsSFElx1O4k4g=",
|
||||
"zh:0d4f683868324af056a9eb2b06306feef7c202c88dbbe6a4ad7517146a22fb50",
|
||||
"zh:4824b3c7914b77d41dfe90f6f333c7ac9860afb83e2a344d91fbe46e5dfbec26",
|
||||
"zh:4b82e43712f3cf0d0cbc95b2cbcd409ba8f0dc7848fdfb7c13633c27468ed04a",
|
||||
"zh:78b3a2b860c3ebc973a794000015f5946eb59b82705d701d487475406b2612f1",
|
||||
"zh:88bc65197bd74ff408d147b32f0045372ae3a3f2a2fdd7f734f315d988c0e4a2",
|
||||
"zh:91bd3c9f625f177f3a5d641a64e54d4b4540cb071070ecda060a8261fb6eb2ef",
|
||||
"zh:a6818842b28d800f784e0c93284ff602b0c4022f407e4750da03f50b853a9a2c",
|
||||
"zh:c4a1a2b52abd05687e6cfded4a789dcd7b43e7a746e4d02dd1055370cf9a994d",
|
||||
"zh:cf65041bf12fc3bde709c1d267dbe94142bc05adcabc4feb17da3b12249132ac",
|
||||
"zh:e385e00e7425dda9d30b74ab4ffa4636f4b8eb23918c0b763f0ffab84ece0c5c",
|
||||
]
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = "3.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_string" "prefix" {
|
||||
length = 6
|
||||
upper = false
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "foo_cloudfront" {
|
||||
bucket = "${random_string.prefix.result}.foo-cloudfront"
|
||||
acl = "private"
|
||||
}
|
||||
|
||||
locals {
|
||||
s3_origin_id = "S3-foo-cloudfront"
|
||||
}
|
||||
|
||||
resource "aws_cloudfront_distribution" "foo_distribution" {
|
||||
enabled = false
|
||||
|
||||
origin {
|
||||
domain_name = aws_s3_bucket.foo_cloudfront.bucket_regional_domain_name
|
||||
origin_id = local.s3_origin_id
|
||||
}
|
||||
|
||||
default_cache_behavior {
|
||||
allowed_methods = ["GET", "HEAD"]
|
||||
cached_methods = ["GET", "HEAD"]
|
||||
target_origin_id = local.s3_origin_id
|
||||
viewer_protocol_policy = "allow-all"
|
||||
|
||||
forwarded_values {
|
||||
query_string = false
|
||||
|
||||
cookies {
|
||||
forward = "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restrictions {
|
||||
geo_restriction {
|
||||
restriction_type = "none"
|
||||
}
|
||||
}
|
||||
|
||||
viewer_certificate {
|
||||
cloudfront_default_certificate = true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/aws" {
|
||||
version = "3.28.0"
|
||||
hashes = [
|
||||
"h1:zejsAukFmgZCOdQCk44L3cumXFs8YDSltRIjZN+izsU=",
|
||||
"zh:1fee7fce319be5bea7df2e95f28a78a04e15c18bad5eb56dcc0ecc324c97f4b8",
|
||||
"zh:2383ff31ef7411f7d4bef1ee288f0f79bec41cf220ac94c2b31f6a702b26f984",
|
||||
"zh:2f450372a8aa7d32f62524159a5930e0251ba34f491d66f00239452a6d575921",
|
||||
"zh:379d4fdc16a2245b50959f5bfcb24c71fb74b292b6cf9c2d267b6ce94dddd208",
|
||||
"zh:9fd1078759edd79548ec52c6853668a69f22803c92c0ac202f5c43c1ace63ac0",
|
||||
"zh:aef544e720ce79f97875cc4ef5dd163922e9f47a496e663d0a272e881d2dd32e",
|
||||
"zh:e2f28ba5bde0403f3273e80860a80ab5e63420e0142c0e8e283b651b750a8ffe",
|
||||
"zh:ebc859186fcdd4700cc7091a8ecf4e06cc6d2eceadaeadda0d0e49efc6456325",
|
||||
"zh:ee7bced0660945206c6226de35ae465b52e406b12e9ff1075186af37962caa6f",
|
||||
"zh:f33063481894f951ff1e76b94a8311041a4bd3f1f1f01d1a8580d6c893e13c2c",
|
||||
]
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
resource "aws_route53_health_check" "http" {
|
||||
fqdn = "moadib.net"
|
||||
port = 80
|
||||
type = "HTTP"
|
||||
resource_path = "/"
|
||||
failure_threshold = "5"
|
||||
request_interval = "30"
|
||||
|
||||
tags = {
|
||||
Name = "http-moadib-net"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route53_health_check" "https" {
|
||||
failure_threshold = "5"
|
||||
fqdn = "moadib.net"
|
||||
port = 443
|
||||
request_interval = "30"
|
||||
resource_path = "/"
|
||||
search_string = "MoAdiB"
|
||||
type = "HTTPS_STR_MATCH"
|
||||
}
|
|
@ -38,14 +38,15 @@ type AccCheck struct {
|
|||
}
|
||||
|
||||
type AccTestCase struct {
|
||||
Path string
|
||||
Args []string
|
||||
OnStart func()
|
||||
OnEnd func()
|
||||
Checks []AccCheck
|
||||
tmpResultFilePath string
|
||||
originalEnv []string
|
||||
tf *tfexec.Terraform
|
||||
Path string
|
||||
Args []string
|
||||
OnStart func()
|
||||
OnEnd func()
|
||||
Checks []AccCheck
|
||||
tmpResultFilePath string
|
||||
originalEnv []string
|
||||
tf *tfexec.Terraform
|
||||
ShouldRefreshBeforeDestroy bool
|
||||
}
|
||||
|
||||
func (c *AccTestCase) initTerraformExecutor() error {
|
||||
|
@ -167,6 +168,12 @@ func (c *AccTestCase) terraformApply() error {
|
|||
}
|
||||
|
||||
func (c *AccTestCase) terraformDestroy() error {
|
||||
if c.ShouldRefreshBeforeDestroy {
|
||||
if err := c.terraformRefresh(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debug("Running terraform destroy ...")
|
||||
stderr := new(bytes.Buffer)
|
||||
c.tf.SetStderr(stderr)
|
||||
|
@ -178,6 +185,18 @@ func (c *AccTestCase) terraformDestroy() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *AccTestCase) terraformRefresh() error {
|
||||
logrus.Debug("Running terraform refresh ...")
|
||||
stderr := new(bytes.Buffer)
|
||||
c.tf.SetStderr(stderr)
|
||||
if err := c.tf.Refresh(context.Background()); err != nil {
|
||||
return errors.Wrap(err, stderr.String())
|
||||
}
|
||||
logrus.Debug("Terraform refresh done")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runDriftCtlCmd(driftctlCmd *cmd.DriftctlCmd) (*cobra.Command, string, error) {
|
||||
old := os.Stdout // keep backup of the real stdout
|
||||
r, w, _ := os.Pipe()
|
||||
|
|
Loading…
Reference in New Issue