Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide ability to disable backend init so that validate-all can be run without a backend #761

Merged
merged 4 commits into from Jul 1, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -54,8 +54,9 @@ type terragruntInclude struct {

// Configuration for Terraform remote state as parsed from a terragrunt.hcl config file
type remoteStateConfigFile struct {
Backend string `hcl:"backend,attr"`
Config cty.Value `hcl:"config,attr"`
Backend string `hcl:"backend,attr"`
DisableInit *bool `hcl:"disable_init,attr"`
Config cty.Value `hcl:"config,attr"`
}

func (remoteState *remoteStateConfigFile) String() string {
@@ -523,6 +524,10 @@ func convertToTerragruntConfig(terragruntConfigFromFile *terragruntConfigFile, c
remoteState.Backend = terragruntConfigFromFile.RemoteState.Backend
remoteState.Config = remoteStateConfig

if terragruntConfigFromFile.RemoteState.DisableInit != nil {
remoteState.DisableInit = *terragruntConfigFromFile.RemoteState.DisableInit
}

remoteState.FillDefaults()
if err := remoteState.Validate(); err != nil {
return nil, err
@@ -9,20 +9,21 @@ import (

// Configuration for Terraform remote state
type RemoteState struct {
Backend string
Config map[string]interface{}
Backend string
DisableInit bool
Config map[string]interface{}
}

func (remoteState *RemoteState) String() string {
return fmt.Sprintf("RemoteState{Backend = %v, Config = %v}", remoteState.Backend, remoteState.Config)
return fmt.Sprintf("RemoteState{Backend = %v, DisableInit = %v, Config = %v}", remoteState.Backend, remoteState.DisableInit, remoteState.Config)
}

type RemoteStateInitializer interface {
// Return true if remote state needs to be initialized
NeedsInitialization(config map[string]interface{}, existingBackend *TerraformBackend, terragruntOptions *options.TerragruntOptions) (bool, error)
NeedsInitialization(remoteState *RemoteState, existingBackend *TerraformBackend, terragruntOptions *options.TerragruntOptions) (bool, error)

// Initialize the remote state
Initialize(config map[string]interface{}, terragruntOptions *options.TerragruntOptions) error
Initialize(remoteState *RemoteState, terragruntOptions *options.TerragruntOptions) error

// Return the config that should be passed on to terraform via -backend-config cmd line param
// Allows the Backends to filter and/or modify the configuration given from the user
@@ -54,7 +55,7 @@ func (remoteState *RemoteState) Initialize(terragruntOptions *options.Terragrunt
terragruntOptions.Logger.Printf("Initializing remote state for the %s backend", remoteState.Backend)
initializer, hasInitializer := remoteStateInitializers[remoteState.Backend]
if hasInitializer {
return initializer.Initialize(remoteState.Config, terragruntOptions)
return initializer.Initialize(remoteState, terragruntOptions)
}

return nil
@@ -71,14 +72,18 @@ func (remoteState *RemoteState) NeedsInit(terragruntOptions *options.TerragruntO
return false, err
}

if remoteState.DisableInit {
return false, nil
}

// Remote state not configured
if state == nil {
return true, nil
}

if initializer, hasInitializer := remoteStateInitializers[remoteState.Backend]; hasInitializer {
// Remote state initializer says initialization is necessary
return initializer.NeedsInitialization(remoteState.Config, state.Backend, terragruntOptions)
return initializer.NeedsInitialization(remoteState, state.Backend, terragruntOptions)
} else if state.IsRemote() && remoteState.differsFrom(state.Backend, terragruntOptions) {
// If there's no remote state initializer, then just compare the the config values
return true, nil
@@ -127,8 +132,10 @@ func terraformStateConfigEqual(existingConfig map[string]interface{}, newConfig

// Convert the RemoteState config into the format used by the terraform init command
func (remoteState RemoteState) ToTerraformInitArgs() []string {

config := remoteState.Config
if remoteState.DisableInit {
return []string{"-backend=false"}
}

initializer, hasInitializer := remoteStateInitializers[remoteState.Backend]
if hasInitializer {
@@ -95,12 +95,16 @@ type S3Initializer struct{}
//
// 1. Any of the existing backend settings are different than the current config
// 2. The configured S3 bucket or DynamoDB table does not exist
func (s3Initializer S3Initializer) NeedsInitialization(config map[string]interface{}, existingBackend *TerraformBackend, terragruntOptions *options.TerragruntOptions) (bool, error) {
if !configValuesEqual(config, existingBackend, terragruntOptions) {
func (s3Initializer S3Initializer) NeedsInitialization(remoteState *RemoteState, existingBackend *TerraformBackend, terragruntOptions *options.TerragruntOptions) (bool, error) {
if remoteState.DisableInit {
return false, nil
}

if !configValuesEqual(remoteState.Config, existingBackend, terragruntOptions) {
return true, nil
}

s3Config, err := parseS3Config(config)
s3Config, err := parseS3Config(remoteState.Config)
if err != nil {
return false, err
}
@@ -186,8 +190,8 @@ func configValuesEqual(config map[string]interface{}, existingBackend *Terraform

// Initialize the remote state S3 bucket specified in the given config. This function will validate the config
// parameters, create the S3 bucket if it doesn't already exist, and check that versioning is enabled.
func (s3Initializer S3Initializer) Initialize(config map[string]interface{}, terragruntOptions *options.TerragruntOptions) error {
s3ConfigExtended, err := parseExtendedS3Config(config)
func (s3Initializer S3Initializer) Initialize(remoteState *RemoteState, terragruntOptions *options.TerragruntOptions) error {
s3ConfigExtended, err := parseExtendedS3Config(remoteState.Config)
if err != nil {
return err
}
@@ -61,6 +61,23 @@ func TestToTerraformInitArgsUnknownBackend(t *testing.T) {
assertTerraformInitArgsEqual(t, args, "-backend-config=encrypt=true -backend-config=bucket=my-bucket -backend-config=key=terraform.tfstate -backend-config=region=us-east-1")
}

func TestToTerraformInitArgsInitDisabled(t *testing.T) {
t.Parallel()

remoteState := RemoteState{
Backend: "s3",
DisableInit: true,
Config: map[string]interface{}{
"encrypt": true,
"bucket": "my-bucket",
"key": "terraform.tfstate",
"region": "us-east-1"},
}
args := remoteState.ToTerraformInitArgs()

assertTerraformInitArgsEqual(t, args, "-backend=false")
}

func TestToTerraformInitArgsNoBackendConfigs(t *testing.T) {
t.Parallel()

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.