workspace

package
v0.19.913 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2026 License: AGPL-3.0 Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const BundledBinaryVersionFile = "VERSION"

BundledBinaryVersionFile is the filename of the version sidecar inside DefaultBundledBinaryDir.

View Source
const DefaultBundledBinaryDir = ".terraform-binaries"

DefaultBundledBinaryDir is the conventional directory name (relative to an archive base path) that holds a terraform CLI binary vendored at build time. The build runner writes per-platform binaries at `<archBase>/<DefaultBundledBinaryDir>/<os>_<arch>/terraform` plus a sibling `VERSION` sidecar that records the terraform version they were built for. The install runner looks at the same path to decide whether it can run terraform fully airgapped.

Mirrors the shape of DefaultFilesystemMirrorDir for providers — same "filesystem-driven, feature-flag-unaware" rule on the install side.

View Source
const DefaultFilesystemMirrorDir = ".terraform-providers"

DefaultFilesystemMirrorDir is the conventional directory name (relative to a workspace root or an archive base path) that holds a terraform provider filesystem mirror. Build runners write the mirror into this directory and install runners pass the same path to WithFilesystemMirror.

The leading dot avoids polluting `terraform fmt` output without colliding with terraform's own `.terraform/` working directory (which the runner ignores during archive packaging).

Variables

This section is empty.

Functions

func BundledBinaryPlatforms added in v0.19.903

func BundledBinaryPlatforms(archBase string) []string

BundledBinaryPlatforms returns the sorted, de-duplicated set of `<os>_<arch>` platforms that have a vendored terraform CLI binary inside archBase. Returns nil when the bundled-binary directory is absent or contains no platform subdirectories. Used both by DetectBundledBinary (to decide whether the host platform is supported) and by callers that want to surface the vendored platform set in logs.

func BundledBinaryVersion added in v0.19.903

func BundledBinaryVersion(archBase string) string

BundledBinaryVersion returns the trimmed contents of the VERSION sidecar inside the bundled-binary directory of an unpacked archive, or "" if the sidecar is missing or unreadable. Used for the version-mismatch fallback branch in DetectBundledBinary and for diagnostic logging.

func DetectBundledBinary added in v0.19.903

func DetectBundledBinary(archBase, requestedVersion string) string

DetectBundledBinary returns an absolute path to a build-vendored terraform CLI binary suitable for handing to a workspace's Binary implementation, or "" if the install runner should fall back to fetching terraform from releases.hashicorp.com as before.

Returns "" when:

  • the bundled-binary directory is absent (older artifact / feature off)
  • no platform subdirectory matches runtime.GOOS_runtime.GOARCH
  • the host platform binary exists but is not a regular file
  • a VERSION sidecar is present and disagrees with requestedVersion

We intentionally do NOT gate on the executable bit: OCI artifacts pulled via oras-go's file.Store do not preserve POSIX mode, so a vendored binary that was 0755 at build time lands at 0644 on the install runner. The localbinary consumer chmods 0755 at Install time — checking exec mode here would just produce a false negative and silently fall through to the remote install path.

The version-mismatch case is the key compat lever: if a component bumps `terraform_version` between builds and an old artifact is still around, we never silently run the wrong CLI version against the new config — we fall through to remotebinary instead. When the sidecar is absent (older vendored builds, before the sidecar was introduced) we accept the binary on the assumption build and install agree on the version they're both reading from the same component config.

Mirrors DetectFilesystemMirror's contract: install side stays feature-flag-unaware, decision is purely from on-disk artifact contents, empty return is a safe no-op.

func DetectFilesystemMirror added in v0.19.903

func DetectFilesystemMirror(archBase string) string

DetectFilesystemMirror returns the path to pass to WithFilesystemMirror (relative to the workspace root), or "" if the unpacked archive at archBase does not contain a non-empty provider mirror tree at DefaultFilesystemMirrorDir, or if the mirror does not include the current runtime platform (runtime.GOOS_runtime.GOARCH).

The install runner is intentionally feature-flag-unaware: whether or not providers are vendored is decided server-side at build time, and the install side only checks "did the artifact ship one we can use?". Callers should pass the result straight to WithFilesystemMirror — an empty string is a no-op and terraform init falls back to direct registry resolution.

