Skip to content

Commit

Permalink
Merge pull request #393 from wata727/eval_provider_block
Browse files Browse the repository at this point in the history
Eval provider attributes
  • Loading branch information
wata727 committed Aug 21, 2019
2 parents fa42936 + 4c69a43 commit a80dc75
Show file tree
Hide file tree
Showing 10 changed files with 411 additions and 183 deletions.
132 changes: 81 additions & 51 deletions client/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ import (
"github.com/aws/aws-sdk-go/service/rds"
"github.com/aws/aws-sdk-go/service/rds/rdsiface"
awsbase "github.com/hashicorp/aws-sdk-go-base"
"github.com/hashicorp/hcl2/gohcl"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/terraform/configs"
homedir "github.com/mitchellh/go-homedir"
)

Expand Down Expand Up @@ -55,21 +53,26 @@ type AwsCredentials struct {
Region string
}

type awsProvider struct {
AccessKey string `hcl:"access_key,optional"`
SecretKey string `hcl:"secret_key,optional"`
Profile string `hcl:"profile,optional"`
CredsFilename string `hcl:"shared_credentials_file,optional"`
Region string `hcl:"region,optional"`
// AwsProviderBlockSchema is a schema of `aws` provider block
var AwsProviderBlockSchema = &hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{Name: "access_key"},
{Name: "secret_key"},
{Name: "profile"},
{Name: "shared_credentials_file"},
{Name: "region"},
},
}

Remain hcl.Body `hcl:",remain"`
type providerResource interface {
Get(key string) (string, bool, error)
}

