github.com/openshift/installer@v1.4.17/pkg/terraform/init.go (about)

     1  package terraform
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"text/template"
    10  
    11  	"github.com/hashicorp/terraform-exec/tfexec"
    12  	"github.com/pkg/errors"
    13  	"k8s.io/apimachinery/pkg/util/sets"
    14  
    15  	"github.com/openshift/installer/data"
    16  	prov "github.com/openshift/installer/pkg/terraform/providers"
    17  )
    18  
    19  // unpack unpacks the platform-specific Terraform modules into the
    20  // given directory.
    21  func unpack(dir string, platform string, target string) (err error) {
    22  	err = data.Unpack(dir, filepath.Join(platform, target))
    23  	if err != nil {
    24  		return err
    25  	}
    26  
    27  	err = data.Unpack(filepath.Join(dir, "config.tf"), "config.tf")
    28  	if err != nil {
    29  		return err
    30  	}
    31  
    32  	platformVarFile := fmt.Sprintf("variables-%s.tf", platform)
    33  
    34  	err = data.Unpack(filepath.Join(dir, platformVarFile), filepath.Join(platform, platformVarFile))
    35  	if err != nil {
    36  		return err
    37  	}
    38  
    39  	err = data.Unpack(filepath.Join(dir, "terraform.rc"), "terraform.rc")
    40  	if err != nil {
    41  		return err
    42  	}
    43  
    44  	return nil
    45  }
    46  
    47  // unpackAndInit unpacks the platform-specific Terraform modules into
    48  // the given directory and then runs 'terraform init'.
    49  func unpackAndInit(dir string, platform string, target string, terraformDir string, providers []prov.Provider) (err error) {
    50  	err = unpack(dir, platform, target)
    51  	if err != nil {
    52  		return errors.Wrap(err, "failed to unpack Terraform modules")
    53  	}
    54  
    55  	if err := addVersionsFiles(dir, providers); err != nil {
    56  		return errors.Wrap(err, "failed to write versions.tf files")
    57  	}
    58  
    59  	tf, err := newTFExec(dir, terraformDir)
    60  	if err != nil {
    61  		return errors.Wrap(err, "failed to create a new tfexec")
    62  	}
    63  
    64  	// Explicitly specify the CLI config file to use so that we control the providers that are used.
    65  	os.Setenv("TF_CLI_CONFIG_FILE", filepath.Join(dir, "terraform.rc"))
    66  
    67  	return errors.Wrap(
    68  		tf.Init(context.Background(), tfexec.PluginDir(filepath.Join(terraformDir, "plugins"))),
    69  		"failed doing terraform init",
    70  	)
    71  }
    72  
    73  const versionFileTemplate = `terraform {
    74    required_version = ">= 1.0.0"
    75    required_providers {
    76  {{- range .}}
    77      {{.Name}} = {
    78        source = "{{.Source}}"
    79      }
    80  {{- end}}
    81    }
    82  }
    83  `
    84  
    85  func addVersionsFiles(dir string, providers []prov.Provider) error {
    86  	tmpl := template.Must(template.New("versions").Parse(versionFileTemplate))
    87  	buf := &bytes.Buffer{}
    88  	if err := tmpl.Execute(buf, providers); err != nil {
    89  		return errors.Wrap(err, "could not create versions.tf from template")
    90  	}
    91  	return addFileToAllDirectories("versions.tf", buf.Bytes(), dir)
    92  }
    93  
    94  func addFileToAllDirectories(name string, data []byte, dir string) error {
    95  	if err := os.WriteFile(filepath.Join(dir, name), data, 0666); err != nil {
    96  		return err
    97  	}
    98  	entries, err := os.ReadDir(dir)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	for _, entry := range entries {
   103  		if entry.IsDir() {
   104  			if err := addFileToAllDirectories(name, data, filepath.Join(dir, entry.Name())); err != nil {
   105  				return err
   106  			}
   107  		}
   108  	}
   109  	return nil
   110  }
   111  
   112  // UnpackTerraform unpacks the terraform binary and the specified provider binaries into the specified directory.
   113  func UnpackTerraform(dir string, stages []Stage) error {
   114  	// Unpack the terraform binary.
   115  	if err := prov.UnpackTerraformBinary(filepath.Join(dir, "bin")); err != nil {
   116  		return err
   117  	}
   118  
   119  	// Unpack the providers.
   120  	providers := sets.NewString()
   121  	for _, stage := range stages {
   122  		for _, provider := range stage.Providers() {
   123  			if providers.Has(provider.Name) {
   124  				continue
   125  			}
   126  			if err := provider.Extract(filepath.Join(dir, "plugins")); err != nil {
   127  				return err
   128  			}
   129  			providers.Insert(provider.Name)
   130  		}
   131  	}
   132  
   133  	return nil
   134  }