Skip to content

Commit

Permalink
feat: no longer require root global backend (#682)
Browse files Browse the repository at this point in the history
* feat: no longer require root global backend

* add back component backends
  • Loading branch information
jakeyheath authored Jul 15, 2022
1 parent 161a7c5 commit ba46914
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 58 deletions.
43 changes: 16 additions & 27 deletions config/v2/resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,66 +180,55 @@ func ResolveAWSProvider(commons ...Common) *AWSProvider {

// ResolveBackend returns the Backend configuration for a given component, after applying all inheritance rules
func ResolveBackend(commons ...Common) *Backend {
var kind, accountID, bucket, dynamoTable, profile, region, hostName, organization, role *string

kind = util.StrPtr("s3")

var ret *Backend
for _, c := range commons {
if c.Backend != nil {
if ret == nil {
ret = &Backend{Kind: util.StrPtr("s3")}
}
b := c.Backend
if b.Kind != nil {
kind = b.Kind
ret.Kind = b.Kind
}

if b.AccountID != nil {
accountID = b.AccountID
ret.AccountID = b.AccountID
}

if b.Bucket != nil {
bucket = b.Bucket
ret.Bucket = b.Bucket
}

if b.DynamoTable != nil {
dynamoTable = b.DynamoTable
ret.DynamoTable = b.DynamoTable
}

if b.Region != nil {
region = b.Region
ret.Region = b.Region
}

// Profile and Role are mutually exclusive, so if one is set then we set the other to
// nil Our validations in validateBackend will assure that they are not both set or missing in the
// same stuct.
if b.Profile != nil {
profile = b.Profile
role = nil
ret.Profile = b.Profile
ret.Role = nil
} else if b.Role != nil {
role = b.Role
profile = nil
ret.Role = b.Role
ret.Profile = nil
}

if b.HostName != nil {
hostName = b.HostName
ret.HostName = b.HostName
}

if b.Organization != nil {
organization = b.Organization
ret.Organization = b.Organization
}
}
}

return &Backend{
Kind: kind,

AccountID: accountID,
Bucket: bucket,
DynamoTable: dynamoTable,
Profile: profile,
Region: region,
HostName: hostName,
Organization: organization,
Role: role,
}
return ret
}

// ResolveGithubProvider will return an GithubProvder iff one of the required fields is set somewhere in the set of Common
Expand Down
7 changes: 7 additions & 0 deletions config/v2/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ func (c *Config) ValidateBackends() error {
var errs *multierror.Error

c.WalkComponents(func(component string, comms ...Common) {
// NOTE[JH]: don't require the global/default have a backend
// Some repos manage several TFE organizations and requiring
// a global backend will inject remote states for which they cannot
// authenticate to.
if component == "global" {
return
}
backendConfig := ResolveBackend(comms...)

if e := ValidateBackend(backendConfig, component); e != nil {
Expand Down
56 changes: 28 additions & 28 deletions plan/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,6 @@ func (p *Plan) buildGlobal(conf *v2.Config) Component {
componentPlan.ComponentCommon.Backend.S3.KeyPath = fmt.Sprintf("terraform/%s/global.tfstate", componentPlan.ComponentCommon.Project)
} else if componentPlan.ComponentCommon.Backend.Kind == BackendKindRemote {
componentPlan.ComponentCommon.Backend.Remote.Workspace = "global"
} else {
panic(fmt.Sprintf("Invalid backend kind of %s", componentPlan.ComponentCommon.Backend.Kind))
}

componentPlan.Name = "global"
Expand Down Expand Up @@ -862,32 +860,34 @@ func resolveComponentCommon(commons ...v2.Common) ComponentCommon {
backendConf := v2.ResolveBackend(commons...)
var backend Backend

if *backendConf.Kind == "s3" {
var roleArn *string
if backendConf.Role != nil {
// we know from our validations that if role is set, then account id must also be set
tmp := fmt.Sprintf("arn:aws:iam::%s:role/%s", *backendConf.AccountID, *backendConf.Role)
roleArn = &tmp
}
backend = Backend{
Kind: BackendKindS3,
S3: &S3Backend{
Region: *backendConf.Region,
Profile: backendConf.Profile,
Bucket: *backendConf.Bucket,
RoleArn: roleArn,

AccountID: backendConf.AccountID,
DynamoTable: backendConf.DynamoTable,
},
}
} else if *backendConf.Kind == "remote" {
backend = Backend{
Kind: BackendKindRemote,
Remote: &RemoteBackend{
HostName: *backendConf.HostName,
Organization: *backendConf.Organization,
},
if backendConf != nil {
if *backendConf.Kind == "s3" {
var roleArn *string
if backendConf.Role != nil {
// we know from our validations that if role is set, then account id must also be set
tmp := fmt.Sprintf("arn:aws:iam::%s:role/%s", *backendConf.AccountID, *backendConf.Role)
roleArn = &tmp
}
backend = Backend{
Kind: BackendKindS3,
S3: &S3Backend{
Region: *backendConf.Region,
Profile: backendConf.Profile,
Bucket: *backendConf.Bucket,
RoleArn: roleArn,

AccountID: backendConf.AccountID,
DynamoTable: backendConf.DynamoTable,
},
}
} else if *backendConf.Kind == "remote" {
backend = Backend{
Kind: BackendKindRemote,
Remote: &RemoteBackend{
HostName: *backendConf.HostName,
Organization: *backendConf.Organization,
},
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions templates/templates/component/terraform/fogg.tf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,15 @@ variable "{{ $key }}" {
}
{{ end }}

{{ if .Global }}
{{ if .Global}}
{{ if .Global.Backend.Kind}}
data "terraform_remote_state" "global" {
backend = "{{ .Global.Backend.Kind }}"

config = {
{{ template "remote_backend" .Global.Backend }}
}
}
{{ end }}
}{{ end }}{{end}}

{{ $outer := . }}
{{ range $component, $backend := .ComponentBackends }}
Expand Down

0 comments on commit ba46914

Please sign in to comment.