Skip to content

Commit

Permalink
Add resource source for terraform state
Browse files Browse the repository at this point in the history
  • Loading branch information
Elie committed Jul 30, 2021
1 parent 360f727 commit 82b8c1c
Show file tree
Hide file tree
Showing 7 changed files with 172,003 additions and 17 deletions.
16 changes: 16 additions & 0 deletions pkg/iac/config/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
package config

import "fmt"

type SupplierConfig struct {
Key string
Backend string
Path string
}

func (c *SupplierConfig) String() string {
str := c.Key
if c.Backend != "" {
str += fmt.Sprintf("+%s", c.Backend)
}
if str != "" {
str += "://"
}
if c.Path != "" {
str += c.Path
}
return str
}
42 changes: 42 additions & 0 deletions pkg/iac/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package config

import "testing"

func TestSupplierConfig_String(t *testing.T) {
tests := []struct {
name string
config SupplierConfig
want string
}{
{
name: "test with empty config",
config: SupplierConfig{},
want: "",
},
{
name: "test with empty path",
config: SupplierConfig{
Key: "tfstate",
Backend: "s3",
Path: "",
},
want: "tfstate+s3://",
},
{
name: "test valid config",
config: SupplierConfig{
Key: "tfstate",
Backend: "s3",
Path: "my-bucket/terraform.tfstate",
},
want: "tfstate+s3://my-bucket/terraform.tfstate",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.config.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}
41 changes: 28 additions & 13 deletions pkg/iac/terraform/state/terraform_state_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import (

const TerraformStateReaderSupplier = "tfstate"

type decodedRes struct {
source resource.Source
val cty.Value
}

type TerraformStateReader struct {
library *terraform.ProviderLibrary
config config.SupplierConfig
Expand All @@ -50,7 +55,7 @@ func NewReader(config config.SupplierConfig, library *terraform.ProviderLibrary,
return &reader, nil
}

func (r *TerraformStateReader) retrieve() (map[string][]cty.Value, error) {
func (r *TerraformStateReader) retrieve() (map[string][]decodedRes, error) {
b, err := backend.GetBackend(r.config, r.backendOptions)
if err != nil {
return nil, err
Expand All @@ -63,7 +68,7 @@ func (r *TerraformStateReader) retrieve() (map[string][]cty.Value, error) {
return nil, err
}

resMap := make(map[string][]cty.Value)
resMap := make(map[string][]decodedRes)
for moduleName, module := range state.Modules {
logrus.WithFields(logrus.Fields{
"module": moduleName,
Expand Down Expand Up @@ -133,12 +138,14 @@ func (r *TerraformStateReader) retrieve() (map[string][]cty.Value, error) {
}
}
_, exists := resMap[stateRes.Addr.Resource.Type]
val := decodedRes{
source: resource.NewTerraformStateSource(r.config.String(), moduleName, resName),
val: decodedVal.Value,
}
if !exists {
resMap[stateRes.Addr.Resource.Type] = []cty.Value{
decodedVal.Value,
}
resMap[stateRes.Addr.Resource.Type] = []decodedRes{val}
} else {
resMap[stateRes.Addr.Resource.Type] = append(resMap[stateRes.Addr.Resource.Type], decodedVal.Value)
resMap[stateRes.Addr.Resource.Type] = append(resMap[stateRes.Addr.Resource.Type], val)
}
}
}
Expand Down Expand Up @@ -175,16 +182,24 @@ func (r *TerraformStateReader) convertInstance(instance *states.ResourceInstance
return instanceObj, nil
}

func (r *TerraformStateReader) decode(values map[string][]cty.Value) ([]resource.Resource, error) {
func (r *TerraformStateReader) decode(valFromState map[string][]decodedRes) ([]resource.Resource, error) {
results := make([]resource.Resource, 0)

for ty, val := range values {
decodedResources, err := r.deserializer.Deserialize(ty, val)
if err != nil {
logrus.WithField("ty", ty).Warnf("Could not read from state: %+v", err)
continue
for ty, val := range valFromState {
for _, stateVal := range val {
res, err := r.deserializer.DeserializeOne(ty, stateVal.val)
if err != nil {
logrus.WithFields(logrus.Fields{
"type": ty,
"name": stateVal.source.InternalName(),
"state": stateVal.source.Source(),
}).Warnf("Could not read from state: %+v", err)
continue
}
stateResource, _ := res.(*resource.AbstractResource)
stateResource.Source = stateVal.source
results = append(results, stateResource)
}
results = append(results, decodedResources...)
}

return results, nil
Expand Down
46 changes: 46 additions & 0 deletions pkg/iac/terraform/state/terraform_state_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,52 @@ func TestReadStateInvalid(t *testing.T) {
}
}

// Check that resource sources are properly set
func TestTerraformStateReader_Source(t *testing.T) {
progress := &output.MockProgress{}
progress.On("Inc").Return().Times(1)
progress.On("Stop").Return().Times(1)

provider := mocks.NewMockedGoldenTFProvider("source", nil, false)
library := terraform.NewProviderLibrary()
library.AddProvider(terraform.AWS, provider)

repo := testresource.InitFakeSchemaRepository(terraform.AWS, "3.19.0")
resourceaws.InitResourcesMetadata(repo)

factory := terraform.NewTerraformResourceFactory(repo)

r := &TerraformStateReader{
config: config.SupplierConfig{
Key: "tfstate",
Path: path.Join(goldenfile.GoldenFilePath, "source", "terraform.tfstate"),
},
library: library,
progress: progress,
deserializer: resource.NewDeserializer(factory),
}

got, err := r.Resources()
assert.Nil(t, err)
assert.Len(t, got, 2)
for _, res := range got {
if res.TerraformType() == resourceaws.AwsS3BucketResourceType {
assert.Equal(t, &resource.TerraformStateSource{
State: "tfstate://test/source/terraform.tfstate",
Module: "",
Name: "bucket",
}, res.(*resource.AbstractResource).Source)
}
if res.TerraformType() == resourceaws.AwsIamUserResourceType {
assert.Equal(t, &resource.TerraformStateSource{
State: "tfstate://test/source/terraform.tfstate",
Module: "module.iam_iam-user",
Name: "this_no_pgp",
}, res.(*resource.AbstractResource).Source)
}
}
}

func TestTerraformStateReader_AWS_Resources(t *testing.T) {
tests := []struct {
name string
Expand Down

0 comments on commit 82b8c1c

Please sign in to comment.