The platform check is a guard against cross-platform install runners (notably local-dev macOS): if the airgap mirror only ships linux_amd64 + linux_arm64 zips and the install runner is darwin_arm64, writing the `direct { exclude = ["*/*"] }` .terraformrc would deadlock terraform init. We'd rather fall back to direct registry resolution on the unsupported platform than fail loudly — production install runners are linux and will always find their platform in the mirror.

We return a workspace-relative path because the dirarchive copies the mirror into the workspace root; the workspace then resolves the absolute path against its own root, not the archive base.

func MirrorPlatforms added in v0.19.903

func MirrorPlatforms(archBase string) []string

MirrorPlatforms returns the sorted, de-duplicated set of `<os>_<arch>` platforms present in the filesystem mirror at archBase/DefaultFilesystemMirrorDir, derived from packed provider zip filenames. Returns nil if no mirror exists or it has no recognizable provider zips.

Used both by DetectFilesystemMirror (to decide whether the current runtime platform is supported) and by callers that want to log the vendored platform set for diagnostics.

func New

func New(v *validator.Validate, opts ...workspaceOption) (*workspace, error)

func WithArchive

func WithArchive(arch archive.Archive) workspaceOption

func WithBackend

func WithBackend(back backend.Backend) workspaceOption

func WithBinary

func WithBinary(bin binary.Binary) workspaceOption

func WithDisableCleanup

func WithDisableCleanup(disable bool) workspaceOption

func WithFilesystemMirror added in v0.19.903

func WithFilesystemMirror(path string) workspaceOption

WithFilesystemMirror configures the workspace to consume providers from a terraform filesystem mirror at the given path instead of downloading them from registry.terraform.io. See the FilesystemMirrorPath field for details.

func WithHooks

func WithHooks(hooks hooks.Hooks) workspaceOption

func WithPlanBytes

func WithPlanBytes(bytes []byte) workspaceOption

func WithVariables

func WithVariables(vars variables.Variables) workspaceOption

Types

type Terraform

