stackeval: Make some provisioners available to stack components

This makes the built-in "remote-exec" and "file" provisioners available
for use in the modules that implement stack components. These are both
relatively easy and low-risk to include because they are builtins and
don't require anything from outside of Terraform itself.

For now this intentionally excludes local-exec because we'll want to think
about what constraints we want to put on it, if any, to help ensure we can
meet the goal of stack configurations being portable between different
execution environments without significant modification, and our current
stacks execution environment doesn't guarantee the availability of any
external software _at all_.

The motivation for adding this now is just to give some better feedback
when someone uses a module using one of these provisioners, since otherwise
they'll see just a confusing generic error message from the modules
runtime about the provisioners not being available. I expect we'll revisit
this later and consider expanding it to at least include local-exec, and
_maybe_ external provisioner plugins, although that's more questionable
because the provisioner plugin mechanism is incredibly legacy and doesn't
have any way to work outside of local Terraform CLI usage today.

There are no tests here yet because these provisioners are not mockable
and would depend on having an SSH or WinRM server to connect to. Later we
should ponder how to make this more testable, which might mean making
another part of the system responsible for actually providing the
provisioner factories and thus our tests here can use fakes. The goal here
is just to get this done in a relatively lightweight way for better
feedback during preview though, so we're not yet ready to make significant
time investments here.
pull/34510/head
Martin Atkins 2 years ago
parent 6071e06f1a
commit 3c14eeb945

@ -12,6 +12,8 @@ import (
"github.com/zclconf/go-cty/cty/convert"
"github.com/hashicorp/terraform/internal/addrs"
fileProvisioner "github.com/hashicorp/terraform/internal/builtin/provisioners/file"
remoteExecProvisioner "github.com/hashicorp/terraform/internal/builtin/provisioners/remote-exec"
"github.com/hashicorp/terraform/internal/collections"
"github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/hashicorp/terraform/internal/instances"
@ -19,6 +21,7 @@ import (
"github.com/hashicorp/terraform/internal/plans"
"github.com/hashicorp/terraform/internal/promising"
"github.com/hashicorp/terraform/internal/providers"
"github.com/hashicorp/terraform/internal/provisioners"
"github.com/hashicorp/terraform/internal/stacks/stackaddrs"
"github.com/hashicorp/terraform/internal/stacks/stackconfig/stackconfigtypes"
"github.com/hashicorp/terraform/internal/stacks/stackplan"
@ -490,6 +493,7 @@ func (c *ComponentInstance) CheckModuleTreePlan(ctx context.Context) (*plans.Pla
},
},
PreloadedProviderSchemas: providerSchemas,
Provisioners: c.availableProvisioners(),
})
if err != nil {
// Should not get here because we should always pass a valid
@ -662,6 +666,7 @@ func (c *ComponentInstance) ApplyModuleTreePlan(ctx context.Context, plan *plans
tfHook,
},
PreloadedProviderSchemas: providerSchemas,
Provisioners: c.availableProvisioners(),
})
if err != nil {
// Should not get here because we should always pass a valid
@ -1301,6 +1306,35 @@ func (c *ComponentInstance) resourceTypeSchema(ctx context.Context, providerType
return ret, nil
}
// availableProvisioners returns the table of provisioner factories that should
// be made available to modules in this component.
func (c *ComponentInstance) availableProvisioners() map[string]provisioners.Factory {
return map[string]provisioners.Factory{
"remote-exec": func() (provisioners.Interface, error) {
return remoteExecProvisioner.New(), nil
},
"file": func() (provisioners.Interface, error) {
return fileProvisioner.New(), nil
},
"local-exec": func() (provisioners.Interface, error) {
// We don't yet have any way to ensure a consistent execution
// environment for local-exec, which means that use of this
// provisioner is very likely to hurt portability between
// local and remote usage of stacks. Existing use of local-exec
// also tends to assume a writable module directory, whereas
// stack components execute from a read-only directory.
//
// Therefore we'll leave this unavailable for now with an explicit
// error message, although we might revisit this later if there's
// a strong reason to allow it and if we can find a suitable
// way to avoid the portability pitfalls that might inhibit
// moving execution of a stack from one execution environment to
// another.
return nil, fmt.Errorf("local-exec provisioners are not supported in stack components; use provider functionality or remote provisioners instead")
},
}
}
func (c *ComponentInstance) tracingName() string {
return c.Addr().String()
}

Loading…
Cancel
Save