Skip to content

Commit

Permalink
[breaking] make aws provider optional (#247)
Browse files Browse the repository at this point in the history
[breaking] make aws provider optional### Summary
This change makes it optional to specify an aws provider. Only planning on supporting this for config
v2 but it might accidentally work in v1.

The only breaking change is that we now require an aws account id for the global component, where before we would silently ignore the fact that it was missing. I consider this a bug / oversight so fixing it here.

### Test Plan

This diff adds a number of tests, especially golden file tests. None of the existing golden files had to be changed.

### References

*
  • Loading branch information
ryanking authored and czimergebot committed May 16, 2019
1 parent 1c1ce9b commit 876ec2a
Show file tree
Hide file tree
Showing 164 changed files with 3,985 additions and 289 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ help: ## display help for this makefile
clean: ## clean the repo
rm fogg 2>/dev/null || true
go clean
rm -rf dist
rm -rf dist 2>/dev/null || true
packr clean
rm coverage.out
rm coverage.out 2>/dev/null || true

dep: ## ensure dependencies are vendored
dep ensure # this should be super-fast in the no-op case
.PHONY: dep

update-golden-files: dep ## update the golden files in testdata
update-golden-files: clean dep ## update the golden files in testdata
go test -v -run TestIntegration ./apply/ -update
.PHONY: update-golden-files

Expand Down
14 changes: 8 additions & 6 deletions apply/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func init() {
Expand Down Expand Up @@ -218,9 +219,9 @@ func TestCreateFileNonExistentDirectory(t *testing.T) {
}

func TestApplySmokeTest(t *testing.T) {
a := assert.New(t)
r := require.New(t)
fs, _, err := util.TestFs()
a.NoError(err)
r.NoError(err)
// defer os.RemoveAll(d)

json := `
Expand All @@ -231,6 +232,7 @@ func TestApplySmokeTest(t *testing.T) {
"aws_profile_provider": "prof",
"aws_profile_backend": "prof",
"aws_provider_version": "0.12.0",
"account_id": 789,
"infra_s3_bucket": "buck",
"project": "proj",
"terraform_version": "0.100.0",
Expand Down Expand Up @@ -265,15 +267,15 @@ func TestApplySmokeTest(t *testing.T) {
}
`
c, e := v1.ReadConfig([]byte(json))
a.NoError(e)
r.NoError(e)
c2, e := config.UpgradeConfigVersion(c)
a.NoError(e)
r.NoError(e)

e = c2.Validate()
a.NoError(e)
r.NoError(e)

e = Apply(fs, c2, templates.Templates, false)
a.NoError(e)
r.NoError(e)
}

func TestApplyModuleInvocation(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions apply/golden_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ func TestIntegration(t *testing.T) {
fileName string
}{
{"v1_full"},
{"v2_full"},
{"v2_minimal_valid"},
{"v2_no_aws_provider"},
}

for _, tc := range testCases {
Expand Down
23 changes: 13 additions & 10 deletions config/v2/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ type Providers struct {

type AWSProvider struct {
// the aws provider is optional (above) but if supplied you must set account id and region
AccountID *int64 `json:"account_id" validate:"required"`
AdditionalRegions []string `json:"additional_regions"`
Profile *string `json:"profile"`
Region *string `json:"region" validate:"required"`
Version *string `json:"version,omitempty" validate:"required"`
AccountID *int64 `json:"account_id,omitempty"`
AdditionalRegions []string `json:"additional_regions,omitempty"`
Profile *string `json:"profile,omitempty"`
Region *string `json:"region,omitempty"`
Version *string `json:"version,omitempty"`
}

type Backend struct {
Expand Down Expand Up @@ -135,12 +135,15 @@ func (c *Config) Generate(r *rand.Rand, size int) reflect.Value {
}

randAWSProvider := func(r *rand.Rand, s int) *AWSProvider {
return &AWSProvider{
AccountID: randInt64Ptr(r, size),
Region: randStringPtr(r, s),
Profile: randStringPtr(r, s),
Version: randStringPtr(r, s),
if r.Float32() < 0.5 {
return &AWSProvider{
AccountID: randInt64Ptr(r, size),
Region: randStringPtr(r, s),
Profile: randStringPtr(r, s),
Version: randStringPtr(r, s),
}
}
return nil
}

randCommon := func(r *rand.Rand, s int) Common {
Expand Down
188 changes: 188 additions & 0 deletions config/v2/resolvers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package v2

import (
"github.com/chanzuckerberg/fogg/config/v1"
)

// lastNonNil, despite its name can return nil if all results are nil
func lastNonNil(getter func(Common) *string, commons ...Common) *string {
var s *string
for _, c := range commons {
t := getter(c)
if t != nil {
s = t
}
}
return s
}

// lastNonNilInt, despite its name can return nil if all results are nil
func lastNonNilInt64(getter func(Common) *int64, commons ...Common) *int64 {
var s *int64
for _, c := range commons {
t := getter(c)
if t != nil {
s = t
}
}
return s
}

// lastNonNilStringSlice, despite its name can return nil if all results are nil
func lastNonNilStringSlice(getter func(Common) []string, commons ...Common) []string {
var s []string
for _, c := range commons {
t := getter(c)
if t != nil {
s = t
}
}
return s
}

// ResolveRequiredString will resolve the value and panic if it is nil. Only to be used after validations are run.
func ResolveRequiredString(getter func(Common) *string, commons ...Common) string {
return *lastNonNil(getter, commons...)
}

// ResolveRequiredInt will resolve the value and panic if it is nil. Only to be used after validations are run.
func ResolveRequiredInt64(getter func(Common) *int64, commons ...Common) int64 {
return *lastNonNilInt64(getter, commons...)
}

func ResolveOptionalString(getter func(Common) *string, commons ...Common) *string {
return lastNonNil(getter, commons...)
}

func ResolveOptionalStringSlice(getter func(Common) []string, commons ...Common) []string {
return lastNonNilStringSlice(getter, commons...)
}

func ResolveStringArray(def []string, override []string) []string {
if override != nil {
return override
}
return def
}

func ResolveStringMap(getter func(Common) map[string]string, commons ...Common) map[string]string {
resolved := map[string]string{}

for _, c := range commons {
m := getter(c)
for k, v := range m {
resolved[k] = v
}
}
return resolved
}

// ResolveAWSProvider will return an AWSProvder iff one of the required fields is set somewhere in the set of Common
// config objects passed in. Otherwise it will return nil.
func ResolveAWSProvider(commons ...Common) *AWSProvider {

profile := lastNonNil(AWSProviderProfileGetter, commons...)
region := lastNonNil(AWSProviderRegionGetter, commons...)
version := lastNonNil(AWSProviderVersionGetter, commons...)

if profile != nil || region != nil || version != nil {
return &AWSProvider{
Profile: profile,
Region: region,
Version: version,

// optional fields
AccountID: lastNonNilInt64(AWSProviderAccountIdGetter, commons...),
AdditionalRegions: ResolveOptionalStringSlice(AWSProviderAdditionalRegionsGetter, commons...),
}
}
return nil
}

func OwnerGetter(comm Common) *string {
return comm.Owner
}

func ProjectGetter(comm Common) *string {
return comm.Project
}

func TerraformVersionGetter(comm Common) *string {
return comm.TerraformVersion
}

func BackendBucketGetter(comm Common) *string {
if comm.Backend != nil {
return comm.Backend.Bucket
}
return nil
}
func BackendRegionGetter(comm Common) *string {
if comm.Backend != nil {
return comm.Backend.Region
}
return nil
}

func BackendDynamoTableGetter(comm Common) *string {
if comm.Backend != nil {
return comm.Backend.DynamoTable
}
return nil
}

func BackendProfileGetter(comm Common) *string {
if comm.Backend != nil {
return comm.Backend.Profile
}
return nil
}

func AWSProviderRegionGetter(comm Common) *string {
if comm.Providers != nil && comm.Providers.AWS != nil {
return comm.Providers.AWS.Region
}
return nil
}

func AWSProviderVersionGetter(comm Common) *string {
if comm.Providers != nil && comm.Providers.AWS != nil {
return comm.Providers.AWS.Version
}
return nil
}

func AWSProviderProfileGetter(comm Common) *string {
if comm.Providers != nil && comm.Providers.AWS != nil {
return comm.Providers.AWS.Profile
}
return nil
}

func AWSProviderAccountIdGetter(comm Common) *int64 {
if comm.Providers != nil && comm.Providers.AWS != nil {
return comm.Providers.AWS.AccountID
}
return nil
}

func AWSProviderAdditionalRegionsGetter(comm Common) []string {
if comm.Providers != nil && comm.Providers.AWS != nil {
return comm.Providers.AWS.AdditionalRegions
}
return nil
}

func ExtraVarsGetter(comm Common) map[string]string {
if comm.ExtraVars != nil {
return comm.ExtraVars
}
return map[string]string{}
}

func ResolveModuleTerraformVersion(def Defaults, module v1.Module) *string {
if module.TerraformVersion != nil {
return module.TerraformVersion
}
return def.TerraformVersion
}
Loading

0 comments on commit 876ec2a

Please sign in to comment.