type Terraform interface {
	// SetEnv allows you to override environment variables, this should not be used for any well known
	// Terraform environment variables that are already covered in options. Pass nil to copy the values
	// from os.Environ. Attempting to set environment variables that should be managed manually will
	// result in ErrManualEnvVar being returned.
	SetEnv(env map[string]string) error
	// SetLogger specifies a logger for tfexec to use.
	// SetStdout specifies a writer to stream stdout to for every command.
	//
	// This should be used for information or logging purposes only, not control
	// flow. Any parsing necessary should be added as functionality to this package.
	SetStdout(w io.Writer)
	// SetStderr specifies a writer to stream stderr to for every command.
	//
	// This should be used for information or logging purposes only, not control
	// flow. Any parsing necessary should be added as functionality to this package.
	SetStderr(w io.Writer)
	// SetLog sets the TF_LOG environment variable for Terraform CLI execution.
	// This must be combined with a call to SetLogPath to take effect.
	//
	// This is only compatible with Terraform CLI 0.15.0 or later as setting the
	// log level was unreliable in earlier versions. It will default to TRACE when
	// SetLogPath is called on versions 0.14.11 and earlier, or if SetLogCore and
	// SetLogProvider have not been called before SetLogPath on versions 0.15.0 and
	// later.
	SetLog(log string) error
	// SetLogCore sets the TF_LOG_CORE environment variable for Terraform CLI
	// execution. This must be combined with a call to SetLogPath to take effect.
	//
	// This is only compatible with Terraform CLI 0.15.0 or later.
	SetLogCore(logCore string) error
	// SetLogPath sets the TF_LOG_PATH environment variable for Terraform CLI
	// execution.
	SetLogPath(path string) error
	// SetLogProvider sets the TF_LOG_PROVIDER environment variable for Terraform
	// CLI execution. This must be combined with a call to SetLogPath to take
	// effect.
	//
	// This is only compatible with Terraform CLI 0.15.0 or later.
	SetLogProvider(logProvider string) error
	// SetAppendUserAgent sets the TF_APPEND_USER_AGENT environment variable for
	// Terraform CLI execution.
	SetAppendUserAgent(ua string) error
	// SetDisablePluginTLS sets the TF_DISABLE_PLUGIN_TLS environment variable for
	// Terraform CLI execution.
	SetDisablePluginTLS(disabled bool) error
	// SetSkipProviderVerify sets the TF_SKIP_PROVIDER_VERIFY environment variable
	// for Terraform CLI execution. This is no longer used in 0.13.0 and greater.
	SetSkipProviderVerify(skip bool) error
	// WorkingDir returns the working directory for Terraform.
	WorkingDir() string
	// ExecPath returns the path to the Terraform executable.
	ExecPath() string
	Init(ctx context.Context, opts ...tfexec.InitOption) error
	// Apply represents the terraform apply subcommand.
	Apply(ctx context.Context, opts ...tfexec.ApplyOption) error
	// ApplyJSON represents the terraform apply subcommand with the `-json` flag.
	// Using the `-json` flag will result in
	// [machine-readable](https://developer.hashicorp.com/terraform/internals/machine-readable-ui)
	// JSON being written to the supplied `io.Writer`. ApplyJSON is likely to be
	// removed in a future major version in favour of Apply returning JSON by default.
	ApplyJSON(ctx context.Context, w io.Writer, opts ...tfexec.ApplyOption) error
	// Destroy represents the terraform destroy subcommand.
	Destroy(ctx context.Context, opts ...tfexec.DestroyOption) error
	// DestroyJSON represents the terraform destroy subcommand with the `-json` flag.
	// Using the `-json` flag will result in
	// [machine-readable](https://developer.hashicorp.com/terraform/internals/machine-readable-ui)
	// JSON being written to the supplied `io.Writer`. DestroyJSON is likely to be
	// removed in a future major version in favour of Destroy returning JSON by default.
	DestroyJSON(ctx context.Context, w io.Writer, opts ...tfexec.DestroyOption) error
	// FormatString formats a passed string.
	FormatString(ctx context.Context, content string) (string, error)
	// Format performs formatting on the unformatted io.Reader (as stdin to the CLI) and returns
	// the formatted result on the formatted io.Writer.
	Format(ctx context.Context, unformatted io.Reader, formatted io.Writer) error
	// FormatWrite attempts to format and modify all config files in the working or selected (via DirOption) directory.
	FormatWrite(ctx context.Context, opts ...tfexec.FormatOption) error
	// FormatCheck returns true if the config files in the working or selected (via DirOption) directory are already formatted.
	FormatCheck(ctx context.Context, opts ...tfexec.FormatOption) (bool, []string, error)
	ForceUnlock(ctx context.Context, lockID string, opts ...tfexec.ForceUnlockOption) error
	Graph(ctx context.Context, opts ...tfexec.GraphOption) (string, error)
	// Output represents the terraform output subcommand.
	Output(ctx context.Context, opts ...tfexec.OutputOption) (map[string]tfexec.OutputMeta, error)
	Validate(ctx context.Context) (*tfjson.ValidateOutput, error)
	// Plan executes `terraform plan` with the specified options and waits for it
	// to complete.
	//
	// The returned boolean is false when the plan diff is empty (no changes) and
	// true when the plan diff is non-empty (changes present).
	//
	// The returned error is nil if `terraform plan` has been executed and exits
	// with either 0 or 2.
	Plan(ctx context.Context, opts ...tfexec.PlanOption) (bool, error)
	// PlanJSON executes `terraform plan` with the specified options as well as the
	// `-json` flag and waits for it to complete.
	//
	// Using the `-json` flag will result in
	// [machine-readable](https://developer.hashicorp.com/terraform/internals/machine-readable-ui)
	// JSON being written to the supplied `io.Writer`.
	//
	// The returned boolean is false when the plan diff is empty (no changes) and
	// true when the plan diff is non-empty (changes present).
	//
	// The returned error is nil if `terraform plan` has been executed and exits
	// with either 0 or 2.
	//
	// PlanJSON is likely to be removed in a future major version in favour of
	// Plan returning JSON by default.
	PlanJSON(ctx context.Context, w io.Writer, opts ...tfexec.PlanOption) (bool, error)
	// ProvidersLock represents the `terraform providers lock` command
	ProvidersLock(ctx context.Context, opts ...tfexec.ProvidersLockOption) error
	Get(ctx context.Context, opts ...tfexec.GetCmdOption) error
	// ProvidersSchema represents the terraform providers schema -json subcommand.
	ProvidersSchema(ctx context.Context) (*tfjson.ProviderSchemas, error)
	// Refresh represents the terraform refresh subcommand.
	Refresh(ctx context.Context, opts ...tfexec.RefreshCmdOption) error
	// RefreshJSON represents the terraform refresh subcommand with the `-json` flag.
	// Using the `-json` flag will result in
	// [machine-readable](https://developer.hashicorp.com/terraform/internals/machine-readable-ui)
	// JSON being written to the supplied `io.Writer`. RefreshJSON is likely to be
	// removed in a future major version in favour of Refresh returning JSON by default.
	RefreshJSON(ctx context.Context, w io.Writer, opts ...tfexec.RefreshCmdOption) error
	// Show reads the default state path and outputs the state.
	// To read a state or plan file, ShowState or ShowPlan must be used instead.
	Show(ctx context.Context, opts ...tfexec.ShowOption) (*tfjson.State, error)
	// ShowStateFile reads a given state file and outputs the state.
	ShowStateFile(ctx context.Context, statePath string, opts ...tfexec.ShowOption) (*tfjson.State, error)
	// ShowPlanFile reads a given plan file and outputs the plan.
	ShowPlanFile(ctx context.Context, planPath string, opts ...tfexec.ShowOption) (*tfjson.Plan, error)
	// ShowPlanFileRaw reads a given plan file and outputs the plan in a
	// human-friendly, opaque format.
	ShowPlanFileRaw(ctx context.Context, planPath string, opts ...tfexec.ShowOption) (string, error)
	// StateMv represents the terraform state mv subcommand.
	StateMv(ctx context.Context, source, destination string, opts ...tfexec.StateMvCmdOption) error
}

