Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

SarahFrench
Copy link
Member

@SarahFrench SarahFrench commented Oct 7, 2025

Description

This PR allows an init command to successfully initialise a project that uses the new state_store block:

  • when the working directory doesn't have a backend state file yet/is uninitialised.
  • when the working directory does have a backend state file but it's ignored due to using the -reconfigure flag.

Behaviour changes versus the equivalent logic for backends

1) Problem: Creation of workspaces is not explicit and happens as a side effect of other code

Expand to read details about current behaviour with `backend`

Currently during an init command when using a backend block the state file for a new workspace is first created as a side effect of obtaining a state manager for that workspace's state. What this looks like depends on whether it's a custom workspace or the "default" workspace.

During an init the default default workspace's state file may be created, depending on the backend in use. If it's not made during init it'll be created later when the first apply persists state. When using the local backend the default workspace file is only made at apply time. When using the gcs backend this code responds to there being no state present for a given workspace by creating that state file, including for the default workspace. Other backends like s3 do this but only for custom workspaces, and the default workspace's state file is only made at apply time.

The code linked above is also used when new custom workspaces are created when a user runs a workspace new commands. This code creates the new workspace as a side effect of obtaining a state manager.

Something worth calling out: remote-state backends create state files for non-default workspaces when obtaining a state manager via the StateMgr method to ensure that the new workspace is listed by the Workspaces method later in the same operation. Also, all remote-state backends' Workspaces methods are hardcoded to report that the "default" workspace exits, regardless of whether there is a default workspace state file.

Overall this shows that Terraform core relies on remote-state backends being implemented in a consistent way for Terraform operations to work as expected. This is a risk, as we cannot rely on all pluggable state storage implementations being implemented in a consistent way to match how remote-state backends behave today.

Solution: Make creation of workspaces (i.e. persisting empty state in a way that signifies a new workspace) an explicit responsibility of Terraform core code

Terraform will now explicitly create custom workspaces by writing an empty state to a new file via the state store.

The default workspace will need special handling, as it's not consciously created by users like custom workspaces are. Instead the init command will need to detect if the default workspace is selected but doesn't currently exist, and then persist an empty state file for the default workspace. This is achieved here:

if ws == backend.DefaultStateName {
// Users control if the default workspace is created through the -create-default-workspace flag (defaults to true)
if opts.CreateDefaultWorkspace {
diags = diags.Append(m.createDefaultWorkspace(c, b))
} else {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "The default workspace does not exist",
Detail: "Terraform has been configured to skip creation of the default workspace in the state store. To create it, either remove the `-create-default-workspace=false` flag and re-run the 'init' command, or create it using a 'workspace new' command",
})
}

