blob: ae4e9cbc9d0dfb6ac9b541a5c79534240223c6df [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package graph
import (
"fmt"
"log"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/moduletest"
"github.com/hashicorp/terraform/internal/providers"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/hashicorp/terraform/version"
)
var (
_ GraphNodeExecutable = (*NodeProviderConfigure)(nil)
_ GraphNodeReferencer = (*NodeProviderConfigure)(nil)
)
type NodeProviderConfigure struct {
name, alias string
Addr addrs.RootProviderConfig
File *moduletest.File
Config *configs.Provider
Provider providers.Interface
Schema providers.GetProviderSchemaResponse
}
func (n *NodeProviderConfigure) Name() string {
if len(n.alias) > 0 {
return fmt.Sprintf("provider.%s.%s", n.name, n.alias)
}
return fmt.Sprintf("provider.%s", n.name)
}
func (n *NodeProviderConfigure) Execute(ctx *EvalContext) {
log.Printf("[TRACE]: NodeProviderConfigure: configuring provider %s for tests", n.Addr)
if ctx.Cancelled() || ctx.Stopped() {
return
}
// first, set the provider so everything else can use it
ctx.SetProvider(n.Addr, n.Provider)
spec := n.Schema.Provider.Body.DecoderSpec()
var references []*addrs.Reference
var referenceDiags tfdiags.Diagnostics
for _, traversal := range hcldec.Variables(n.Config.Config, spec) {
ref, moreDiags := addrs.ParseRefFromTestingScope(traversal)
referenceDiags = referenceDiags.Append(moreDiags)
if ref != nil {
references = append(references, ref)
}
}
n.File.AppendDiagnostics(referenceDiags)
if referenceDiags.HasErrors() {
ctx.SetProviderStatus(n.Addr, moduletest.Error)
return
}
if !ctx.ReferencesCompleted(references) {
ctx.SetProviderStatus(n.Addr, moduletest.Skip)
return
}
hclContext, moreDiags := ctx.HclContext(references)
n.File.AppendDiagnostics(moreDiags)
if moreDiags.HasErrors() {
ctx.SetProviderStatus(n.Addr, moduletest.Error)
return
}
body, hclDiags := hcldec.Decode(n.Config.Config, spec, hclContext)
n.File.AppendDiagnostics(moreDiags)
if hclDiags.HasErrors() {
ctx.SetProviderStatus(n.Addr, moduletest.Error)
return
}
unmarkedBody, _ := body.UnmarkDeep()
response := n.Provider.ConfigureProvider(providers.ConfigureProviderRequest{
TerraformVersion: version.SemVer.String(),
Config: unmarkedBody,
ClientCapabilities: providers.ClientCapabilities{
DeferralAllowed: false, // TODO: Enable deferrals in test framework.
WriteOnlyAttributesAllowed: true,
},
})
n.File.AppendDiagnostics(response.Diagnostics)
if response.Diagnostics.HasErrors() {
ctx.SetProviderStatus(n.Addr, moduletest.Error)
return
}
}
func (n *NodeProviderConfigure) References() []*addrs.Reference {
var refs []*addrs.Reference
for _, variable := range hcldec.Variables(n.Config.Config, n.Schema.Provider.Body.DecoderSpec()) {
ref, _ := addrs.ParseRefFromTestingScope(variable)
if ref != nil {
refs = append(refs, ref)
}
}
return refs
}
var (
_ GraphNodeExecutable = (*NodeProviderClose)(nil)
)
type NodeProviderClose struct {
name, alias string
Addr addrs.RootProviderConfig
File *moduletest.File
Config *configs.Provider
Provider providers.Interface
}
func (n *NodeProviderClose) Name() string {
if len(n.alias) > 0 {
return fmt.Sprintf("provider.%s.%s (close)", n.name, n.alias)
}
return fmt.Sprintf("provider.%s (close)", n.name)
}
func (n *NodeProviderClose) Execute(ctx *EvalContext) {
log.Printf("[TRACE]: NodeProviderClose: closing provider %s for tests", n.Addr)
// we don't check for cancelled or stopped here - we still want to kill
// any running providers even if someone has stopped or cancelled the
// process
if err := n.Provider.Close(); err != nil {
var diags tfdiags.Diagnostics
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Failed to close provider",
Detail: fmt.Sprintf("Failed to close provider: %s", err.Error()),
Subject: n.Config.DeclRange.Ptr(),
})
n.File.AppendDiagnostics(diags)
}
}