-
Notifications
You must be signed in to change notification settings - Fork 1.5k
*: include terraform in the installer binary #797
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| /bin/ | ||
| .openshift-install.log | ||
| /data/data/bin/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,59 +2,20 @@ package terraform | |
|
|
||
| import ( | ||
| "bytes" | ||
| "os" | ||
| "os/exec" | ||
| "path/filepath" | ||
| "runtime" | ||
| "strings" | ||
|
|
||
| "github.com/openshift/installer/pkg/lineprinter" | ||
| "github.com/pkg/errors" | ||
| "github.com/sirupsen/logrus" | ||
| ) | ||
|
|
||
| // executor enables calling Terraform from Go, across platforms, with any | ||
| // additional providers/provisioners that the currently executing binary | ||
| // exposes. | ||
| // | ||
| // The Terraform binary is expected to be in the executing binary's folder, in | ||
| // the current working directory or in the PATH. | ||
| type executor struct { | ||
| binaryPath string | ||
| } | ||
|
|
||
| // Set the binary names for different platforms | ||
| const ( | ||
| tfBinUnix = "terraform" | ||
| tfBinWindows = "terraform.exe" | ||
crawford marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| // errBinaryNotFound denotes the fact that the Terraform binary could not be | ||
| // found on disk. | ||
| var errBinaryNotFound = errors.New( | ||
| "terraform not in executable's folder, cwd nor PATH", | ||
| ) | ||
|
|
||
| // newExecutor initializes a new Executor. | ||
| func newExecutor() (*executor, error) { | ||
| ex := new(executor) | ||
|
|
||
| // Find the Terraform binary. | ||
| binPath, err := tfBinaryPath() | ||
| if err != nil { | ||
| return nil, errors.Wrap(err, "failed to get Terraform binary's path") | ||
| } | ||
|
|
||
| ex.binaryPath = binPath | ||
| return ex, nil | ||
| } | ||
|
|
||
| // Execute runs the given command and arguments against Terraform. | ||
| // | ||
| // An error is returned if the Terraform binary could not be found, or if the | ||
| // Terraform call itself failed, in which case, details can be found in the | ||
| // output. | ||
| func (ex *executor) execute(clusterDir string, args ...string) error { | ||
| func Execute(clusterDir string, args ...string) error { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to make this public. Can we change this (and the name in the godoc above) to |
||
| // Prepare Terraform command by setting up the command, configuration, | ||
| // and the working directory | ||
| if clusterDir == "" { | ||
|
|
@@ -67,7 +28,7 @@ func (ex *executor) execute(clusterDir string, args ...string) error { | |
|
|
||
| stderr := &bytes.Buffer{} | ||
|
|
||
| cmd := exec.Command(ex.binaryPath, args...) | ||
| cmd := exec.Command(filepath.Join(clusterDir, executablePath), args...) | ||
| cmd.Dir = clusterDir | ||
| cmd.Stdout = linePrinter | ||
| cmd.Stderr = stderr | ||
|
|
@@ -80,67 +41,3 @@ func (ex *executor) execute(clusterDir string, args ...string) error { | |
| } | ||
| return err | ||
| } | ||
|
|
||
| // Version gets the output of 'terrraform version'. | ||
| func Version() (version string, err error) { | ||
| // Find the Terraform binary. | ||
| binPath, err := tfBinaryPath() | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| output, err := exec.Command(binPath, "version").Output() | ||
| if err != nil { | ||
| exitError := err.(*exec.ExitError) | ||
| if len(exitError.Stderr) == 0 { | ||
| exitError.Stderr = output | ||
| } | ||
| } | ||
| return strings.TrimRight(string(output), "\n"), err | ||
| } | ||
|
|
||
| // tfBinaryPath searches for a Terraform binary on disk: | ||
| // - in the executing binary's folder, | ||
| // - in the current working directory, | ||
| // - in the PATH. | ||
| // The first to be found is the one returned. | ||
| func tfBinaryPath() (string, error) { | ||
| // Depending on the platform, the expected binary name is different. | ||
| binaryFileName := tfBinUnix | ||
| if runtime.GOOS == "windows" { | ||
| binaryFileName = tfBinWindows | ||
| } | ||
|
|
||
| // Find the current executable's path, gets an absolute path or error | ||
| execPath, err := os.Executable() | ||
| if err == nil { | ||
| // execPath could be a symlink | ||
| if stat, err := os.Stat(execPath); err == nil && (stat.Mode()&os.ModeSymlink) == os.ModeSymlink { | ||
| if evalExecPath, err := filepath.EvalSymlinks(execPath); err != nil { | ||
| execPath = evalExecPath | ||
| } | ||
| } | ||
|
|
||
| // Look into the executable's folder. | ||
| path := filepath.Join(filepath.Dir(execPath), binaryFileName) | ||
| if stat, err := os.Stat(path); err == nil && !stat.IsDir() { | ||
| return path, nil | ||
| } | ||
| } | ||
|
|
||
| // Look into cwd. | ||
| if workingDirectory, err := os.Getwd(); err == nil { | ||
| path := filepath.Join(workingDirectory, binaryFileName) | ||
| if stat, err := os.Stat(path); err == nil && !stat.IsDir() { | ||
| return path, nil | ||
| } | ||
| } | ||
|
|
||
| // If we still haven't found the executable, look for it | ||
| // in the PATH. | ||
| if path, err := exec.LookPath(binaryFileName); err == nil { | ||
| return filepath.Abs(path) | ||
| } | ||
|
|
||
| return "", errBinaryNotFound | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ package terraform | |
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
|
|
||
| "github.com/openshift/installer/data" | ||
|
|
@@ -10,17 +11,12 @@ import ( | |
|
|
||
| const ( | ||
| // StateFileName is the default name for Terraform state files. | ||
| StateFileName string = "terraform.tfstate" | ||
| StateFileName string = "terraform.tfstate" | ||
| executablePath string = "bin/terraform" | ||
| ) | ||
|
|
||
| func terraformExec(clusterDir string, args ...string) error { | ||
| // Create an executor | ||
| ex, err := newExecutor() | ||
| if err != nil { | ||
| return errors.Wrap(err, "failed to create Terraform executor") | ||
| } | ||
|
|
||
| err = ex.execute(clusterDir, args...) | ||
| err := Execute(clusterDir, args...) | ||
| if err != nil { | ||
| return errors.Wrap(err, "failed to execute Terraform") | ||
| } | ||
|
|
@@ -93,6 +89,16 @@ func unpackAndInit(dir string, platform string) (err error) { | |
| return errors.Wrap(err, "failed to unpack Terraform modules") | ||
| } | ||
|
|
||
| err = data.Unpack(filepath.Join(dir, executablePath), filepath.FromSlash(executablePath)) | ||
| if err != nil { | ||
| return errors.Wrap(err, "failed to unpack Terraform binary") | ||
| } | ||
|
|
||
| err = os.Chmod(filepath.Join(dir, executablePath), 0555) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will need |
||
| if err != nil { | ||
| return errors.Wrap(err, "failed to make Terraform binary executable") | ||
| } | ||
|
|
||
| err = terraformExec(dir, "init", "-input=false", "-no-color") | ||
| if err != nil { | ||
| return errors.Wrap(err, "failed to initialize Terraform") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wking do you know a good way of calculating
"../../.."from"data/data/bin/terraform"?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I came up with the following, but it may be more effort than it is worth:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, one way would be to use hardlinks instead of symlinks:
See the
<number of links>field changing from 1 to 2 after thelncall.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume all of this will always be on the same filesystem, so a hardlink should work. I'll go with that instead.