provisioners/file: convert to helper/schema
This commit is contained in:
parent
0fb87cd96b
commit
02a4adc07c
|
@ -1,6 +1,7 @@
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
@ -8,26 +9,48 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/communicator"
|
"github.com/hashicorp/terraform/communicator"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResourceProvisioner represents a file provisioner
|
func Provisioner() terraform.ResourceProvisioner {
|
||||||
type ResourceProvisioner struct{}
|
return &schema.Provisioner{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"source": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ConflictsWith: []string{"content"},
|
||||||
|
},
|
||||||
|
|
||||||
|
"content": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ConflictsWith: []string{"source"},
|
||||||
|
},
|
||||||
|
|
||||||
|
"destination": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ApplyFunc: applyFn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyFn(ctx context.Context) error {
|
||||||
|
connData := ctx.Value(schema.ProvConnDataKey).(*schema.ResourceData)
|
||||||
|
data := ctx.Value(schema.ProvConfigDataKey).(*schema.ResourceData)
|
||||||
|
|
||||||
// Apply executes the file provisioner
|
|
||||||
func (p *ResourceProvisioner) Apply(
|
|
||||||
o terraform.UIOutput,
|
|
||||||
s *terraform.InstanceState,
|
|
||||||
c *terraform.ResourceConfig) error {
|
|
||||||
// Get a new communicator
|
// Get a new communicator
|
||||||
comm, err := communicator.New(s)
|
comm, err := communicator.NewData(connData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the source
|
// Get the source
|
||||||
src, deleteSource, err := p.getSrc(c)
|
src, deleteSource, err := getSrc(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -36,57 +59,20 @@ func (p *ResourceProvisioner) Apply(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get destination
|
// Get destination
|
||||||
dRaw := c.Config["destination"]
|
dst := data.Get("destination").(string)
|
||||||
dst, ok := dRaw.(string)
|
return copyFiles(comm, src, dst)
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Unsupported 'destination' type! Must be string.")
|
|
||||||
}
|
|
||||||
return p.copyFiles(comm, src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks if the required arguments are configured
|
|
||||||
func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
|
|
||||||
numDst := 0
|
|
||||||
numSrc := 0
|
|
||||||
for name := range c.Raw {
|
|
||||||
switch name {
|
|
||||||
case "destination":
|
|
||||||
numDst++
|
|
||||||
case "source", "content":
|
|
||||||
numSrc++
|
|
||||||
default:
|
|
||||||
es = append(es, fmt.Errorf("Unknown configuration '%s'", name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if numSrc != 1 || numDst != 1 {
|
|
||||||
es = append(es, fmt.Errorf("Must provide one of 'content' or 'source' and 'destination' to file"))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSrc returns the file to use as source
|
// getSrc returns the file to use as source
|
||||||
func (p *ResourceProvisioner) getSrc(c *terraform.ResourceConfig) (string, bool, error) {
|
func getSrc(data *schema.ResourceData) (string, bool, error) {
|
||||||
var src string
|
src := data.Get("source").(string)
|
||||||
|
if content, ok := data.GetOk("content"); ok {
|
||||||
sRaw, ok := c.Config["source"]
|
|
||||||
if ok {
|
|
||||||
if src, ok = sRaw.(string); !ok {
|
|
||||||
return "", false, fmt.Errorf("Unsupported 'source' type! Must be string.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
content, ok := c.Config["content"]
|
|
||||||
if ok {
|
|
||||||
file, err := ioutil.TempFile("", "tf-file-content")
|
file, err := ioutil.TempFile("", "tf-file-content")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", true, err
|
return "", true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contentStr, ok := content.(string)
|
if _, err = file.WriteString(content.(string)); err != nil {
|
||||||
if !ok {
|
|
||||||
return "", true, fmt.Errorf("Unsupported 'content' type! Must be string.")
|
|
||||||
}
|
|
||||||
if _, err = file.WriteString(contentStr); err != nil {
|
|
||||||
return "", true, err
|
return "", true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +84,7 @@ func (p *ResourceProvisioner) getSrc(c *terraform.ResourceConfig) (string, bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyFiles is used to copy the files from a source to a destination
|
// copyFiles is used to copy the files from a source to a destination
|
||||||
func (p *ResourceProvisioner) copyFiles(comm communicator.Communicator, src, dst string) error {
|
func copyFiles(comm communicator.Communicator, src, dst string) error {
|
||||||
// Wait and retry until we establish the connection
|
// Wait and retry until we establish the connection
|
||||||
err := retryFunc(comm.Timeout(), func() error {
|
err := retryFunc(comm.Timeout(), func() error {
|
||||||
err := comm.Connect(nil)
|
err := comm.Connect(nil)
|
||||||
|
|
|
@ -7,16 +7,12 @@ import (
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResourceProvisioner_impl(t *testing.T) {
|
|
||||||
var _ terraform.ResourceProvisioner = new(ResourceProvisioner)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResourceProvider_Validate_good_source(t *testing.T) {
|
func TestResourceProvider_Validate_good_source(t *testing.T) {
|
||||||
c := testConfig(t, map[string]interface{}{
|
c := testConfig(t, map[string]interface{}{
|
||||||
"source": "/tmp/foo",
|
"source": "/tmp/foo",
|
||||||
"destination": "/tmp/bar",
|
"destination": "/tmp/bar",
|
||||||
})
|
})
|
||||||
p := new(ResourceProvisioner)
|
p := Provisioner()
|
||||||
warn, errs := p.Validate(c)
|
warn, errs := p.Validate(c)
|
||||||
if len(warn) > 0 {
|
if len(warn) > 0 {
|
||||||
t.Fatalf("Warnings: %v", warn)
|
t.Fatalf("Warnings: %v", warn)
|
||||||
|
@ -31,7 +27,7 @@ func TestResourceProvider_Validate_good_content(t *testing.T) {
|
||||||
"content": "value to copy",
|
"content": "value to copy",
|
||||||
"destination": "/tmp/bar",
|
"destination": "/tmp/bar",
|
||||||
})
|
})
|
||||||
p := new(ResourceProvisioner)
|
p := Provisioner()
|
||||||
warn, errs := p.Validate(c)
|
warn, errs := p.Validate(c)
|
||||||
if len(warn) > 0 {
|
if len(warn) > 0 {
|
||||||
t.Fatalf("Warnings: %v", warn)
|
t.Fatalf("Warnings: %v", warn)
|
||||||
|
@ -45,7 +41,7 @@ func TestResourceProvider_Validate_bad_not_destination(t *testing.T) {
|
||||||
c := testConfig(t, map[string]interface{}{
|
c := testConfig(t, map[string]interface{}{
|
||||||
"source": "nope",
|
"source": "nope",
|
||||||
})
|
})
|
||||||
p := new(ResourceProvisioner)
|
p := Provisioner()
|
||||||
warn, errs := p.Validate(c)
|
warn, errs := p.Validate(c)
|
||||||
if len(warn) > 0 {
|
if len(warn) > 0 {
|
||||||
t.Fatalf("Warnings: %v", warn)
|
t.Fatalf("Warnings: %v", warn)
|
||||||
|
@ -61,7 +57,7 @@ func TestResourceProvider_Validate_bad_to_many_src(t *testing.T) {
|
||||||
"content": "value to copy",
|
"content": "value to copy",
|
||||||
"destination": "/tmp/bar",
|
"destination": "/tmp/bar",
|
||||||
})
|
})
|
||||||
p := new(ResourceProvisioner)
|
p := Provisioner()
|
||||||
warn, errs := p.Validate(c)
|
warn, errs := p.Validate(c)
|
||||||
if len(warn) > 0 {
|
if len(warn) > 0 {
|
||||||
t.Fatalf("Warnings: %v", warn)
|
t.Fatalf("Warnings: %v", warn)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/communicator/remote"
|
"github.com/hashicorp/terraform/communicator/remote"
|
||||||
"github.com/hashicorp/terraform/communicator/ssh"
|
"github.com/hashicorp/terraform/communicator/ssh"
|
||||||
"github.com/hashicorp/terraform/communicator/winrm"
|
"github.com/hashicorp/terraform/communicator/winrm"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,3 +52,18 @@ func New(s *terraform.InstanceState) (Communicator, error) {
|
||||||
return nil, fmt.Errorf("connection type '%s' not supported", connType)
|
return nil, fmt.Errorf("connection type '%s' not supported", connType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewData creates a new Communicator from a ResourceData structure that
|
||||||
|
// represents the connection information.
|
||||||
|
func NewData(d *schema.ResourceData) (Communicator, error) {
|
||||||
|
// Turn the ResourceData into a legacy-style ConnInfo struct that
|
||||||
|
// is used to instantiate the communicator.
|
||||||
|
raw := d.State()
|
||||||
|
state := &terraform.InstanceState{
|
||||||
|
Ephemeral: terraform.EphemeralState{
|
||||||
|
ConnInfo: raw.Attributes,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(state)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue