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 }