Documentation
¶
Index ¶
- Constants
- func BundledBinaryPlatforms(archBase string) []string
- func BundledBinaryVersion(archBase string) string
- func DetectBundledBinary(archBase, requestedVersion string) string
- func DetectFilesystemMirror(archBase string) string
- func MirrorPlatforms(archBase string) []string
- func New(v *validator.Validate, opts ...workspaceOption) (*workspace, error)
- func WithArchive(arch archive.Archive) workspaceOption
- func WithBackend(back backend.Backend) workspaceOption
- func WithBinary(bin binary.Binary) workspaceOption
- func WithDisableCleanup(disable bool) workspaceOption
- func WithFilesystemMirror(path string) workspaceOption
- func WithHooks(hooks hooks.Hooks) workspaceOption
- func WithPlanBytes(bytes []byte) workspaceOption
- func WithVariables(vars variables.Variables) workspaceOption
- type Terraform
- type Workspace
Constants ¶
const BundledBinaryVersionFile = "VERSION"
BundledBinaryVersionFile is the filename of the version sidecar inside DefaultBundledBinaryDir.
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.
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
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
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
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
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
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 WithArchive ¶
func WithBackend ¶
func WithBinary ¶
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 WithPlanBytes ¶
func WithPlanBytes(bytes []byte) workspaceOption
func WithVariables ¶
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.