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)
|
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)
|
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
|
### Usage
|
||||||
|
|
||||||
- Commands
|
- Commands
|
||||||
|
|
|
@ -63,6 +63,9 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
||||||
"Effect": "Allow",
|
"Effect": "Allow",
|
||||||
"Resource": "*",
|
"Resource": "*",
|
||||||
"Action": [
|
"Action": [
|
||||||
|
"cloudfront:GetDistribution",
|
||||||
|
"cloudfront:ListDistributions",
|
||||||
|
"cloudfront:ListTagsForResource",
|
||||||
"ec2:DescribeAddresses",
|
"ec2:DescribeAddresses",
|
||||||
"ec2:DescribeImages",
|
"ec2:DescribeImages",
|
||||||
"ec2:DescribeInstanceAttribute",
|
"ec2:DescribeInstanceAttribute",
|
||||||
|
@ -107,6 +110,8 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
||||||
"route53:ListHostedZones",
|
"route53:ListHostedZones",
|
||||||
"route53:ListResourceRecordSets",
|
"route53:ListResourceRecordSets",
|
||||||
"route53:ListTagsForResource",
|
"route53:ListTagsForResource",
|
||||||
|
"route53:ListHealthChecks",
|
||||||
|
"route53:GetHealthCheck",
|
||||||
"s3:GetAccelerateConfiguration",
|
"s3:GetAccelerateConfiguration",
|
||||||
"s3:GetAnalyticsConfiguration",
|
"s3:GetAnalyticsConfiguration",
|
||||||
"s3:GetBucketAcl",
|
"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_record
|
||||||
- [x] aws_route53_zone
|
- [x] aws_route53_zone
|
||||||
- [ ] aws_route53_delegation_set
|
- [ ] aws_route53_delegation_set
|
||||||
- [ ] aws_route53_health_check
|
- [x] aws_route53_health_check
|
||||||
- [ ] aws_route53_query_log
|
- [ ] aws_route53_query_log
|
||||||
- [ ] aws_route53_vpc_association_authorization
|
- [ ] aws_route53_vpc_association_authorization
|
||||||
- [ ] aws_route53_zone_association
|
- [ ] 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
|
- [x] aws_sqs_queue_policy
|
||||||
|
|
||||||
## SNS
|
## SNS
|
||||||
|
|
||||||
- [x] aws_sns_topic
|
- [x] aws_sns_topic
|
||||||
- [x] aws_sns_topic_policy
|
- [x] aws_sns_topic_policy
|
||||||
- [x] aws_sns_topic_subscription
|
- [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
|
- [ ] aws_sns_sms_preferences
|
||||||
|
|
||||||
## DynamoDB
|
## DynamoDB
|
||||||
|
|
||||||
- [x] aws_dynamodb_table
|
- [x] aws_dynamodb_table
|
||||||
- [ ] aws_dynamodb_global_table
|
- [ ] aws_dynamodb_global_table
|
||||||
- [ ] aws_dynamodb_table_item
|
- [ ] 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
|
package alerter
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
type Alerts map[string][]Alert
|
type Alerts map[string][]Alert
|
||||||
|
|
||||||
type Alert struct {
|
type Alert interface {
|
||||||
Message string `json:"message"`
|
Message() string
|
||||||
ShouldIgnoreResource bool `json:"-"`
|
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 {
|
func (a *Alerter) shouldBeIgnored(alert []Alert) bool {
|
||||||
for _, a := range alert {
|
for _, a := range alert {
|
||||||
if a.ShouldIgnoreResource {
|
if a.ShouldIgnoreResource() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,18 +23,12 @@ func TestAlerter_Alert(t *testing.T) {
|
||||||
name: "TestWithSingleAlert",
|
name: "TestWithSingleAlert",
|
||||||
alerts: Alerts{
|
alerts: Alerts{
|
||||||
"fakeres.foobar": []Alert{
|
"fakeres.foobar": []Alert{
|
||||||
{
|
&FakeAlert{"This is an alert", false},
|
||||||
Message: "This is an alert",
|
|
||||||
ShouldIgnoreResource: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: Alerts{
|
expected: Alerts{
|
||||||
"fakeres.foobar": []Alert{
|
"fakeres.foobar": []Alert{
|
||||||
{
|
&FakeAlert{"This is an alert", false},
|
||||||
Message: "This is an alert",
|
|
||||||
ShouldIgnoreResource: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -42,38 +36,20 @@ func TestAlerter_Alert(t *testing.T) {
|
||||||
name: "TestWithMultipleAlerts",
|
name: "TestWithMultipleAlerts",
|
||||||
alerts: Alerts{
|
alerts: Alerts{
|
||||||
"fakeres.foobar": []Alert{
|
"fakeres.foobar": []Alert{
|
||||||
{
|
&FakeAlert{"This is an alert", false},
|
||||||
Message: "This is an alert",
|
&FakeAlert{"This is a second alert", true},
|
||||||
ShouldIgnoreResource: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Message: "This is a second alert",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"fakeres.barfoo": []Alert{
|
"fakeres.barfoo": []Alert{
|
||||||
{
|
&FakeAlert{"This is a third alert", true},
|
||||||
Message: "This is a third alert",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: Alerts{
|
expected: Alerts{
|
||||||
"fakeres.foobar": []Alert{
|
"fakeres.foobar": []Alert{
|
||||||
{
|
&FakeAlert{"This is an alert", false},
|
||||||
Message: "This is an alert",
|
&FakeAlert{"This is a second alert", true},
|
||||||
ShouldIgnoreResource: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Message: "This is a second alert",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"fakeres.barfoo": []Alert{
|
"fakeres.barfoo": []Alert{
|
||||||
{
|
&FakeAlert{"This is a third alert", true},
|
||||||
Message: "This is a third alert",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -116,24 +92,16 @@ func TestAlerter_IgnoreResources(t *testing.T) {
|
||||||
name: "TestShouldNotBeIgnoredWithAlerts",
|
name: "TestShouldNotBeIgnoredWithAlerts",
|
||||||
alerts: Alerts{
|
alerts: Alerts{
|
||||||
"fakeres": {
|
"fakeres": {
|
||||||
{
|
&FakeAlert{"Should not be ignored", false},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"fakeres.foobar": {
|
"fakeres.foobar": {
|
||||||
{
|
&FakeAlert{"Should not be ignored", false},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"fakeres.barfoo": {
|
"fakeres.barfoo": {
|
||||||
{
|
&FakeAlert{"Should not be ignored", false},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.resource": {
|
"other.resource": {
|
||||||
{
|
&FakeAlert{"Should not be ignored", false},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resource: &resource2.FakeResource{
|
resource: &resource2.FakeResource{
|
||||||
|
@ -146,21 +114,13 @@ func TestAlerter_IgnoreResources(t *testing.T) {
|
||||||
name: "TestShouldBeIgnoredWithAlertsOnWildcard",
|
name: "TestShouldBeIgnoredWithAlertsOnWildcard",
|
||||||
alerts: Alerts{
|
alerts: Alerts{
|
||||||
"fakeres": {
|
"fakeres": {
|
||||||
{
|
&FakeAlert{"Should be ignored", true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.foobaz": {
|
"other.foobaz": {
|
||||||
{
|
&FakeAlert{"Should be ignored", true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.resource": {
|
"other.resource": {
|
||||||
{
|
&FakeAlert{"Should not be ignored", false},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resource: &resource2.FakeResource{
|
resource: &resource2.FakeResource{
|
||||||
|
@ -173,21 +133,13 @@ func TestAlerter_IgnoreResources(t *testing.T) {
|
||||||
name: "TestShouldBeIgnoredWithAlertsOnResource",
|
name: "TestShouldBeIgnoredWithAlertsOnResource",
|
||||||
alerts: Alerts{
|
alerts: Alerts{
|
||||||
"fakeres": {
|
"fakeres": {
|
||||||
{
|
&FakeAlert{"Should be ignored", true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.foobaz": {
|
"other.foobaz": {
|
||||||
{
|
&FakeAlert{"Should be ignored", true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.resource": {
|
"other.resource": {
|
||||||
{
|
&FakeAlert{"Should not be ignored", false},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resource: &resource2.FakeResource{
|
resource: &resource2.FakeResource{
|
||||||
|
|
|
@ -43,13 +43,13 @@ type serializableDifference struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type serializableAnalysis struct {
|
type serializableAnalysis struct {
|
||||||
Summary Summary `json:"summary"`
|
Summary Summary `json:"summary"`
|
||||||
Managed []resource.SerializableResource `json:"managed"`
|
Managed []resource.SerializableResource `json:"managed"`
|
||||||
Unmanaged []resource.SerializableResource `json:"unmanaged"`
|
Unmanaged []resource.SerializableResource `json:"unmanaged"`
|
||||||
Deleted []resource.SerializableResource `json:"deleted"`
|
Deleted []resource.SerializableResource `json:"deleted"`
|
||||||
Differences []serializableDifference `json:"differences"`
|
Differences []serializableDifference `json:"differences"`
|
||||||
Coverage int `json:"coverage"`
|
Coverage int `json:"coverage"`
|
||||||
Alerts alerter.Alerts `json:"alerts"`
|
Alerts map[string][]alerter.SerializableAlert `json:"alerts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Analysis) MarshalJSON() ([]byte, error) {
|
func (a Analysis) MarshalJSON() ([]byte, error) {
|
||||||
|
@ -69,9 +69,16 @@ func (a Analysis) MarshalJSON() ([]byte, error) {
|
||||||
Changelog: di.Changelog,
|
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.Summary = a.summary
|
||||||
bla.Coverage = a.Coverage()
|
bla.Coverage = a.Coverage()
|
||||||
bla.Alerts = a.alerts
|
|
||||||
|
|
||||||
return json.Marshal(bla)
|
return json.Marshal(bla)
|
||||||
}
|
}
|
||||||
|
@ -108,7 +115,16 @@ func (a *Analysis) UnmarshalJSON(bytes []byte) error {
|
||||||
Changelog: di.Changelog,
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,34 @@ import (
|
||||||
"github.com/r3labs/diff/v2"
|
"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 {
|
type Analyzer struct {
|
||||||
alerter *alerter.Alerter
|
alerter *alerter.Alerter
|
||||||
}
|
}
|
||||||
|
@ -80,17 +108,11 @@ func (a Analyzer) Analyze(remoteResources, resourcesFromState []resource.Resourc
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.hasUnmanagedSecurityGroupRules(filteredRemoteResource) {
|
if a.hasUnmanagedSecurityGroupRules(filteredRemoteResource) {
|
||||||
a.alerter.SendAlert("",
|
a.alerter.SendAlert("", newUnmanagedSecurityGroupRulesAlert())
|
||||||
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",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if haveComputedDiff {
|
if haveComputedDiff {
|
||||||
a.alerter.SendAlert("",
|
a.alerter.SendAlert("", NewComputedDiffAlert())
|
||||||
alerter.Alert{
|
|
||||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add remaining unmanaged resources
|
// Add remaining unmanaged resources
|
||||||
|
|
|
@ -272,9 +272,7 @@ func TestAnalyze(t *testing.T) {
|
||||||
},
|
},
|
||||||
alerts: alerter.Alerts{
|
alerts: alerter.Alerts{
|
||||||
"": {
|
"": {
|
||||||
{
|
NewComputedDiffAlert(),
|
||||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -351,9 +349,7 @@ func TestAnalyze(t *testing.T) {
|
||||||
},
|
},
|
||||||
alerts: alerter.Alerts{
|
alerts: alerter.Alerts{
|
||||||
"": {
|
"": {
|
||||||
{
|
NewComputedDiffAlert(),
|
||||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -520,21 +516,13 @@ func TestAnalyze(t *testing.T) {
|
||||||
},
|
},
|
||||||
alerts: alerter.Alerts{
|
alerts: alerter.Alerts{
|
||||||
"fakeres": {
|
"fakeres": {
|
||||||
{
|
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.foobaz": {
|
"other.foobaz": {
|
||||||
{
|
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.resource": {
|
"other.resource": {
|
||||||
{
|
&alerter.FakeAlert{Msg: "Should not be ignored"},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: Analysis{
|
expected: Analysis{
|
||||||
|
@ -656,26 +644,16 @@ func TestAnalyze(t *testing.T) {
|
||||||
},
|
},
|
||||||
alerts: alerter.Alerts{
|
alerts: alerter.Alerts{
|
||||||
"fakeres": {
|
"fakeres": {
|
||||||
{
|
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.foobaz": {
|
"other.foobaz": {
|
||||||
{
|
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
|
||||||
Message: "Should be ignored",
|
|
||||||
ShouldIgnoreResource: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other.resource": {
|
"other.resource": {
|
||||||
{
|
&alerter.FakeAlert{Msg: "Should not be ignored"},
|
||||||
Message: "Should not be ignored",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"": {
|
"": {
|
||||||
{
|
NewComputedDiffAlert(),
|
||||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -875,9 +853,7 @@ func TestAnalyze(t *testing.T) {
|
||||||
},
|
},
|
||||||
alerts: alerter.Alerts{
|
alerts: alerter.Alerts{
|
||||||
"": {
|
"": {
|
||||||
{
|
NewComputedDiffAlert(),
|
||||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -916,9 +892,7 @@ func TestAnalyze(t *testing.T) {
|
||||||
},
|
},
|
||||||
alerts: alerter.Alerts{
|
alerts: alerter.Alerts{
|
||||||
"": {
|
"": {
|
||||||
{
|
newUnmanagedSecurityGroupRulesAlert(),
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1069,9 +1043,7 @@ func TestAnalysis_MarshalJSON(t *testing.T) {
|
||||||
})
|
})
|
||||||
analysis.SetAlerts(alerter.Alerts{
|
analysis.SetAlerts(alerter.Alerts{
|
||||||
"aws_iam_access_key": {
|
"aws_iam_access_key": {
|
||||||
{
|
&alerter.FakeAlert{Msg: "This is an alert"},
|
||||||
Message: "This is an alert",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1151,8 +1123,8 @@ func TestAnalysis_UnmarshalJSON(t *testing.T) {
|
||||||
},
|
},
|
||||||
alerts: alerter.Alerts{
|
alerts: alerter.Alerts{
|
||||||
"aws_iam_access_key": {
|
"aws_iam_access_key": {
|
||||||
{
|
&alerter.SerializedAlert{
|
||||||
Message: "This is an alert",
|
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, 2, got.Summary().TotalDeleted)
|
||||||
assert.Equal(t, 6, got.Summary().TotalResources)
|
assert.Equal(t, 6, got.Summary().TotalResources)
|
||||||
assert.Equal(t, 1, got.Summary().TotalDrifted)
|
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"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/remote"
|
||||||
|
|
||||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
@ -93,12 +95,21 @@ func (c *Console) Write(analysis *analyser.Analysis) error {
|
||||||
|
|
||||||
c.writeSummary(analysis)
|
c.writeSummary(analysis)
|
||||||
|
|
||||||
|
policy := false
|
||||||
for _, alerts := range analysis.Alerts() {
|
for _, alerts := range analysis.Alerts() {
|
||||||
for _, alert := range 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,12 @@ func TestConsole_Write(t *testing.T) {
|
||||||
args: args{analysis: fakeAnalysisWithComputedFields()},
|
args: args{analysis: fakeAnalysisWithComputedFields()},
|
||||||
wantErr: false,
|
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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -38,6 +38,14 @@ func TestJSON_Write(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantErr: false,
|
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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/cloudskiff/driftctl/pkg/alerter"
|
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/remote"
|
||||||
testresource "github.com/cloudskiff/driftctl/test/resource"
|
testresource "github.com/cloudskiff/driftctl/test/resource"
|
||||||
"github.com/r3labs/diff/v2"
|
"github.com/r3labs/diff/v2"
|
||||||
)
|
)
|
||||||
|
@ -230,9 +231,19 @@ func fakeAnalysisWithComputedFields() *analyser.Analysis {
|
||||||
}})
|
}})
|
||||||
a.SetAlerts(alerter.Alerts{
|
a.SetAlerts(alerter.Alerts{
|
||||||
"": []alerter.Alert{
|
"": []alerter.Alert{
|
||||||
{
|
analyser.NewComputedDiffAlert(),
|
||||||
Message: "You have diffs on computed fields, check the documentation for potential false positive drifts",
|
},
|
||||||
},
|
})
|
||||||
|
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
|
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.NewSNSTopicPolicyDeserializer(),
|
||||||
awsdeserializer.NewSNSTopicSubscriptionDeserializer(),
|
awsdeserializer.NewSNSTopicSubscriptionDeserializer(),
|
||||||
awsdeserializer.NewDynamoDBTableDeserializer(),
|
awsdeserializer.NewDynamoDBTableDeserializer(),
|
||||||
|
awsdeserializer.NewRoute53HealthCheckDeserializer(),
|
||||||
|
awsdeserializer.NewCloudfrontDistributionDeserializer(),
|
||||||
|
|
||||||
ghdeserializer.NewGithubRepositoryDeserializer(),
|
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 Policy", dirName: "sns_topic_policy", wantErr: false},
|
||||||
{name: "SNS Topic Subscription", dirName: "sns_topic_subscription", wantErr: false},
|
{name: "SNS Topic Subscription", dirName: "sns_topic_subscription", wantErr: false},
|
||||||
{name: "DynamoDB table", dirName: "dynamodb_table", 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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
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"
|
"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
|
// Explodes routes found in aws_default_route_table.route and aws_route_table.route to dedicated resources
|
||||||
type AwsRouteTableExpander struct {
|
type AwsRouteTableExpander struct {
|
||||||
alerter alerter.AlerterInterface
|
alerter alerter.AlerterInterface
|
||||||
|
@ -60,9 +77,7 @@ func (m *AwsRouteTableExpander) handleTable(table *aws.AwsRouteTable, results *[
|
||||||
for _, route := range *table.Route {
|
for _, route := range *table.Route {
|
||||||
routeId, err := aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock)
|
routeId, err := aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.alerter.SendAlert(aws.AwsRouteTableResourceType, alerter.Alert{
|
m.alerter.SendAlert(aws.AwsRouteTableResourceType, newInvalidRouteAlert(aws.AwsRouteTableResourceType, table.Id))
|
||||||
Message: fmt.Sprintf("Skipped invalid route found in state for %s.%s", aws.AwsRouteTableResourceType, table.Id),
|
|
||||||
})
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newRouteFromTable := &aws.AwsRoute{
|
newRouteFromTable := &aws.AwsRoute{
|
||||||
|
@ -107,9 +122,7 @@ func (m *AwsRouteTableExpander) handleDefaultTable(table *aws.AwsDefaultRouteTab
|
||||||
for _, route := range *table.Route {
|
for _, route := range *table.Route {
|
||||||
routeId, err := aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock)
|
routeId, err := aws.CalculateRouteID(&table.Id, route.CidrBlock, route.Ipv6CidrBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.alerter.SendAlert(aws.AwsDefaultRouteTableResourceType, alerter.Alert{
|
m.alerter.SendAlert(aws.AwsDefaultRouteTableResourceType, newInvalidRouteAlert(aws.AwsDefaultRouteTableResourceType, table.Id))
|
||||||
Message: fmt.Sprintf("Skipped invalid route found in state for %s.%s", aws.AwsDefaultRouteTableResourceType, table.Id),
|
|
||||||
})
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newRouteFromTable := &aws.AwsRoute{
|
newRouteFromTable := &aws.AwsRoute{
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
awssdk "github.com/aws/aws-sdk-go/aws"
|
awssdk "github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||||
"github.com/cloudskiff/driftctl/mocks"
|
"github.com/cloudskiff/driftctl/mocks"
|
||||||
"github.com/cloudskiff/driftctl/pkg/alerter"
|
|
||||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||||
resource2 "github.com/cloudskiff/driftctl/test/resource"
|
resource2 "github.com/cloudskiff/driftctl/test/resource"
|
||||||
|
@ -215,12 +214,12 @@ func TestAwsRouteTableExpander_Execute(t *testing.T) {
|
||||||
func TestAwsRouteTableExpander_ExecuteWithInvalidRoutes(t *testing.T) {
|
func TestAwsRouteTableExpander_ExecuteWithInvalidRoutes(t *testing.T) {
|
||||||
|
|
||||||
mockedAlerter := &mocks.AlerterInterface{}
|
mockedAlerter := &mocks.AlerterInterface{}
|
||||||
mockedAlerter.On("SendAlert", aws.AwsRouteTableResourceType, alerter.Alert{
|
mockedAlerter.On("SendAlert", aws.AwsRouteTableResourceType, newInvalidRouteAlert(
|
||||||
Message: "Skipped invalid route found in state for aws_route_table.table_from_state",
|
"aws_route_table", "table_from_state",
|
||||||
})
|
))
|
||||||
mockedAlerter.On("SendAlert", aws.AwsDefaultRouteTableResourceType, alerter.Alert{
|
mockedAlerter.On("SendAlert", aws.AwsDefaultRouteTableResourceType, newInvalidRouteAlert(
|
||||||
Message: "Skipped invalid route found in state for aws_default_route_table.default_table_from_state",
|
"aws_default_route_table", "default_table_from_state",
|
||||||
})
|
))
|
||||||
|
|
||||||
input := []resource.Resource{
|
input := []resource.Resource{
|
||||||
&aws.AwsRouteTable{
|
&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(NewSNSTopicPolicySupplier(provider))
|
||||||
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider))
|
supplierLibrary.AddSupplier(NewSNSTopicSubscriptionSupplier(provider))
|
||||||
supplierLibrary.AddSupplier(NewDynamoDBTableSupplier(provider))
|
supplierLibrary.AddSupplier(NewDynamoDBTableSupplier(provider))
|
||||||
|
supplierLibrary.AddSupplier(NewRoute53HealthCheckSupplier(provider))
|
||||||
|
supplierLibrary.AddSupplier(NewCloudfrontDistributionSupplier(provider))
|
||||||
|
|
||||||
return nil
|
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"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/cloudskiff/driftctl/pkg/alerter"
|
"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 {
|
func HandleResourceEnumerationError(err error, alertr *alerter.Alerter) error {
|
||||||
listError, ok := err.(*remoteerror.ResourceEnumerationError)
|
listError, ok := err.(*remoteerror.ResourceEnumerationError)
|
||||||
if !ok {
|
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")) {
|
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.WithFields(logrus.Fields{
|
||||||
logrus.Debugf(message)
|
"supplier_type": listError.SupplierType(),
|
||||||
alertr.SendAlert(listError.SupplierType(), alerter.Alert{
|
"listed_type": listError.ListedTypeError(),
|
||||||
Message: message,
|
}).Debugf("Got an access denied error")
|
||||||
ShouldIgnoreResource: true,
|
alertr.SendAlert(listError.SupplierType(), NewEnumerationAccessDeniedAlert(listError.SupplierType(), listError.ListedTypeError()))
|
||||||
})
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,13 @@ func TestHandleListAwsError(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "Handled error 403",
|
name: "Handled error 403",
|
||||||
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(awserr.New("", "", errors.New("")), 403, ""), resourceaws.AwsVpcResourceType),
|
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,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Handled error AccessDenied",
|
name: "Handled error AccessDenied",
|
||||||
err: remoteerror.NewResourceEnumerationError(awserr.NewRequestFailure(awserr.New("AccessDeniedException", "", errors.New("")), 403, ""), resourceaws.AwsDynamodbTableResourceType),
|
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,
|
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 {
|
type AccTestCase struct {
|
||||||
Path string
|
Path string
|
||||||
Args []string
|
Args []string
|
||||||
OnStart func()
|
OnStart func()
|
||||||
OnEnd func()
|
OnEnd func()
|
||||||
Checks []AccCheck
|
Checks []AccCheck
|
||||||
tmpResultFilePath string
|
tmpResultFilePath string
|
||||||
originalEnv []string
|
originalEnv []string
|
||||||
tf *tfexec.Terraform
|
tf *tfexec.Terraform
|
||||||
|
ShouldRefreshBeforeDestroy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AccTestCase) initTerraformExecutor() error {
|
func (c *AccTestCase) initTerraformExecutor() error {
|
||||||
|
@ -167,6 +168,12 @@ func (c *AccTestCase) terraformApply() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AccTestCase) terraformDestroy() error {
|
func (c *AccTestCase) terraformDestroy() error {
|
||||||
|
if c.ShouldRefreshBeforeDestroy {
|
||||||
|
if err := c.terraformRefresh(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logrus.Debug("Running terraform destroy ...")
|
logrus.Debug("Running terraform destroy ...")
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
c.tf.SetStderr(stderr)
|
c.tf.SetStderr(stderr)
|
||||||
|
@ -178,6 +185,18 @@ func (c *AccTestCase) terraformDestroy() error {
|
||||||
return nil
|
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) {
|
func runDriftCtlCmd(driftctlCmd *cmd.DriftctlCmd) (*cobra.Command, string, error) {
|
||||||
old := os.Stdout // keep backup of the real stdout
|
old := os.Stdout // keep backup of the real stdout
|
||||||
r, w, _ := os.Pipe()
|
r, w, _ := os.Pipe()
|
||||||
|
|
Loading…
Reference in New Issue