github.com/ezbercih/terraform@v0.1.1-0.20140729011846-3c33865e0839/builtin/provisioners/file/resource_provisioner.go (about)

     1  package file
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/hashicorp/terraform/helper/config"
    10  	helper "github.com/hashicorp/terraform/helper/ssh"
    11  	"github.com/hashicorp/terraform/terraform"
    12  )
    13  
    14  type ResourceProvisioner struct{}
    15  
    16  func (p *ResourceProvisioner) Apply(s *terraform.ResourceState,
    17  	c *terraform.ResourceConfig) error {
    18  	// Ensure the connection type is SSH
    19  	if err := helper.VerifySSH(s); err != nil {
    20  		return err
    21  	}
    22  
    23  	// Get the SSH configuration
    24  	conf, err := helper.ParseSSHConfig(s)
    25  	if err != nil {
    26  		return err
    27  	}
    28  
    29  	// Get the source and destination
    30  	sRaw := c.Config["source"]
    31  	src, ok := sRaw.(string)
    32  	if !ok {
    33  		return fmt.Errorf("Unsupported 'source' type! Must be string.")
    34  	}
    35  
    36  	dRaw := c.Config["destination"]
    37  	dst, ok := dRaw.(string)
    38  	if !ok {
    39  		return fmt.Errorf("Unsupported 'destination' type! Must be string.")
    40  	}
    41  	return p.copyFiles(conf, src, dst)
    42  }
    43  
    44  func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
    45  	v := &config.Validator{
    46  		Required: []string{
    47  			"source",
    48  			"destination",
    49  		},
    50  	}
    51  	return v.Validate(c)
    52  }
    53  
    54  // copyFiles is used to copy the files from a source to a destination
    55  func (p *ResourceProvisioner) copyFiles(conf *helper.SSHConfig, src, dst string) error {
    56  	// Get the SSH client config
    57  	config, err := helper.PrepareConfig(conf)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	// Wait and retry until we establish the SSH connection
    63  	var comm *helper.SSHCommunicator
    64  	err = retryFunc(conf.TimeoutVal, func() error {
    65  		host := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
    66  		comm, err = helper.New(host, config)
    67  		return err
    68  	})
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	info, err := os.Stat(src)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	// If we're uploading a directory, short circuit and do that
    79  	if info.IsDir() {
    80  		if err := comm.UploadDir(dst, src, nil); err != nil {
    81  			return fmt.Errorf("Upload failed: %v", err)
    82  		}
    83  		return nil
    84  	}
    85  
    86  	// We're uploading a file...
    87  	f, err := os.Open(src)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	defer f.Close()
    92  
    93  	err = comm.Upload(dst, f)
    94  	if err != nil {
    95  		return fmt.Errorf("Upload failed: %v", err)
    96  	}
    97  	return err
    98  }
    99  
   100  // retryFunc is used to retry a function for a given duration
   101  func retryFunc(timeout time.Duration, f func() error) error {
   102  	finish := time.After(timeout)
   103  	for {
   104  		err := f()
   105  		if err == nil {
   106  			return nil
   107  		}
   108  		log.Printf("Retryable error: %v", err)
   109  
   110  		select {
   111  		case <-finish:
   112  			return err
   113  		case <-time.After(3 * time.Second):
   114  		}
   115  	}
   116  }