github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/builder/vmware/common/driver.go (about) 1 package common 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "os/exec" 8 "runtime" 9 "strconv" 10 "strings" 11 12 "github.com/mitchellh/multistep" 13 ) 14 15 // A driver is able to talk to VMware, control virtual machines, etc. 16 type Driver interface { 17 // Clone clones the VMX and the disk to the destination path. The 18 // destination is a path to the VMX file. The disk will be copied 19 // to that same directory. 20 Clone(dst string, src string) error 21 22 // CompactDisk compacts a virtual disk. 23 CompactDisk(string) error 24 25 // CreateDisk creates a virtual disk with the given size. 26 CreateDisk(string, string, string) error 27 28 // Checks if the VMX file at the given path is running. 29 IsRunning(string) (bool, error) 30 31 // SSHAddress returns the SSH address for the VM that is being 32 // managed by this driver. 33 SSHAddress(multistep.StateBag) (string, error) 34 35 // Start starts a VM specified by the path to the VMX given. 36 Start(string, bool) error 37 38 // Stop stops a VM specified by the path to the VMX given. 39 Stop(string) error 40 41 // SuppressMessages modifies the VMX or surrounding directory so that 42 // VMware doesn't show any annoying messages. 43 SuppressMessages(string) error 44 45 // Get the path to the VMware ISO for the given flavor. 46 ToolsIsoPath(string) string 47 48 // Attach the VMware tools ISO 49 ToolsInstall() error 50 51 // Get the path to the DHCP leases file for the given device. 52 DhcpLeasesPath(string) string 53 54 // Verify checks to make sure that this driver should function 55 // properly. This should check that all the files it will use 56 // appear to exist and so on. If everything is okay, this doesn't 57 // return an error. Otherwise, this returns an error. 58 Verify() error 59 } 60 61 // NewDriver returns a new driver implementation for this operating 62 // system, or an error if the driver couldn't be initialized. 63 func NewDriver(dconfig *DriverConfig, config *SSHConfig) (Driver, error) { 64 drivers := []Driver{} 65 66 switch runtime.GOOS { 67 case "darwin": 68 drivers = []Driver{ 69 &Fusion6Driver{ 70 Fusion5Driver: Fusion5Driver{ 71 AppPath: dconfig.FusionAppPath, 72 SSHConfig: config, 73 }, 74 }, 75 &Fusion5Driver{ 76 AppPath: dconfig.FusionAppPath, 77 SSHConfig: config, 78 }, 79 } 80 case "linux": 81 fallthrough 82 case "windows": 83 drivers = []Driver{ 84 &Workstation10Driver{ 85 Workstation9Driver: Workstation9Driver{ 86 SSHConfig: config, 87 }, 88 }, 89 &Workstation9Driver{ 90 SSHConfig: config, 91 }, 92 &Player6Driver{ 93 Player5Driver: Player5Driver{ 94 SSHConfig: config, 95 }, 96 }, 97 &Player5Driver{ 98 SSHConfig: config, 99 }, 100 } 101 default: 102 return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS) 103 } 104 105 errs := "" 106 for _, driver := range drivers { 107 err := driver.Verify() 108 if err == nil { 109 return driver, nil 110 } 111 errs += "* " + err.Error() + "\n" 112 } 113 114 return nil, fmt.Errorf( 115 "Unable to initialize any driver for this platform. The errors\n"+ 116 "from each driver are shown below. Please fix at least one driver\n"+ 117 "to continue:\n%s", errs) 118 } 119 120 func runAndLog(cmd *exec.Cmd) (string, string, error) { 121 var stdout, stderr bytes.Buffer 122 123 log.Printf("Executing: %s %v", cmd.Path, cmd.Args[1:]) 124 cmd.Stdout = &stdout 125 cmd.Stderr = &stderr 126 err := cmd.Run() 127 128 stdoutString := strings.TrimSpace(stdout.String()) 129 stderrString := strings.TrimSpace(stderr.String()) 130 131 if _, ok := err.(*exec.ExitError); ok { 132 message := stderrString 133 if message == "" { 134 message = stdoutString 135 } 136 137 err = fmt.Errorf("VMware error: %s", message) 138 } 139 140 log.Printf("stdout: %s", stdoutString) 141 log.Printf("stderr: %s", stderrString) 142 143 // Replace these for Windows, we only want to deal with Unix 144 // style line endings. 145 returnStdout := strings.Replace(stdout.String(), "\r\n", "\n", -1) 146 returnStderr := strings.Replace(stderr.String(), "\r\n", "\n", -1) 147 148 return returnStdout, returnStderr, err 149 } 150 151 func normalizeVersion(version string) (string, error) { 152 i, err := strconv.Atoi(version) 153 if err != nil { 154 return "", fmt.Errorf( 155 "VMware version '%s' is not numeric", version) 156 } 157 158 return fmt.Sprintf("%02d", i), nil 159 } 160 161 func compareVersions(versionFound string, versionWanted string, product string) error { 162 found, err := normalizeVersion(versionFound) 163 if err != nil { 164 return err 165 } 166 167 wanted, err := normalizeVersion(versionWanted) 168 if err != nil { 169 return err 170 } 171 172 if found < wanted { 173 return fmt.Errorf( 174 "VMware %s version %s, or greater, is required. Found version: %s", product, versionWanted, versionFound) 175 } 176 177 return nil 178 }