stacks/stackconfig: Initial stubbing of Stacks language objects

This commit is contained in:
Martin Atkins 2023-05-22 17:09:53 -07:00
parent e667352553
commit c11edd0cd8
8 changed files with 219 additions and 0 deletions

View file

@ -0,0 +1,51 @@
package stackconfig
import (
"github.com/apparentlymart/go-versions/versions/constraints"
"github.com/hashicorp/go-slug/sourceaddrs"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/internal/addrs"
)
// Component represents the declaration of a single component within a
// particular [Stack].
//
// Components are the most important object in a stack configuration, just as
// resources are the most important object in a Terraform module: each one
// refers to a Terraform module that describes the infrastructure that the
// component is "made of".
type Component struct {
Name string
SourceAddr sourceaddrs.Source
AllowedVersions constraints.IntersectionSpec
ForEach hcl.Expression
// Inputs is an expression that should produce a value that can convert
// to an object type derived from the component's input variable
// declarations, and whose attribute values will then be used to populate
// those input variables.
Inputs hcl.Expression
// ProviderConfigs describes the mapping between the static provider
// configuration slots declared in the component's root module and the
// dynamic provider configuration objects in scope in the calling
// stack configuration.
//
// This map deals with the slight schism between the stacks language's
// treatment of provider configurations as regular values of a special
// data type vs. the main Terraform language's treatment of provider
// configurations as something special passed out of band from the
// input variables. The overall structure and the map keys are fixed
// statically during decoding, but the final provider configuration objects
// are determined only at runtime by normal expression evaluation.
//
// The keys of this map refer to provider configuration slots inside
// the module being called, but use the local names defined in the
// calling stack configuration. The stacks language runtime will
// translate the caller's local names into the callee's declared provider
// configurations by using the stack configuration's table of local
// provider names.
ProviderConfigs map[addrs.LocalProviderConfig]hcl.Expression
}

View file

@ -0,0 +1,18 @@
package stackconfig
// Config represents a node in a tree of stacks that are to be planned and
// applied together.
//
// A fully-resolved stack configuration has a root node of this type, which
// can have zero or more child nodes that are also of this type, and so on
// to arbitrary levels of nesting.
type Config struct {
// Stack is the definition of this node in the stack tree.
Stack *Stack
// Children describes all of the embedded stacks nested directly beneath
// this node in the stack tree. The keys match the labels on the "stack"
// blocks in the configuration that [Config.Stack] was built from, and
// so also match the keys in the EmbeddedStacks field of that Stack.
Children map[string]*Stack
}

View file

@ -0,0 +1,13 @@
// Package stackconfig deals with decoding and some static validation of the
// Terraform Stack language, which uses files with the suffixes .tfstack.hcl
// and .tfstack.json to describe a set of components to be planned and applied
// together.
//
// The Stack language has some elements that are intentionally similar to the
// main Terraform language (used to describe individual modules), but is
// currently implemented separately so they can evolve independently while
// the stacks language is still relatively new. Over time it might make sense
// to refactor so that there's only one implementation of each of the common
// elements, but we'll wait to see how similar things are once this language
// has been in real use for some time.
package stackconfig

View file

@ -0,0 +1,34 @@
package stackconfig
import (
"github.com/apparentlymart/go-versions/versions/constraints"
"github.com/hashicorp/go-slug/sourceaddrs"
"github.com/hashicorp/hcl/v2"
)
// EmbeddedStack describes a call to another stack configuration whose
// declarations should be included as part of the overall stack configuration
// tree.
//
// An embedded stack exists only as a child of another stack and doesn't have
// its own independent identity outside of that calling stack.
//
// Terraform Cloud offers a related concept of "linked stacks" where the
// deployment configuration for one stack can refer to the outputs of another,
// while the other stack retains its own independent identity and lifecycle,
// but that concept only makes sense in an environment like Terraform Cloud
// where the stack outputs can be published for external consumption.
type EmbeddedStack struct {
Name string
SourceAddr sourceaddrs.Source
AllowedVersions constraints.IntersectionSpec
ForEach hcl.Expression
// Inputs is an expression that should produce a value that can convert
// to an object type derived from the child stack's input variable
// declarations, and whose attribute values will then be used to populate
// those input variables.
Inputs hcl.Expression
}

View file

@ -0,0 +1,22 @@
package stackconfig
import "github.com/hashicorp/go-slug/sourceaddrs"
// File represents the content of a single .tfstack.hcl or .tfstack.json file
// before it's been merged with its siblings in the same directory to produce
// the overall [Stack] object.
type File struct {
// SourceAddr is the source location for this particular file, meaning
// that the "sub-path" portion of the address should always be populated
// and refer to a particular file rather than to a directory.
SourceAddr sourceaddrs.Source
// The remaining fields in here correspond to the fields of the same name in
// [Stack].
Components map[string]*Component
EmbeddedStacks map[string]*EmbeddedStack
InputVariables map[string]*InputVariable
LocalValues map[string]*LocalValue
OutputValues map[string]*OutputValue
ProviderConfigs map[string]*ProviderConfig
}

View file

@ -0,0 +1,26 @@
package stackconfig
import (
"github.com/zclconf/go-cty/cty"
)
// InputVariable is a declaration of an input variable within a stack
// configuration. Callers must provide the values for these variables.
type InputVariable struct {
Name string
TypeConstraint cty.Type
}
// LocalValue is a declaration of a private local value within a particular
// stack configuration. These are visible only within the scope of a particular
// [Stack].
type LocalValue struct {
Name string
}
// OutputValue is a declaration of a result from a stack configuration, which
// can be read by the stack's caller.
type OutputValue struct {
Name string
TypeConstraint cty.Type
}

View file

@ -0,0 +1,20 @@
package stackconfig
import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/internal/addrs"
)
// ProviderConfig is a provider configuration declared within a [Stack].
type ProviderConfig struct {
Provider addrs.Provider
Name string
// TODO: Figure out how we're going to retain the relevant subset of
// a provider configuration in the state so that we still have what
// we need to destroy any associated objects when a provider is removed
// from the configuration.
ForEach hcl.Expression
Config hcl.Body
}

View file

@ -0,0 +1,35 @@
package stackconfig
import (
"github.com/hashicorp/go-slug/sourceaddrs"
"github.com/hashicorp/terraform/internal/addrs"
)
// Stack represents a single stack, which can potentially call other
// "embedded stacks" in a similar manner to how Terraform modules can call
// other modules.
type Stack struct {
SourceAddr sourceaddrs.Source
// EmbeddedStacks are calls to other stack configurations that should
// be treated as a part of the overall desired state produced from this
// stack. These are declared with "stack" blocks in the stack language.
EmbeddedStacks map[string]*EmbeddedStack
// Components are calls to trees of Terraform modules that represent the
// real infrastructure described by a stack.
Components map[string]*Component
// InputVariables, LocalValues, and OutputValues together represent all
// of the "named values" in the stack configuration, which are just glue
// to pass values between scopes or to factor out common expressions for
// reuse in multiple locations.
InputVariables map[string]*InputVariable
LocalValues map[string]*LocalValue
OutputValues map[string]*OutputValue
// ProviderConfigs are the provider configurations declared in this
// particular stack configuration. Other stack configurations in the
// overall tree might have their own provider configurations.
ProviderConfigs map[addrs.Provider]map[string]*ProviderConfig
}