Skip to content

Commit 0095012

Browse files
committed
refactor: Gate pluggable state storage experiment behind the experiment pluggable_state_stores. This is defined via configuration, instead of the old CLI flag -enable-pluggable-state-storage-experiment
This commit removes the old `-enable-pluggable-state-storage-experiment` flag and the equivalent `TF_ENABLE_PLUGGABLE_STATE_STORAGE` ENV. All tests are updated to no longer provide that flag or ENV, and instead all the test fixture configurations are updated to include `experiments = [pluggable_state_stores]`
1 parent 4050e74 commit 0095012

File tree

32 files changed

+73
-107
lines changed

32 files changed

+73
-107
lines changed

internal/command/arguments/init.go

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,6 @@ type Init struct {
7575

7676
Args []string
7777

78-
// The -enable-pluggable-state-storage-experiment flag is used in control flow logic in the init command.
79-
// TODO(SarahFrench/radeksimko): Remove this once the feature is no longer
80-
// experimental
81-
EnablePssExperiment bool
82-
8378
// CreateDefaultWorkspace indicates whether the default workspace should be created by
8479
// Terraform when initializing a state store for the first time.
8580
CreateDefaultWorkspace bool
@@ -118,9 +113,6 @@ func ParseInit(args []string, experimentsEnabled bool) (*Init, tfdiags.Diagnosti
118113
cmdFlags.Var(&init.PluginPath, "plugin-dir", "plugin directory")
119114
cmdFlags.BoolVar(&init.CreateDefaultWorkspace, "create-default-workspace", true, "when -input=false, use this flag to block creation of the default workspace")
120115

121-
// Used for enabling experimental code that's invoked before configuration is parsed.
122-
cmdFlags.BoolVar(&init.EnablePssExperiment, "enable-pluggable-state-storage-experiment", false, "Enable the pluggable state storage experiment")
123-
124116
if err := cmdFlags.Parse(args); err != nil {
125117
diags = diags.Append(tfdiags.Sourceless(
126118
tfdiags.Error,
@@ -129,44 +121,20 @@ func ParseInit(args []string, experimentsEnabled bool) (*Init, tfdiags.Diagnosti
129121
))
130122
}
131123

132-
if v := os.Getenv("TF_ENABLE_PLUGGABLE_STATE_STORAGE"); v != "" {
133-
init.EnablePssExperiment = true
134-
}
135-
136124
if v := os.Getenv("TF_SKIP_CREATE_DEFAULT_WORKSPACE"); v != "" {
137125
// If TF_SKIP_CREATE_DEFAULT_WORKSPACE is set it will override
138126
// a -create-default-workspace=true flag that's set explicitly,
139127
// as that's indistinguishable from the default value being used.
140128
init.CreateDefaultWorkspace = false
141129
}
142130

143-
if !experimentsEnabled {
144-
// If experiments aren't enabled then these flags should not be used.
145-
if init.EnablePssExperiment {
146-
diags = diags.Append(tfdiags.Sourceless(
147-
tfdiags.Error,
148-
"Cannot use -enable-pluggable-state-storage-experiment flag without experiments enabled",
149-
"Terraform cannot use the -enable-pluggable-state-storage-experiment flag (or TF_ENABLE_PLUGGABLE_STATE_STORAGE environment variable) unless experiments are enabled.",
150-
))
151-
}
152-
if !init.CreateDefaultWorkspace {
153-
// Can only be set to false by using the flag
154-
// and we cannot identify if -create-default-workspace=true is set explicitly.
155-
diags = diags.Append(tfdiags.Sourceless(
156-
tfdiags.Error,
157-
"Cannot use -create-default-workspace flag without experiments enabled",
158-
"Terraform cannot use the -create-default-workspace flag (or TF_SKIP_CREATE_DEFAULT_WORKSPACE environment variable) unless experiments are enabled.",
159-
))
160-
}
161-
} else {
162-
// Errors using flags despite experiments being enabled.
163-
if !init.CreateDefaultWorkspace && !init.EnablePssExperiment {
164-
diags = diags.Append(tfdiags.Sourceless(
165-
tfdiags.Error,
166-
"Cannot use -create-default-workspace=false flag unless the pluggable state storage experiment is enabled",
167-
"Terraform cannot use the -create-default-workspace=false flag (or TF_SKIP_CREATE_DEFAULT_WORKSPACE environment variable) unless you also supply the -enable-pluggable-state-storage-experiment flag (or set the TF_ENABLE_PLUGGABLE_STATE_STORAGE environment variable).",
168-
))
169-
}
131+
if !experimentsEnabled && !init.CreateDefaultWorkspace {
132+
// CreateDefaultWorkspace can only be set to false by using the flag
133+
diags = diags.Append(tfdiags.Sourceless(
134+
tfdiags.Error,
135+
"Cannot use -create-default-workspace flag without experiments enabled",
136+
"Terraform cannot use the -create-default-workspace flag (or TF_SKIP_CREATE_DEFAULT_WORKSPACE environment variable) unless experiments are enabled.",
137+
))
170138
}
171139

172140
if init.MigrateState && init.Json {

internal/command/arguments/init_test.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,6 @@ func TestParseInit_experimentalFlags(t *testing.T) {
182182
wantErr string
183183
experimentsEnabled bool
184184
}{
185-
"error: -enable-pluggable-state-storage-experiment and experiments are disabled": {
186-
args: []string{"-enable-pluggable-state-storage-experiment"},
187-
experimentsEnabled: false,
188-
wantErr: "Cannot use -enable-pluggable-state-storage-experiment flag without experiments enabled",
189-
},
190-
"error: TF_ENABLE_PLUGGABLE_STATE_STORAGE is set and experiments are disabled": {
191-
envs: map[string]string{
192-
"TF_ENABLE_PLUGGABLE_STATE_STORAGE": "1",
193-
},
194-
experimentsEnabled: false,
195-
wantErr: "Cannot use -enable-pluggable-state-storage-experiment flag without experiments enabled",
196-
},
197185
"error: -create-default-workspace=false and experiments are disabled": {
198186
args: []string{"-create-default-workspace=false"},
199187
experimentsEnabled: false,
@@ -206,18 +194,6 @@ func TestParseInit_experimentalFlags(t *testing.T) {
206194
experimentsEnabled: false,
207195
wantErr: "Cannot use -create-default-workspace flag without experiments enabled",
208196
},
209-
"error: -create-default-workspace=false used without -enable-pluggable-state-storage-experiment, while experiments are enabled": {
210-
args: []string{"-create-default-workspace=false"},
211-
experimentsEnabled: true,
212-
wantErr: "Cannot use -create-default-workspace=false flag unless the pluggable state storage experiment is enabled",
213-
},
214-
"error: TF_SKIP_CREATE_DEFAULT_WORKSPACE used without -enable-pluggable-state-storage-experiment, while experiments are enabled": {
215-
envs: map[string]string{
216-
"TF_SKIP_CREATE_DEFAULT_WORKSPACE": "1",
217-
},
218-
experimentsEnabled: true,
219-
wantErr: "Cannot use -create-default-workspace=false flag unless the pluggable state storage experiment is enabled",
220-
},
221197
}
222198

223199
for name, tc := range testCases {

internal/command/init.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/hashicorp/terraform/internal/configs"
2727
"github.com/hashicorp/terraform/internal/configs/configschema"
2828
"github.com/hashicorp/terraform/internal/depsfile"
29+
"github.com/hashicorp/terraform/internal/experiments"
2930
"github.com/hashicorp/terraform/internal/getproviders"
3031
"github.com/hashicorp/terraform/internal/getproviders/providerreqs"
3132
"github.com/hashicorp/terraform/internal/providercache"
@@ -55,12 +56,22 @@ func (c *InitCommand) Run(args []string) int {
5556
return 1
5657
}
5758

59+
path, err := ModulePath(initArgs.Args)
60+
if err != nil {
61+
diags = diags.Append(err)
62+
view.Diagnostics(diags)
63+
return 1
64+
}
65+
rootMod, _ := c.loadSingleModuleWithTests(path, initArgs.TestsDirectory)
66+
// We purposefully ignore any diagnostics returned here. They will be encountered downstream,
67+
// when the 'run' logic below is executed. If we return early due to error diagnostics here we
68+
// will break the order that errors are expected to be raised in.
69+
5870
// The else condition below invokes the original logic of the init command.
5971
// An experimental version of the init code will be used if:
60-
// > The user uses an experimental version of TF (alpha or built from source)
61-
// > Either the flag -enable-pluggable-state-storage-experiment is passed to the init command.
62-
// > Or, the environment variable TF_ENABLE_PLUGGABLE_STATE_STORAGE is set to any value.
63-
if c.Meta.AllowExperimentalFeatures && initArgs.EnablePssExperiment {
72+
// > The user uses an experimental version of TF (alpha or built from source).
73+
// > The terraform block in the configuration lists the `pluggable_state_stores` experiment.
74+
if c.Meta.AllowExperimentalFeatures && rootMod.ActiveExperiments.Has(experiments.PluggableStateStores) {
6475
// TODO(SarahFrench/radeksimko): Remove forked init logic once feature is no longer experimental
6576
return c.runPssInit(initArgs, view)
6677
} else {
@@ -1476,10 +1487,6 @@ Options:
14761487
14771488
-test-directory=path Set the Terraform test directory, defaults to "tests".
14781489
1479-
-enable-pluggable-state-storage-experiment [EXPERIMENTAL]
1480-
A flag to enable an alternative init command that allows use of
1481-
pluggable state storage. Only usable with experiments enabled.
1482-
14831490
-create-default-workspace [EXPERIMENTAL]
14841491
This flag must be used alongside the -enable-pluggable-state-storage-
14851492
experiment flag with experiments enabled. This flag's value defaults

internal/command/init_run.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/hashicorp/terraform/internal/command/arguments"
1515
"github.com/hashicorp/terraform/internal/command/views"
1616
"github.com/hashicorp/terraform/internal/configs"
17+
"github.com/hashicorp/terraform/internal/experiments"
1718
"github.com/hashicorp/terraform/internal/states"
1819
"github.com/hashicorp/terraform/internal/terraform"
1920
"github.com/hashicorp/terraform/internal/tfdiags"
@@ -142,7 +143,7 @@ func (c *InitCommand) run(initArgs *arguments.Init, view views.Init) int {
142143

143144
return 1
144145
}
145-
if !(c.Meta.AllowExperimentalFeatures && initArgs.EnablePssExperiment) && rootModEarly.StateStore != nil {
146+
if !(c.Meta.AllowExperimentalFeatures && rootModEarly.ActiveExperiments.Has(experiments.PluggableStateStores)) && rootModEarly.StateStore != nil {
146147
// TODO(SarahFrench/radeksimko) - remove when this feature isn't experimental.
147148
// This approach for making the feature experimental is required
148149
// to let us assert the feature is gated behind an experiment in tests.
@@ -152,11 +153,13 @@ func (c *InitCommand) run(initArgs *arguments.Init, view views.Init) int {
152153
if !c.Meta.AllowExperimentalFeatures {
153154
detail += " an experimental build of terraform"
154155
}
155-
if !initArgs.EnablePssExperiment {
156+
if !rootModEarly.ActiveExperiments.Has(experiments.PluggableStateStores) {
156157
if !c.Meta.AllowExperimentalFeatures {
157158
detail += " and"
158159
}
159-
detail += " -enable-pluggable-state-storage-experiment flag"
160+
detail += fmt.Sprintf(" the configuration to opt into the %q experiment using the `terraform` block's `experiments` attribute",
161+
experiments.PluggableStateStores.Keyword(),
162+
)
160163
}
161164

162165
diags = diags.Append(earlyConfDiags)

internal/command/init_test.go

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,7 @@ func TestInit_two_step_provider_download(t *testing.T) {
223223
},
224224
}
225225

226-
args := append(tc.flags, "-enable-pluggable-state-storage-experiment") // Needed to test init changes for PSS project
227-
if code := c.Run(args); code != 0 {
226+
if code := c.Run(tc.flags); code != 0 {
228227
t.Fatalf("bad: \n%s", done(t).All())
229228
}
230229

@@ -3264,7 +3263,7 @@ func TestInit_stateStore_newWorkingDir(t *testing.T) {
32643263
Meta: meta,
32653264
}
32663265

3267-
args := []string{"-enable-pluggable-state-storage-experiment=true"}
3266+
args := []string{}
32683267
code := c.Run(args)
32693268
testOutput := done(t)
32703269
if code != 0 {
@@ -3348,7 +3347,7 @@ func TestInit_stateStore_newWorkingDir(t *testing.T) {
33483347
},
33493348
}
33503349

3351-
args := []string{"-enable-pluggable-state-storage-experiment=true", "-create-default-workspace=false"}
3350+
args := []string{"-create-default-workspace=false"}
33523351
code := c.Run(args)
33533352
testOutput := done(t)
33543353
if code != 0 {
@@ -3398,7 +3397,7 @@ func TestInit_stateStore_newWorkingDir(t *testing.T) {
33983397
}
33993398

34003399
t.Setenv("TF_SKIP_CREATE_DEFAULT_WORKSPACE", "1") // any value
3401-
args := []string{"-enable-pluggable-state-storage-experiment=true"}
3400+
args := []string{}
34023401
code := c.Run(args)
34033402
testOutput := done(t)
34043403
if code != 0 {
@@ -3453,7 +3452,7 @@ func TestInit_stateStore_newWorkingDir(t *testing.T) {
34533452
Meta: meta,
34543453
}
34553454

3456-
args := []string{"-enable-pluggable-state-storage-experiment=true"}
3455+
args := []string{}
34573456
code := c.Run(args)
34583457
testOutput := done(t)
34593458
if code != 1 {
@@ -3527,7 +3526,6 @@ func TestInit_stateStore_newWorkingDir(t *testing.T) {
35273526

35283527
// If input is disabled users receive an error about the missing workspace
35293528
args := []string{
3530-
"-enable-pluggable-state-storage-experiment=true",
35313529
"-input=false",
35323530
}
35333531
code := c.Run(args)
@@ -3628,9 +3626,7 @@ func TestInit_stateStore_configUnchanged(t *testing.T) {
36283626
}
36293627

36303628
// Run init command
3631-
args := []string{
3632-
"-enable-pluggable-state-storage-experiment=true",
3633-
}
3629+
args := []string{}
36343630
code := c.Run(args)
36353631
testOutput := done(t)
36363632
if code != 0 {
@@ -3700,7 +3696,6 @@ func TestInit_stateStore_configChanges(t *testing.T) {
37003696
}
37013697

37023698
args := []string{
3703-
"-enable-pluggable-state-storage-experiment=true",
37043699
"-reconfigure",
37053700
}
37063701
code := c.Run(args)
@@ -3783,9 +3778,7 @@ func TestInit_stateStore_configChanges(t *testing.T) {
37833778
Meta: meta,
37843779
}
37853780

3786-
args := []string{
3787-
"-enable-pluggable-state-storage-experiment=true",
3788-
}
3781+
args := []string{}
37893782
code := c.Run(args)
37903783
testOutput := done(t)
37913784
if code != 1 {
@@ -3833,9 +3826,7 @@ func TestInit_stateStore_configChanges(t *testing.T) {
38333826
Meta: meta,
38343827
}
38353828

3836-
args := []string{
3837-
"-enable-pluggable-state-storage-experiment=true",
3838-
}
3829+
args := []string{}
38393830
code := c.Run(args)
38403831
testOutput := done(t)
38413832
if code != 1 {
@@ -3885,9 +3876,7 @@ func TestInit_stateStore_configChanges(t *testing.T) {
38853876
Meta: meta,
38863877
}
38873878

3888-
args := []string{
3889-
"-enable-pluggable-state-storage-experiment=true",
3890-
}
3879+
args := []string{}
38913880
code := c.Run(args)
38923881
testOutput := done(t)
38933882
if code != 1 {
@@ -3943,9 +3932,7 @@ func TestInit_stateStore_configChanges(t *testing.T) {
39433932
Meta: meta,
39443933
}
39453934

3946-
args := []string{
3947-
"-enable-pluggable-state-storage-experiment=true",
3948-
}
3935+
args := []string{}
39493936
code := c.Run(args)
39503937
testOutput := done(t)
39513938
if code != 1 {
@@ -3999,7 +3986,6 @@ func TestInit_stateStore_providerUpgrade(t *testing.T) {
39993986
}
40003987

40013988
args := []string{
4002-
"-enable-pluggable-state-storage-experiment=true",
40033989
"-upgrade",
40043990
}
40053991
code := c.Run(args)
@@ -4054,9 +4040,7 @@ func TestInit_stateStore_unset(t *testing.T) {
40544040
}
40554041

40564042
// Init
4057-
args := []string{
4058-
"-enable-pluggable-state-storage-experiment=true",
4059-
}
4043+
args := []string{}
40604044
code := c.Run(args)
40614045
testOutput := done(t)
40624046
if code != 0 {
@@ -4096,7 +4080,6 @@ func TestInit_stateStore_unset(t *testing.T) {
40964080
}
40974081

40984082
args := []string{
4099-
"-enable-pluggable-state-storage-experiment=true",
41004083
"-force-copy",
41014084
}
41024085
code := c.Run(args)
@@ -4152,9 +4135,7 @@ func TestInit_stateStore_unset_withoutProviderRequirements(t *testing.T) {
41524135
}
41534136

41544137
// Init
4155-
args := []string{
4156-
"-enable-pluggable-state-storage-experiment=true",
4157-
}
4138+
args := []string{}
41584139
code := c.Run(args)
41594140
testOutput := done(t)
41604141
if code != 0 {
@@ -4195,7 +4176,6 @@ func TestInit_stateStore_unset_withoutProviderRequirements(t *testing.T) {
41954176
}
41964177

41974178
args := []string{
4198-
"-enable-pluggable-state-storage-experiment=true",
41994179
"-force-copy",
42004180
}
42014181
code := c.Run(args)

internal/command/testdata/backend-to-state-store/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
terraform {
2+
experiments = [pluggable_state_stores]
23
required_providers {
34
test = {
45
source = "hashicorp/test"

internal/command/testdata/init-provider-download/config-and-state-different-providers/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
terraform {
2+
experiments = [pluggable_state_stores]
23
required_providers {
34
null = {
45
source = "hashicorp/null"

internal/command/testdata/init-provider-download/config-and-state-same-providers/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
terraform {
2+
experiments = [pluggable_state_stores]
23
required_providers {
34
random = {
45
source = "hashicorp/random"

internal/command/testdata/init-provider-download/config-state-file-and-lockfile/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
terraform {
2+
experiments = [pluggable_state_stores]
23
required_providers {
34
random = {
45
source = "hashicorp/random"

internal/command/testdata/init-provider-download/state-file-only/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
terraform {
2+
experiments = [pluggable_state_stores]
23
backend "local" {
34
path = "./state-using-random-provider.tfstate"
45
}

0 commit comments

Comments
 (0)