Skip to content

Commit

Permalink
Merge pull request #75 from cloudskiff/stronger_state_reader
Browse files Browse the repository at this point in the history
Ignore unknown attributes error in state
  • Loading branch information
eliecharra authored Jan 6, 2021
2 parents 6daffa8 + 896edb9 commit e131550
Show file tree
Hide file tree
Showing 5 changed files with 172,089 additions and 12 deletions.
69 changes: 59 additions & 10 deletions pkg/iac/terraform/state/terraform_state_reader.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package state

import (
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
"github.com/hashicorp/terraform/addrs"

"github.com/cloudskiff/driftctl/pkg/iac"
"github.com/cloudskiff/driftctl/pkg/iac/config"
"github.com/cloudskiff/driftctl/pkg/iac/terraform/state/backend"
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"

"github.com/hashicorp/terraform/states/statefile"

"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/states/statefile"
"github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
ctyconvert "github.com/zclconf/go-cty/cty/convert"
ctyjson "github.com/zclconf/go-cty/cty/json"
)

const TerraformStateReaderSupplier = "tfstate"
Expand Down Expand Up @@ -54,11 +53,13 @@ func (r *TerraformStateReader) retrieve() (map[string][]cty.Value, error) {
stateResources := state.RootModule().Resources
resMap := make(map[string][]cty.Value)
for _, stateRes := range stateResources {
resName := stateRes.Addr.Resource.Name
resType := stateRes.Addr.Resource.Type
if stateRes.Addr.Resource.Mode != addrs.ManagedResourceMode {
logrus.WithFields(logrus.Fields{
"mode": stateRes.Addr.Resource.Mode,
"name": stateRes.Addr.Resource.Name,
"type": stateRes.Addr.Resource.Type,
"name": resName,
"type": resType,
}).Debug("Skipping state entry as it is not a managed resource")
continue
}
Expand All @@ -74,8 +75,28 @@ func (r *TerraformStateReader) retrieve() (map[string][]cty.Value, error) {
for _, instance := range stateRes.Instances {
decodedVal, err := instance.Current.Decode(schema.Block.ImpliedType())
if err != nil {
logrus.Error(err)
continue
// Try to do a manual type conversion if we got a path error
// It will allow driftctl to read state generated with a superior version of provider
// than the actually supported one
// by ignoring new fields
_, isPathError := err.(cty.PathError)
if isPathError {
logrus.WithFields(logrus.Fields{
"name": resName,
"type": resType,
"err": err.Error(),
}).Debug("Got a cty path error when deserializing state")

decodedVal, err = r.convertInstance(instance.Current, schema.Block.ImpliedType())
}

if err != nil {
logrus.WithFields(logrus.Fields{
"name": resName,
"type": resType,
}).Error("Unable to decode resource from state")
return nil, err
}
}
_, exists := resMap[stateRes.Addr.Resource.Type]
if !exists {
Expand All @@ -91,6 +112,34 @@ func (r *TerraformStateReader) retrieve() (map[string][]cty.Value, error) {
return resMap, nil
}

func (r *TerraformStateReader) convertInstance(instance *states.ResourceInstanceObjectSrc, ty cty.Type) (*states.ResourceInstanceObject, error) {
inputType, err := ctyjson.ImpliedType(instance.AttrsJSON)
if err != nil {
return nil, err
}
input, err := ctyjson.Unmarshal(instance.AttrsJSON, inputType)
if err != nil {
return nil, err
}

convertedVal, err := ctyconvert.Convert(input, ty)
if err != nil {
return nil, err
}

instanceObj := &states.ResourceInstanceObject{
Value: convertedVal,
Status: instance.Status,
Dependencies: instance.Dependencies,
Private: instance.Private,
CreateBeforeDestroy: instance.CreateBeforeDestroy,
}

logrus.Debug("Successfully converted resource")

return instanceObj, nil
}

func (r *TerraformStateReader) decode(values map[string][]cty.Value) ([]resource.Resource, error) {
results := make([]resource.Resource, 0)
for _, deserializer := range r.deserializers {
Expand Down
4 changes: 2 additions & 2 deletions pkg/iac/terraform/state/terraform_state_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import (
"strings"
"testing"

"github.com/cloudskiff/driftctl/test/goldenfile"

"github.com/cloudskiff/driftctl/pkg/iac"
"github.com/cloudskiff/driftctl/pkg/iac/terraform/state/backend"
"github.com/cloudskiff/driftctl/pkg/remote/aws"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test/goldenfile"
"github.com/cloudskiff/driftctl/test/mocks"

"github.com/r3labs/diff/v2"
Expand Down Expand Up @@ -50,6 +49,7 @@ func TestTerraformStateReader_Resources(t *testing.T) {
{name: "RDS DB instance", dirName: "db_instance", wantErr: false},
{name: "RDS DB Subnet group", dirName: "db_subnet_group", wantErr: false},
{name: "Lambda function", dirName: "lambda_function", wantErr: false},
{name: "unsupported attribute", dirName: "unsupported_attribute", wantErr: false},
{name: "Unsupported provider", dirName: "unsupported_provider", wantErr: false},
{name: "EC2 instance", dirName: "ec2_instance", wantErr: false},
{name: "EC2 key pair", dirName: "ec2_key_pair", wantErr: false},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
[
{
"Ami": "ami-0f8e5edde3a79f541",
"Arn": "arn:aws:ec2:eu-west-3:929327065333:instance/i-002c7d44410fee60e",
"AssociatePublicIpAddress": true,
"AvailabilityZone": "eu-west-3a",
"CpuCoreCount": 1,
"CpuThreadsPerCore": 2,
"DisableApiTermination": false,
"EbsOptimized": false,
"GetPasswordData": false,
"Hibernation": false,
"HostId": null,
"IamInstanceProfile": "",
"Id": "i-002c7d44410fee60e",
"InstanceInitiatedShutdownBehavior": null,
"InstanceState": "running",
"InstanceType": "t3.micro",
"Ipv6AddressCount": 0,
"Ipv6Addresses": [],
"KeyName": "",
"Monitoring": false,
"OutpostArn": "",
"PasswordData": "",
"PlacementGroup": "",
"PrimaryNetworkInterfaceId": "eni-004ddff1c7a130f8b",
"PrivateDns": "ip-172-31-11-192.eu-west-3.compute.internal",
"PrivateIp": "172.31.11.192",
"PublicDns": "ec2-15-188-23-233.eu-west-3.compute.amazonaws.com",
"PublicIp": "15.188.23.233",
"SecondaryPrivateIps": [],
"SecurityGroups": [
"default"
],
"SourceDestCheck": true,
"SubnetId": "subnet-63c5f90a",
"Tags": {
"Name": "HelloWorld"
},
"Tenancy": "default",
"UserData": null,
"UserDataBase64": null,
"VolumeTags": {},
"VpcSecurityGroupIds": [
"sg-a74815c8"
],
"CreditSpecification": [
{
"CpuCredits": "unlimited"
}
],
"EbsBlockDevice": null,
"EphemeralBlockDevice": [],
"MetadataOptions": [
{
"HttpEndpoint": "enabled",
"HttpPutResponseHopLimit": 1,
"HttpTokens": "optional"
}
],
"NetworkInterface": [],
"RootBlockDevice": [
{
"DeleteOnTermination": true,
"DeviceName": "/dev/sda1",
"Encrypted": false,
"Iops": 100,
"KmsKeyId": "",
"VolumeId": "vol-08b1deab4881e2b00",
"VolumeSize": 8,
"VolumeType": "gp2"
}
],
"Timeouts": null
}
]
Loading

0 comments on commit e131550

Please sign in to comment.