Skip to content

Commit

Permalink
Fix how to get aws default region (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
obierlaire authored Jun 21, 2023
1 parent 9696a5f commit 1d5b47a
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 15 deletions.
65 changes: 65 additions & 0 deletions internal/terraform/aws/default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package aws

import (
"os"

"github.com/carboniferio/carbonifer/internal/terraform/tfrefs"
"github.com/carboniferio/carbonifer/internal/utils"
tfjson "github.com/hashicorp/terraform-json"
log "github.com/sirupsen/logrus"

"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/session"
)

func GetDefaults(awsConfig *tfjson.ProviderConfig, tfPlan *tfjson.Plan, terraformRefs *tfrefs.References) {
log.Debugf("Reading provider config %v", awsConfig.Name)

region := getDefaultRegion(awsConfig, tfPlan)
if region != nil {
terraformRefs.ProviderConfigs["region"] = region.(string)
}
}

func getDefaultRegion(awsConfig *tfjson.ProviderConfig, tfPlan *tfjson.Plan) interface{} {
var region interface{}
regionExpr := awsConfig.Expressions["region"]
if regionExpr != nil {
var err error
region, err = utils.GetValueOfExpression(regionExpr, tfPlan)
if err != nil {
log.Fatalf("Error getting region from provider config %v", err)
}
}
if region == nil {
if os.Getenv("AWS_DEFAULT_REGION") != "" {
region = os.Getenv("AWS_DEFAULT_REGION")
}
}
if region == nil {
if os.Getenv("AWS_REGION") != "" {
region = os.Getenv("AWS_REGION")
}
}

// Check AWS Config file
if region == nil {
sess, err := session.NewSession()
if err != nil {
log.Fatalf("Error getting region from AWS config file %v", err)
}
if *sess.Config.Region != "" {
region = *sess.Config.Region
}
}

// Check EC2 Instance Metadata
if region == nil {
sess := session.Must(session.NewSession())
svc := ec2metadata.New(sess)
if svc.Available() {
region, _ = svc.Region()
}
}
return region
}
118 changes: 118 additions & 0 deletions internal/terraform/aws/default_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package aws

import (
"io"
"os"
"path/filepath"
"testing"

tfjson "github.com/hashicorp/terraform-json"
"github.com/stretchr/testify/assert"
)

func Test_getDefaultRegion_providerConstant(t *testing.T) {
awsConfigs := &tfjson.ProviderConfig{
Name: "aws",
Expressions: map[string]*tfjson.Expression{
"region": {
ExpressionData: &tfjson.ExpressionData{
ConstantValue: "test1",
},
},
},
}

tfPlan := &tfjson.Plan{}

region := getDefaultRegion(awsConfigs, tfPlan)
assert.Equal(t, "test1", region)

}

func Test_getDefaultRegion_providerVariable(t *testing.T) {
awsConfigs := &tfjson.ProviderConfig{
Name: "aws",
Expressions: map[string]*tfjson.Expression{
"region": {
ExpressionData: &tfjson.ExpressionData{
References: []string{"var.region"},
},
},
},
}

tfPlan := &tfjson.Plan{
Variables: map[string]*tfjson.PlanVariable{
"region": {
Value: "test2",
},
},
}

region := getDefaultRegion(awsConfigs, tfPlan)
assert.Equal(t, "test2", region)

}

func Test_getDefaultRegion_EnvVar(t *testing.T) {
awsConfigs := &tfjson.ProviderConfig{
Name: "aws",
Expressions: map[string]*tfjson.Expression{},
}

tfPlan := &tfjson.Plan{}

t.Setenv("AWS_REGION", "test3")

region := getDefaultRegion(awsConfigs, tfPlan)
assert.Equal(t, "test3", region)

}

func Test_getDefaultRegion_EnvDefaultVar(t *testing.T) {
awsConfigs := &tfjson.ProviderConfig{
Name: "aws",
Expressions: map[string]*tfjson.Expression{},
}

tfPlan := &tfjson.Plan{}

t.Setenv("AWS_DEFAULT_REGION", "test4")

region := getDefaultRegion(awsConfigs, tfPlan)
assert.Equal(t, "test4", region)

}

func Test_getDefaultRegion_AWSConfigFile(t *testing.T) {
// Create a temporary directory
tmpDir := t.TempDir()

// Create AWS config file
awsConfigFile := filepath.Join(tmpDir, "config")
f, err := os.Create(awsConfigFile)
if err != nil {
t.Fatal(err)
}
defer f.Close()

_, err = io.WriteString(f, "[default]\nregion = region_from_config_file\n")
if err != nil {
t.Fatal(err)
}

// Set the AWS_SDK_LOAD_CONFIG environment variable
t.Setenv("AWS_SDK_LOAD_CONFIG", "1")
t.Setenv("AWS_CONFIG_FILE", awsConfigFile)

awsConfigs := &tfjson.ProviderConfig{
Name: "aws",
Expressions: map[string]*tfjson.Expression{},
}

tfPlan := &tfjson.Plan{}

region := getDefaultRegion(awsConfigs, tfPlan)
assert.Equal(t, "region_from_config_file", region)

}
16 changes: 1 addition & 15 deletions internal/terraform/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package terraform

import (
"encoding/json"
"os"
"strings"

"github.com/carboniferio/carbonifer/internal/resources"
Expand Down Expand Up @@ -66,20 +65,7 @@ func GetResources(tfPlan *tfjson.Plan) (map[string]resources.Resource, error) {
// Get default values
for provider, resConfig := range tfPlan.Config.ProviderConfigs {
if provider == "aws" {
log.Debugf("Reading provider config %v", resConfig.Name)
// TODO #58 Improve way we get default regions (env var, profile...)
var region interface{}
regionExpr := resConfig.Expressions["region"]
if regionExpr != nil {
region = regionExpr.ConstantValue
} else {
if os.Getenv("AWS_REGION") != "" {
region = os.Getenv("AWS_REGION")
}
}
if region != nil {
terraformRefs.ProviderConfigs["region"] = region.(string)
}
aws.GetDefaults(resConfig, tfPlan, &terraformRefs)
}
}

Expand Down
28 changes: 28 additions & 0 deletions internal/utils/expressions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package utils

import (
"errors"
"fmt"
"strings"

tfjson "github.com/hashicorp/terraform-json"
)

func GetValueOfExpression(expression *tfjson.Expression, tfPlan *tfjson.Plan) (interface{}, error) {
if fmt.Sprintf("%T", expression.ConstantValue) != "*tfjson.unknownConstantValue" && expression.ConstantValue != nil {
// It's a known value, return it as is
return expression.ConstantValue, nil
}

// Constant value is not set or unknown, look up references
for _, reference := range expression.References {
ref := strings.TrimPrefix(reference, "var.")
if val, ok := tfPlan.Variables[ref]; ok {
return val.Value, nil
}
}

// No variables were found
return nil, errors.New("no value found for expression")

}

0 comments on commit 1d5b47a

Please sign in to comment.