Creating the default workspace will happen by default and will not ask the user for confirmation, which matches the UX with backends. If a user wants to skip this behaviour in CI they can set -create-default-workspace=false and -input=false. The -create-default-workspace flag default to true, and it cannot be set to false if Terraform is not in CI (i.e. -input=true`).

2) Before: Users prompted for input if required fields aren't in the configuration (or present in override data)

If a user doesn't supply a value for a required field in a backend they're prompted for a value through the terminal:

// TODO: test
if m.Input() {
var err error
configVal, err = m.inputForSchema(configVal, schema)
if err != nil {
diags = diags.Append(fmt.Errorf("Error asking for input to configure backend %q: %s", c.Type, err))
}

After: Terraform will return errors to users and prompt them to supply a value for the required field via other methods.

We've purposefully avoided prompting users for missing values. Instead, users should supply values through configuration, overrides, or ENVs. If users require the ability to supply values through input during another operation we should wait for feature requests to learn more about the reasons/use case.

Target Release

N/A

Rollback Plan

  • If a change needs to be reverted, we will roll out an update to the code within 7 days.

Changes to Security Controls

Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.

CHANGELOG entry

  • This change is user-facing and I added a changelog entry.
  • This change is not user-facing.

@SarahFrench SarahFrench added the no-changelog-needed Add this to your PR if the change does not require a changelog entry label Oct 7, 2025
Copy link
Contributor

github-actions bot commented Oct 7, 2025

The equivalence tests failed. Please investigate here.

Copy link
Member Author

@SarahFrench SarahFrench left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving some thoughts of my own & highlighting some things, as I appreciate this is a large PR to parse. There are a bunch of changes but hopefully it's manageable once the test fixture changes are hidden and once it's clear that all the new code is feeding into or is called by the new stateStore_C_s method.

internal/command/meta_providers.go Show resolved Hide resolved
internal/command/meta_backend.go Show resolved Hide resolved
internal/command/meta_backend.go Outdated Show resolved Hide resolved
@SarahFrench SarahFrench force-pushed the pss/init-empty-workdir branch from a41b9da to 4c2528d Compare October 8, 2025 11:03
@SarahFrench
Copy link
Member Author

I just force pushed to remove some commits that included changes to try debug the test failure on the PR, no code changes were added other than the new commit 4c2528d

Ideally I'd like to get that removed test code working, but I'm unsure why the testStdinPipe helper fails in this test but other tests pass ok 🤔

@SarahFrench SarahFrench marked this pull request as ready for review October 8, 2025 11:07
@SarahFrench SarahFrench requested a review from a team as a code owner October 8, 2025 11:07
internal/command/command_test.go Outdated Show resolved Hide resolved
internal/command/meta_backend.go Outdated Show resolved Hide resolved
internal/command/meta_backend.go Outdated Show resolved Hide resolved
internal/command/meta_backend.go Outdated Show resolved Hide resolved
internal/command/meta_backend.go Outdated Show resolved Hide resolved
internal/command/meta_backend.go Show resolved Hide resolved
internal/command/meta_backend_test.go Show resolved Hide resolved
internal/command/init_test.go Show resolved Hide resolved
internal/command/init_test.go Show resolved Hide resolved
internal/command/arguments/init.go Show resolved Hide resolved
internal/command/arguments/init.go Outdated Show resolved Hide resolved
@SarahFrench
Copy link
Member Author

Force push was to rebase onto #37762 and change any new errors in this PR into functions in meta_backend_errors.go

This can only be done once modules have been parsed and the required providers data is available. There are multiple places where config is parsed, into either Config or Module structs, so this needs to be implemented in multiple places.
…ng code to access the provider schema when using provider configuration data.
…version Version.

This is needed for using locks when creating the backend state file.
…eStore_C_s`. Default to creating the default workspace if no workspaces exist.
The `testingOverrides` field will only be set in tests, so this should not impact end users.
… time (and do the same when forced by -reconfigure flag). Remove replaced tests.
…e default workspace by default when -input=false (i.e for use in CI). Refactor creation of default workspace logic. Add tests.
…n't exist, but other workspaces do exist.

The consequences here are due to using `selectWorkspace` in `stateStore_C_s`, matching what's done in `backend_C_r_s`.
This test passes when run in isolation but fails when run alongside other tests, even when skipping all other tests using `testStdinPipe`. I don't think the value of this test is great enough to start changing how we test stdin input.
…ils of errors copying data to stdin.

Note: We cannot call t.Fatal from a non-test goroutine.
@SarahFrench SarahFrench force-pushed the pss/init-empty-workdir branch from 82372c1 to e79ea11 Compare October 13, 2025 15:07
internal/command/meta_backend.go Show resolved Hide resolved
Copy link
Member

@radeksimko radeksimko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have yet to give this a full (manual) test run but the code generally LGTM aside from that one concern regarding the new flag.

internal/command/arguments/init.go Show resolved Hide resolved
@SarahFrench SarahFrench merged commit 6b73f71 into main Oct 15, 2025
7 checks passed
@SarahFrench SarahFrench deleted the pss/init-empty-workdir branch October 15, 2025 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog-needed Add this to your PR if the change does not require a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.