// NewAwsClient returns new AwsClient with configured session
func NewAwsClient(provider *configs.Provider, creds AwsCredentials) (*AwsClient, error) {
func NewAwsClient(creds AwsCredentials) (*AwsClient, error) {
log.Print("[INFO] Initialize AWS Client")

config, err := getBaseConfig(provider, creds)
config, err := getBaseConfig(creds)
if err != nil {
return nil, err
}
Expand All @@ -90,59 +93,86 @@ func NewAwsClient(provider *configs.Provider, creds AwsCredentials) (*AwsClient,
}, nil
}

func getBaseConfig(provider *configs.Provider, creds AwsCredentials) (*awsbase.Config, error) {
base := &awsbase.Config{}

if provider != nil {
pc, err := decodeProviderConfig(provider)
if err != nil {
return base, err
}
// ConvertToCredentials converts to credentials from the given provider config
func ConvertToCredentials(providerConfig providerResource) (AwsCredentials, error) {
ret := AwsCredentials{}

base = &awsbase.Config{
AccessKey: pc.AccessKey,
Profile: pc.Profile,
Region: pc.Region,
SecretKey: pc.SecretKey,
}
accessKey, exists, err := providerConfig.Get("access_key")
if err != nil {
return ret, err
}
if exists {
ret.AccessKey = accessKey
}

path, err := homedir.Expand(pc.CredsFilename)
if err != nil {
return base, err
}
base.CredsFilename = path
secretKey, exists, err := providerConfig.Get("secret_key")
if err != nil {
return ret, err
}
if exists {
ret.SecretKey = secretKey
}

if creds.AccessKey != "" {
base.AccessKey = creds.AccessKey
profile, exists, err := providerConfig.Get("profile")
if err != nil {
return ret, err
}
if exists {
ret.Profile = profile
}
if creds.CredsFile != "" {
path, err := homedir.Expand(creds.CredsFile)
if err != nil {
return base, err
}
base.CredsFilename = path

credsFile, exists, err := providerConfig.Get("shared_credentials_file")
if err != nil {
return ret, err
}
if creds.Profile != "" {
base.Profile = creds.Profile
if exists {
ret.CredsFile = credsFile
}
if creds.Region != "" {
base.Region = creds.Region

region, exists, err := providerConfig.Get("region")
if err != nil {
return ret, err
}
if creds.SecretKey != "" {
base.SecretKey = creds.SecretKey
if exists {
ret.Region = region
}

return base, nil
return ret, nil
}

// Merge returns a merged credentials
func (c AwsCredentials) Merge(other AwsCredentials) AwsCredentials {
if other.AccessKey != "" {
c.AccessKey = other.AccessKey
}
if other.SecretKey != "" {
c.SecretKey = other.SecretKey
}
if other.Profile != "" {
c.Profile = other.Profile
}
if other.CredsFile != "" {
c.CredsFile = other.CredsFile
}
if other.Region != "" {
c.Region = other.Region
}
return c
}

func decodeProviderConfig(provider *configs.Provider) (awsProvider, error) {
var config awsProvider
diags := gohcl.DecodeBody(provider.Config, nil, &config)
if diags.HasErrors() {
return config, diags
func getBaseConfig(creds AwsCredentials) (*awsbase.Config, error) {
expandedCredsFile, err := homedir.Expand(creds.CredsFile)
if err != nil {
return nil, err
}
return config, nil

return &awsbase.Config{
AccessKey: creds.AccessKey,
SecretKey: creds.SecretKey,
Profile: creds.Profile,
CredsFilename: expandedCredsFile,
Region: creds.Region,
}, nil
}

// @see https://github.com/hashicorp/aws-sdk-go-base/blob/v0.3.0/session.go#L87
Expand Down
164 changes: 78 additions & 86 deletions client/aws_test.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,92 @@
package client

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

"github.com/google/go-cmp/cmp"
awsbase "github.com/hashicorp/aws-sdk-go-base"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/hcl2/hclparse"
"github.com/hashicorp/terraform/configs"
homedir "github.com/mitchellh/go-homedir"
)

func Test_getBaseConfig(t *testing.T) {
currentDir, err := os.Getwd()
if err != nil {
t.Fatal(err)
func Test_Merge(t *testing.T) {
cases := []struct {
Name string
Self AwsCredentials
Other AwsCredentials
Expected AwsCredentials
}{
{
Name: "self is empty",
Self: AwsCredentials{},
Other: AwsCredentials{
AccessKey: "AWS_ACCESS_KEY",
SecretKey: "AWS_SECRET_KEY",
Profile: "default",
CredsFile: "~/.aws/creds",
Region: "us-east-1",
},
Expected: AwsCredentials{
AccessKey: "AWS_ACCESS_KEY",
SecretKey: "AWS_SECRET_KEY",
Profile: "default",
CredsFile: "~/.aws/creds",
Region: "us-east-1",
},
},
{
Name: "other is empty",
Self: AwsCredentials{
AccessKey: "AWS_ACCESS_KEY_2",
SecretKey: "AWS_SECRET_KEY_2",
Profile: "staging",
CredsFile: "~/.aws/creds_stg",
Region: "ap-northeast-1",
},
Other: AwsCredentials{},
Expected: AwsCredentials{
AccessKey: "AWS_ACCESS_KEY_2",
SecretKey: "AWS_SECRET_KEY_2",
Profile: "staging",
CredsFile: "~/.aws/creds_stg",
Region: "ap-northeast-1",
},
},
{
Name: "merged",
Self: AwsCredentials{
AccessKey: "AWS_ACCESS_KEY_2",
SecretKey: "AWS_SECRET_KEY_2",
Profile: "staging",
CredsFile: "~/.aws/creds_stg",
Region: "ap-northeast-1",
},
Other: AwsCredentials{
AccessKey: "AWS_ACCESS_KEY",
SecretKey: "AWS_SECRET_KEY",
Profile: "default",
CredsFile: "~/.aws/creds",
Region: "us-east-1",
},
Expected: AwsCredentials{
AccessKey: "AWS_ACCESS_KEY",
SecretKey: "AWS_SECRET_KEY",
Profile: "default",
CredsFile: "~/.aws/creds",
Region: "us-east-1",
},
},
}

for _, tc := range cases {
ret := tc.Self.Merge(tc.Other)
if !cmp.Equal(tc.Expected, ret) {
t.Fatalf("Failed `%s` test: Diff=%s", tc.Name, cmp.Diff(tc.Expected, ret))
}
}
}

func Test_getBaseConfig(t *testing.T) {
home, err := homedir.Expand("~/")
if err != nil {
t.Fatal(err)
Expand All @@ -26,7 +95,6 @@ func Test_getBaseConfig(t *testing.T) {
cases := []struct {
Name string
Creds AwsCredentials
File string
Expected *awsbase.Config
}{
{
Expand Down Expand Up @@ -55,86 +123,10 @@ func Test_getBaseConfig(t *testing.T) {
Region: "us-east-1",
},
},
{
Name: "static credentials provider",
File: "static-creds.tf",
Expected: &awsbase.Config{
AccessKey: "AWS_ACCESS_KEY",
SecretKey: "AWS_SECRET_KEY",
Region: "us-east-1",
},
},
{
Name: "shared credentials provider",
File: "shared-creds.tf",
Expected: &awsbase.Config{
Profile: "default",
CredsFilename: filepath.Join(home, ".aws", "creds"),
Region: "us-east-1",
},
},
{
Name: "assume role provider",
File: "assume-role.tf",
Expected: &awsbase.Config{},
},
{
Name: "prefer tflint static credentials over provider",
File: "static-creds.tf",
Creds: AwsCredentials{
AccessKey: "TFLINT_AWS_ACCESS_KEY",
SecretKey: "TFLINT_AWS_SECRET_KEY",
Region: "us-east-2",
},
Expected: &awsbase.Config{
AccessKey: "TFLINT_AWS_ACCESS_KEY",
SecretKey: "TFLINT_AWS_SECRET_KEY",
Region: "us-east-2",
},
},
{
Name: "prefer tflint shared credentials over provider",
File: "shared-creds.tf",
Creds: AwsCredentials{
Profile: "terraform",
CredsFile: "~/.aws/tf_credentials",
Region: "us-east-2",
},
Expected: &awsbase.Config{
Profile: "terraform",
CredsFilename: filepath.Join(home, ".aws", "tf_credentials"),
Region: "us-east-2",
},
},
}

for _, tc := range cases {
var pc *configs.Provider
if tc.File != "" {
parser := hclparse.NewParser()
f, diags := parser.ParseHCLFile(filepath.Join(currentDir, "test-fixtures", tc.File))
if diags.HasErrors() {
t.Fatal(diags)
}

body, _, diags := f.Body.PartialContent(&hcl.BodySchema{
Blocks: []hcl.BlockHeaderSchema{
{
Type: "provider",
LabelNames: []string{"name"},
},
},
})
if diags.HasErrors() {
t.Fatal(diags)
}

pc = &configs.Provider{
Config: body.Blocks[0].Body,
}
}

base, err := getBaseConfig(pc, tc.Creds)
base, err := getBaseConfig(tc.Creds)
if err != nil {
t.Fatalf("Failed `%s` test: Unexpected error occurred: %s", tc.Name, err)
}
Expand Down
7 changes: 0 additions & 7 deletions client/test-fixtures/assume-role.tf

This file was deleted.

5 changes: 0 additions & 5 deletions client/test-fixtures/shared-creds.tf

This file was deleted.

5 changes: 0 additions & 5 deletions client/test-fixtures/static-creds.tf

This file was deleted.

Loading

0 comments on commit a80dc75

Please sign in to comment.