diff --git a/README.md b/README.md index 86821a6..06b24d0 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Execute from the working directory: docker run --rm \ -v $(pwd):$(pwd) \ -w $(pwd) \ - jmccann/drone-terraform:1 --plan + jmccann/drone-terraform:latest --plan ``` ## Drone 0.4 diff --git a/main.go b/main.go index ab9ab9a..65bc527 100644 --- a/main.go +++ b/main.go @@ -90,6 +90,11 @@ func main() { Usage: "destory all resurces", EnvVar: "PLUGIN_DESTROY", }, + cli.StringFlag{ + Name: "tf.version", + Usage: "terraform version to use", + EnvVar: "PLUGIN_TF_VERSION", + }, } if err := app.Run(os.Args); err != nil { @@ -137,6 +142,9 @@ func run(c *cli.Context) error { VarFiles: c.StringSlice("var_files"), Destroy: c.Bool("destroy"), }, + Terraform: Terraform{ + Version: c.String("tf.version"), + }, } return plugin.Exec() diff --git a/plugin.go b/plugin.go index 093e321..1bb5108 100644 --- a/plugin.go +++ b/plugin.go @@ -42,18 +42,30 @@ type ( // Plugin represents the plugin instance to be executed Plugin struct { - Config Config + Config Config + Terraform Terraform } ) // Exec executes the plugin func (p Plugin) Exec() error { + // Install specified version of terraform + if p.Terraform.Version != "" { + err := installTerraform(p.Terraform.Version) + + if err != nil { + return err + } + } + if p.Config.RoleARN != "" { assumeRole(p.Config.RoleARN) } var commands []*exec.Cmd + commands = append(commands, exec.Command("terraform", "version")) + CopyTfEnv() if p.Config.Cacert != "" { diff --git a/terraform.go b/terraform.go new file mode 100644 index 0000000..19ee04e --- /dev/null +++ b/terraform.go @@ -0,0 +1,113 @@ +package main + +import ( + "archive/zip" + "fmt" + "io" + "net/http" + "os" + "path/filepath" +) + +type ( + // Terraform holds input parameters for terraform + Terraform struct { + Version string + } +) + +func installTerraform(version string) error { + err := downloadTerraform(version) + if err != nil { + return nil + } + + return Unzip("/var/tmp/terraform.zip", "/bin") +} + +func downloadTerraform(version string) error { + return downloadFile("/var/tmp/terraform.zip", fmt.Sprintf("https://releases.hashicorp.com/terraform/%s/terraform_%s_linux_amd64.zip", version, version)) +} + +func downloadFile(filepath string, url string) error { + // Create the file + out, err := os.Create(filepath) + if err != nil { + return err + } + defer out.Close() + + // Get the data + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + // Writer the body to file + _, err = io.Copy(out, resp.Body) + if err != nil { + return err + } + + return nil +} + +func Unzip(src, dest string) error { + r, err := zip.OpenReader(src) + if err != nil { + return err + } + defer func() { + if err := r.Close(); err != nil { + panic(err) + } + }() + + os.MkdirAll(dest, 0755) + + // Closure to address file descriptors issue with all the deferred .Close() methods + extractAndWriteFile := func(f *zip.File) error { + rc, err := f.Open() + if err != nil { + return err + } + defer func() { + if err := rc.Close(); err != nil { + panic(err) + } + }() + + path := filepath.Join(dest, f.Name) + + if f.FileInfo().IsDir() { + os.MkdirAll(path, f.Mode()) + } else { + os.MkdirAll(filepath.Dir(path), f.Mode()) + f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + defer func() { + if err := f.Close(); err != nil { + panic(err) + } + }() + + _, err = io.Copy(f, rc) + if err != nil { + return err + } + } + return nil + } + + for _, f := range r.File { + err := extractAndWriteFile(f) + if err != nil { + return err + } + } + + return nil +}