@@ -3,6 +3,8 @@ package main
33import (
44 "encoding/json"
55 "fmt"
6+ "io/ioutil"
7+ "net/http"
68 "os"
79 "os/exec"
810 "path/filepath"
@@ -11,10 +13,9 @@ import (
1113 "strings"
1214 "time"
1315
16+ "github.com/boot2docker/boot2docker-cli/driver"
1417 _ "github.com/boot2docker/boot2docker-cli/dummy"
1518 _ "github.com/boot2docker/boot2docker-cli/virtualbox"
16-
17- "github.com/boot2docker/boot2docker-cli/driver"
1819)
1920
2021// Initialize the boot2docker VM from scratch.
@@ -277,6 +278,19 @@ func cmdPoweroff() error {
277278
278279// Upgrade the boot2docker ISO - preserving server state
279280func cmdUpgrade () error {
281+ if runtime .GOOS == "darwin" || runtime .GOOS == "linux" {
282+ if B2D .Clobber {
283+ err := upgradeDockerClientBinary ()
284+ if err != nil {
285+ return err
286+ }
287+ } else {
288+ fmt .Println ("Skipping client binary download, use --clobber=true to enable..." )
289+ }
290+ }
291+ if err := upgradeBoot2DockerBinary (); err != nil {
292+ return fmt .Errorf ("Error upgrading boot2docker binary: %s" , err )
293+ }
280294 m , err := driver .GetMachine (& B2D )
281295 if err == nil {
282296 if m .GetState () == driver .Running || m .GetState () == driver .Saved || m .GetState () == driver .Paused {
@@ -292,6 +306,133 @@ func cmdUpgrade() error {
292306 return cmdDownload ()
293307}
294308
309+ func upgradeBoot2DockerBinary () error {
310+ var (
311+ goos , arch , ext string
312+ )
313+ latestVersion , err := getLatestReleaseName ("https://api.github.com/repos/boot2docker/boot2docker-cli/releases" )
314+ if err != nil {
315+ return fmt .Errorf ("Error attempting to get the latest boot2docker-cli release: %s" , err )
316+ }
317+ baseUrl := "https://github.com/boot2docker/boot2docker-cli/releases/download"
318+
319+ ext = ""
320+
321+ switch runtime .GOARCH {
322+ case "amd64" :
323+ arch = "amd64"
324+ default :
325+ return fmt .Errorf ("Architecture not supported" )
326+ }
327+
328+ switch runtime .GOOS {
329+ case "darwin" , "linux" :
330+ goos = runtime .GOOS
331+ case "windows" :
332+ goos = "windows"
333+ arch = "amd64"
334+ ext = ".exe"
335+ default :
336+ return fmt .Errorf ("Operating system not supported" )
337+ }
338+ binaryUrl := fmt .Sprintf ("%s/%s/boot2docker-%s-%s-%s%s" , baseUrl , latestVersion , latestVersion , goos , arch , ext )
339+ currentBoot2DockerVersion := Version
340+ if err := attemptUpgrade (binaryUrl , "boot2docker" , latestVersion , currentBoot2DockerVersion ); err != nil {
341+ return fmt .Errorf ("Error attempting upgrade: %s" , err )
342+ }
343+ return nil
344+ }
345+
346+ func upgradeDockerClientBinary () error {
347+ var (
348+ clientOs , clientArch string
349+ )
350+ resp , err := http .Get ("https://get.docker.com/latest" )
351+ if err != nil {
352+ return fmt .Errorf ("Error checking the latest version of Docker: %s" , err )
353+ }
354+ defer resp .Body .Close ()
355+ latestVersionBytes , err := ioutil .ReadAll (resp .Body )
356+ if err != nil {
357+ return fmt .Errorf ("Error reading response body on latest version of Docker call: %s" , err )
358+ }
359+ latestVersion := strings .TrimSpace (string (latestVersionBytes ))
360+ localClientVersion , err := getLocalClientVersion ()
361+ if err != nil {
362+ return fmt .Errorf ("Error getting local Docker client version: %s" , err )
363+ }
364+ switch runtime .GOARCH {
365+ case "amd64" :
366+ clientArch = "x86_64"
367+ default :
368+ return fmt .Errorf ("Architecture not supported" )
369+ }
370+
371+ switch runtime .GOOS {
372+ case "darwin" :
373+ clientOs = "Darwin"
374+ case "linux" :
375+ clientOs = "Linux"
376+ default :
377+ return fmt .Errorf ("Operating system not supported" )
378+ }
379+ binaryUrl := fmt .Sprintf ("https://get.docker.com/builds/%s/%s/docker-latest" , clientOs , clientArch )
380+ if err := attemptUpgrade (binaryUrl , "docker" , latestVersion , localClientVersion ); err != nil {
381+ return fmt .Errorf ("Error attempting upgrade: %s" , err )
382+ }
383+ return nil
384+ }
385+
386+ func attemptUpgrade (binaryUrl , binaryName , latestVersion , localVersion string ) error {
387+ if (latestVersion != localVersion && ! strings .Contains (latestVersion , "rc" )) || B2D .ForceUpgradeDownload {
388+ if err := backupAndDownload (binaryUrl , binaryName , localVersion ); err != nil {
389+ return fmt .Errorf ("Error attempting backup and download of Docker client binary: %s" , err )
390+ }
391+ } else {
392+ fmt .Printf ("%s is up to date (%s), skipping upgrade...\n " , binaryName , localVersion )
393+ }
394+ return nil
395+ }
396+
397+ func backupAndDownload (binaryUrl , binaryName , localVersion string ) error {
398+ binaryPath , err := exec .LookPath (binaryName )
399+ if err != nil {
400+ return fmt .Errorf ("Error attempting to locate local binary: %s" , err )
401+ }
402+ path := strings .TrimSpace (string (binaryPath ))
403+
404+ fmt .Println ("Backing up existing" , binaryName , "binary..." )
405+ if err := backupBinary (binaryName , localVersion , path ); err != nil {
406+ return fmt .Errorf ("Error backing up docker client: %s" , err )
407+ }
408+
409+ fmt .Println ("Downloading new" , binaryName , "client binary..." )
410+ if err := download (path , binaryUrl ); err != nil {
411+ return fmt .Errorf ("Error attempting to download new client binary: %s" , err )
412+ }
413+ if err := os .Chmod (path , 0755 ); err != nil {
414+ return err
415+ }
416+ fmt .Printf ("Success: downloaded %s\n \t to %s\n \t The old version is backed up to ~/.boot2docker.\n " , binaryUrl , path )
417+ return nil
418+ }
419+
420+ func backupBinary (binaryName , localVersion , path string ) error {
421+ dir , err := cfgDir (".boot2docker" )
422+ if err != nil {
423+ return fmt .Errorf ("Error getting boot2docker config dir: %s" , err )
424+ }
425+ buf , err := ioutil .ReadFile (path )
426+ if err != nil {
427+ return fmt .Errorf ("Error opening binary for reading at %s: %s" , path , err )
428+ }
429+ backupName := fmt .Sprintf ("%s-%s" , binaryName , localVersion )
430+ if err := ioutil .WriteFile (filepath .Join (dir , backupName ), buf , 0755 ); err != nil {
431+ return fmt .Errorf ("Error creating backup file: %s" , err )
432+ }
433+ return nil
434+ }
435+
295436// Gracefully stop and then start the VM.
296437func cmdRestart () error {
297438 m , err := driver .GetMachine (& B2D )
0 commit comments