From f215d31df438ce23187bd30282ac1862fde4c31a Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 14 Jul 2014 14:28:37 -0700 Subject: [PATCH] provisioner/remote-exec: Collect scripts to upload --- .../remote-exec/resource_provisioner.go | 72 +++++++++++++++ .../remote-exec/resource_provisioner_test.go | 90 +++++++++++++++++++ .../remote-exec/test-fixtures/script1.sh | 4 + 3 files changed, 166 insertions(+) create mode 100755 builtin/provisioners/remote-exec/test-fixtures/script1.sh diff --git a/builtin/provisioners/remote-exec/resource_provisioner.go b/builtin/provisioners/remote-exec/resource_provisioner.go index 4d9150f4d..02cbcc7c9 100644 --- a/builtin/provisioners/remote-exec/resource_provisioner.go +++ b/builtin/provisioners/remote-exec/resource_provisioner.go @@ -1,7 +1,11 @@ package remoteexec import ( + "bytes" "fmt" + "io" + "io/ioutil" + "os" "strings" "github.com/hashicorp/terraform/terraform" @@ -54,6 +58,13 @@ func (p *ResourceProvisioner) Apply(s *terraform.ResourceState, return s, err } + // Collect the scripts + _, err = p.collectScripts(c) + if err != nil { + return s, err + } + + // For-each script, copy + exec panic("not implemented") return s, nil } @@ -147,3 +158,64 @@ func (p *ResourceProvisioner) generateScript(c *terraform.ResourceConfig) (strin lines = append(lines, "") return strings.Join(lines, "\n"), nil } + +// collectScripts is used to collect all the scripts we need +// to execute in preperation for copying them. +func (p *ResourceProvisioner) collectScripts(c *terraform.ResourceConfig) ([]io.ReadCloser, error) { + // Check if inline + _, ok := c.Config["inline"] + if ok { + script, err := p.generateScript(c) + if err != nil { + return nil, err + } + rc := ioutil.NopCloser(bytes.NewReader([]byte(script))) + return []io.ReadCloser{rc}, nil + } + + // Collect scripts + var scripts []string + s, ok := c.Config["script"] + if ok { + sStr, ok := s.(string) + if !ok { + return nil, fmt.Errorf("Unsupported 'script' type! Must be a string.") + } + scripts = append(scripts, sStr) + } + + sl, ok := c.Config["scripts"] + if ok { + switch slt := sl.(type) { + case []string: + scripts = append(scripts, slt...) + case []interface{}: + for _, l := range slt { + lStr, ok := l.(string) + if ok { + scripts = append(scripts, lStr) + } else { + return nil, fmt.Errorf("Unsupported 'scripts' type! Must be list of strings.") + } + } + default: + return nil, fmt.Errorf("Unsupported 'scripts' type! Must be list of strings.") + } + } + + // Open all the scripts + var fhs []io.ReadCloser + for _, s := range scripts { + fh, err := os.Open(s) + if err != nil { + for _, fh := range fhs { + fh.Close() + } + return nil, fmt.Errorf("Failed to open script '%s': %v", s, err) + } + fhs = append(fhs, fh) + } + + // Done, return the file handles + return fhs, nil +} diff --git a/builtin/provisioners/remote-exec/resource_provisioner_test.go b/builtin/provisioners/remote-exec/resource_provisioner_test.go index 27112f42b..1f89bf0e3 100644 --- a/builtin/provisioners/remote-exec/resource_provisioner_test.go +++ b/builtin/provisioners/remote-exec/resource_provisioner_test.go @@ -1,6 +1,8 @@ package remoteexec import ( + "bytes" + "io" "testing" "github.com/hashicorp/terraform/config" @@ -126,6 +128,94 @@ wget http://foobar exit 0 ` +func TestResourceProvider_CollectScripts_inline(t *testing.T) { + p := new(ResourceProvisioner) + conf := testConfig(t, map[string]interface{}{ + "inline": []string{ + "cd /tmp", + "wget http://foobar", + "exit 0", + }, + }) + + scripts, err := p.collectScripts(conf) + if err != nil { + t.Fatalf("err: %v", err) + } + + if len(scripts) != 1 { + t.Fatalf("bad: %v", scripts) + } + + var out bytes.Buffer + _, err = io.Copy(&out, scripts[0]) + if err != nil { + t.Fatalf("err: %v", err) + } + + if string(out.Bytes()) != expectedScriptOut { + t.Fatalf("bad: %v", out.Bytes()) + } +} + +func TestResourceProvider_CollectScripts_script(t *testing.T) { + p := new(ResourceProvisioner) + conf := testConfig(t, map[string]interface{}{ + "script": "test-fixtures/script1.sh", + }) + + scripts, err := p.collectScripts(conf) + if err != nil { + t.Fatalf("err: %v", err) + } + + if len(scripts) != 1 { + t.Fatalf("bad: %v", scripts) + } + + var out bytes.Buffer + _, err = io.Copy(&out, scripts[0]) + if err != nil { + t.Fatalf("err: %v", err) + } + + if string(out.Bytes()) != expectedScriptOut { + t.Fatalf("bad: %v", out.Bytes()) + } +} + +func TestResourceProvider_CollectScripts_scripts(t *testing.T) { + p := new(ResourceProvisioner) + conf := testConfig(t, map[string]interface{}{ + "scripts": []interface{}{ + "test-fixtures/script1.sh", + "test-fixtures/script1.sh", + "test-fixtures/script1.sh", + }, + }) + + scripts, err := p.collectScripts(conf) + if err != nil { + t.Fatalf("err: %v", err) + } + + if len(scripts) != 3 { + t.Fatalf("bad: %v", scripts) + } + + for idx := range scripts { + var out bytes.Buffer + _, err = io.Copy(&out, scripts[idx]) + if err != nil { + t.Fatalf("err: %v", err) + } + + if string(out.Bytes()) != expectedScriptOut { + t.Fatalf("bad: %v", out.Bytes()) + } + } +} + func testConfig( t *testing.T, c map[string]interface{}) *terraform.ResourceConfig { diff --git a/builtin/provisioners/remote-exec/test-fixtures/script1.sh b/builtin/provisioners/remote-exec/test-fixtures/script1.sh new file mode 100755 index 000000000..cd22f3e63 --- /dev/null +++ b/builtin/provisioners/remote-exec/test-fixtures/script1.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cd /tmp +wget http://foobar +exit 0