pkg/resource_schema.go (85 lines of code) (raw):
package pkg
import (
"context"
"fmt"
"github.com/hashicorp/terraform-exec/tfexec"
tfjson "github.com/hashicorp/terraform-json"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
)
type TerraformProviderSchemaRetriever interface {
Get(providerSource, versionConstraint string) (*tfjson.ProviderSchema, error)
}
type TerraformCliProviderSchemaRetriever struct {
ctx context.Context
}
func NewTerraformCliProviderSchemaRetriever(ctx context.Context) TerraformProviderSchemaRetriever {
return TerraformCliProviderSchemaRetriever{ctx: ctx}
}
func (t TerraformCliProviderSchemaRetriever) Get(providerSource, versionConstraint string) (*tfjson.ProviderSchema, error) {
tmpFolder, err := os.MkdirTemp("", "*")
if err != nil {
return nil, fmt.Errorf("error creating temp TF code folder: %s", err)
}
defer func() {
_ = os.RemoveAll(tmpFolder)
}()
tfProviderCode := fmt.Sprintf(`
terraform {
required_providers {
provider = {
source = "%s"
version = "%s"
}
}
}
`, providerSource, versionConstraint)
err = os.WriteFile(filepath.Join(tmpFolder, "main.tf"), []byte(tfProviderCode), 0600)
if err != nil {
return nil, fmt.Errorf("error writing temp TF code file: %s", err)
}
execPath, err := t.getTerraformPath()
if err != nil {
return nil, err
}
workingDir := tmpFolder
tf, err := tfexec.NewTerraform(workingDir, execPath)
if err != nil {
return nil, fmt.Errorf("error running NewTerraform: %w", err)
}
err = tf.Init(t.ctx, tfexec.Upgrade(true))
if err != nil {
return nil, fmt.Errorf("error running Init: %s", err)
}
schema, err := tf.ProvidersSchema(t.ctx)
if err != nil {
return nil, fmt.Errorf("error running providers: %w", err)
}
src := fmt.Sprintf("registry.terraform.io/%s", providerSource)
r, ok := schema.Schemas[src]
if !ok {
src = providerSource
r = schema.Schemas[src]
}
return r, nil
}
func (t TerraformCliProviderSchemaRetriever) getTerraformPath() (string, error) {
var cmd *exec.Cmd
if t.isWindows() {
cmd = exec.Command("where", "terraform")
} else {
cmd = exec.Command("which", "terraform")
}
out, err := cmd.Output()
if err != nil {
return "", err
}
path := strings.TrimSpace(string(out))
return path, nil
}
func (t TerraformCliProviderSchemaRetriever) isWindows() bool {
return runtime.GOOS == "windows"
}