github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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/communicator" 10 "github.com/hashicorp/terraform/helper/config" 11 "github.com/hashicorp/terraform/terraform" 12 "github.com/mitchellh/go-homedir" 13 ) 14 15 // ResourceProvisioner represents a file provisioner 16 type ResourceProvisioner struct{} 17 18 // Apply executes the file provisioner 19 func (p *ResourceProvisioner) Apply( 20 o terraform.UIOutput, 21 s *terraform.InstanceState, 22 c *terraform.ResourceConfig) error { 23 // Get a new communicator 24 comm, err := communicator.New(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 src, err = homedir.Expand(src) 37 if err != nil { 38 return err 39 } 40 41 dRaw := c.Config["destination"] 42 dst, ok := dRaw.(string) 43 if !ok { 44 return fmt.Errorf("Unsupported 'destination' type! Must be string.") 45 } 46 return p.copyFiles(comm, src, dst) 47 } 48 49 // Validate checks if the required arguments are configured 50 func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) { 51 v := &config.Validator{ 52 Required: []string{ 53 "source", 54 "destination", 55 }, 56 } 57 return v.Validate(c) 58 } 59 60 // copyFiles is used to copy the files from a source to a destination 61 func (p *ResourceProvisioner) copyFiles(comm communicator.Communicator, src, dst string) error { 62 // Wait and retry until we establish the connection 63 err := retryFunc(comm.Timeout(), func() error { 64 err := comm.Connect(nil) 65 return err 66 }) 67 if err != nil { 68 return err 69 } 70 defer comm.Disconnect() 71 72 info, err := os.Stat(src) 73 if err != nil { 74 return err 75 } 76 77 // If we're uploading a directory, short circuit and do that 78 if info.IsDir() { 79 if err := comm.UploadDir(dst, src); err != nil { 80 return fmt.Errorf("Upload failed: %v", err) 81 } 82 return nil 83 } 84 85 // We're uploading a file... 86 f, err := os.Open(src) 87 if err != nil { 88 return err 89 } 90 defer f.Close() 91 92 err = comm.Upload(dst, f) 93 if err != nil { 94 return fmt.Errorf("Upload failed: %v", err) 95 } 96 return err 97 } 98 99 // retryFunc is used to retry a function for a given duration 100 func retryFunc(timeout time.Duration, f func() error) error { 101 finish := time.After(timeout) 102 for { 103 err := f() 104 if err == nil { 105 return nil 106 } 107 log.Printf("Retryable error: %v", err) 108 109 select { 110 case <-finish: 111 return err 112 case <-time.After(3 * time.Second): 113 } 114 } 115 }