Terraform represents the client that terraform exposes in `tfexec`. We interface it here, so we can mock it and expose tests for this locally.

type Workspace

type Workspace interface {
	// LoadArchive loads the archives into the workspace
	LoadArchive(ctx context.Context) error
	// LoadBackend loads the backend from the provided plugin
	LoadBackend(ctx context.Context) error
	// LoadBinary installs the binary using the provided binary
	LoadBinary(ctx context.Context, log hclog.Logger) error
	// LoadHooks initializes any hooks that need to be executed
	LoadHooks(ctx context.Context) error
	// InitRoot: initializes workspace should be called before any other load functions
	InitRoot(ctx context.Context) error
	//LoadVariables is used to load the variables into the environment
	LoadVariables(ctx context.Context) error
	// Root returns the root directory
	Root() string

	Cleanup(ctx context.Context) error

	// the following commands are used to run terraform operations against a workspace
	Apply(context.Context, hclog.Logger) ([]byte, error)
	ApplyPlan(context.Context, hclog.Logger) ([]byte, error)
	Destroy(context.Context, hclog.Logger) ([]byte, error)
	ApplyDestroyPlan(context.Context, hclog.Logger) ([]byte, error)
	Init(context.Context, hclog.Logger) error
	Refresh(context.Context, hclog.Logger) ([]byte, error)
	Plan(context.Context, hclog.Logger) ([]byte, error)
	Output(context.Context, hclog.Logger) (map[string]tfexec.OutputMeta, error)
	Show(context.Context, hclog.Logger) (*tfjson.State, error)
	ShowPlan(context.Context, hclog.Logger) (*tfjson.Plan, error)
	// StateMv renames a resource address in state without touching infra.
	StateMv(ctx context.Context, log hclog.Logger, source, destination string) error
	Validate(context.Context, hclog.Logger) (*tfjson.ValidateOutput, error)
	// Writes plan to plan.json
	WriteTFPlan(context.Context, hclog.Logger) ([]byte, error)
	CompressTFPlan(context.Context, hclog.Logger) ([]byte, error)
	PlanDestroy(context.Context, hclog.Logger) ([]byte, error)
	GetTfplan(ctx context.Context, log hclog.Logger) ([]byte, error)
	GetTfplanCompressed(ctx context.Context, log hclog.Logger) ([]byte, error)
	GetTfplanJsonCompressed(ctx context.Context, log hclog.Logger) ([]byte, error)
}

Workspace represents an environment for working with a terraform module + state.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL