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 }