mirror of
https://github.com/hashicorp/terraform.git
synced 2026-03-21 18:10:30 -04:00
103 lines
3.2 KiB
Go
103 lines
3.2 KiB
Go
// Copyright IBM Corp. 2014, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package workdir
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
ctyjson "github.com/zclconf/go-cty/cty/json"
|
|
|
|
"github.com/hashicorp/terraform/internal/configs/configschema"
|
|
"github.com/hashicorp/terraform/internal/plans"
|
|
)
|
|
|
|
var _ ConfigState = &BackendConfigState{}
|
|
var _ DeepCopier[BackendConfigState] = &BackendConfigState{}
|
|
var _ PlanDataProvider[plans.Backend] = &BackendConfigState{}
|
|
|
|
// BackendConfigState describes the physical storage format for the backend state
|
|
// in a working directory, and provides the lowest-level API for decoding it.
|
|
type BackendConfigState struct {
|
|
Type string `json:"type"` // Backend type
|
|
ConfigRaw json.RawMessage `json:"config"` // Backend raw config
|
|
Hash uint64 `json:"hash"` // Hash of portion of configuration from config files
|
|
}
|
|
|
|
// Empty returns true if there is no active backend.
|
|
//
|
|
// In practice this typically means that the working directory is using the
|
|
// implied local backend, but that decision is made by the caller.
|
|
func (s *BackendConfigState) Empty() bool {
|
|
return s == nil || s.Type == ""
|
|
}
|
|
|
|
// Config decodes the type-specific configuration object using the provided
|
|
// schema and returns the result as a cty.Value.
|
|
//
|
|
// An error is returned if the stored configuration does not conform to the
|
|
// given schema, or is otherwise invalid.
|
|
func (s *BackendConfigState) Config(schema *configschema.Block) (cty.Value, error) {
|
|
ty := schema.ImpliedType()
|
|
if s == nil {
|
|
return cty.NullVal(ty), nil
|
|
}
|
|
return ctyjson.Unmarshal(s.ConfigRaw, ty)
|
|
}
|
|
|
|
// SetConfig replaces (in-place) the type-specific configuration object using
|
|
// the provided value and associated schema.
|
|
//
|
|
// An error is returned if the given value does not conform to the implied
|
|
// type of the schema.
|
|
func (s *BackendConfigState) SetConfig(val cty.Value, schema *configschema.Block) error {
|
|
if s == nil {
|
|
return errors.New("SetConfig called on nil BackendConfigState receiver")
|
|
}
|
|
ty := schema.ImpliedType()
|
|
buf, err := ctyjson.Marshal(val, ty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.ConfigRaw = buf
|
|
return nil
|
|
}
|
|
|
|
// PlanData produces an alternative representation of the receiver that is
|
|
// suitable for storing in a plan. The current workspace must additionally
|
|
// be provided, to be stored alongside the backend configuration.
|
|
//
|
|
// The backend configuration schema is required in order to properly
|
|
// encode the backend-specific configuration settings.
|
|
//
|
|
// As backends are not implemented by providers, the provider schema argument should always be nil
|
|
func (s *BackendConfigState) PlanData(schema *configschema.Block, _ *configschema.Block, workspaceName string) (*plans.Backend, error) {
|
|
if s == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
configVal, err := s.Config(schema)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode backend config: %w", err)
|
|
}
|
|
return plans.NewBackend(s.Type, configVal, schema, workspaceName)
|
|
}
|
|
|
|
func (s *BackendConfigState) DeepCopy() *BackendConfigState {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
ret := &BackendConfigState{
|
|
Type: s.Type,
|
|
Hash: s.Hash,
|
|
}
|
|
|
|
if s.ConfigRaw != nil {
|
|
ret.ConfigRaw = make([]byte, len(s.ConfigRaw))
|
|
copy(ret.ConfigRaw, s.ConfigRaw)
|
|
}
|
|
return ret
|
|
}
|