Merge pull request #2618 from dgageot/2189-update-b2d-cache-in-precreatecheck

Update b2d cache in PreCreateCheck
This commit is contained in:
Nathan LeClaire 2015-12-18 16:51:56 -08:00
commit 204af9fe5e
6 changed files with 92 additions and 67 deletions

View File

@ -19,7 +19,7 @@ import (
type Driver struct { type Driver struct {
*drivers.BaseDriver *drivers.BaseDriver
boot2DockerURL string Boot2DockerURL string
boot2DockerLoc string boot2DockerLoc string
vSwitch string vSwitch string
diskImage string diskImage string
@ -73,7 +73,7 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
} }
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
d.boot2DockerURL = flags.String("hyperv-boot2docker-url") d.Boot2DockerURL = flags.String("hyperv-boot2docker-url")
d.boot2DockerLoc = flags.String("hyperv-boot2docker-location") d.boot2DockerLoc = flags.String("hyperv-boot2docker-location")
d.vSwitch = flags.String("hyperv-virtual-switch") d.vSwitch = flags.String("hyperv-virtual-switch")
d.DiskSize = flags.Int("hyperv-disk-size") d.DiskSize = flags.Int("hyperv-disk-size")
@ -139,16 +139,27 @@ func (d *Driver) GetState() (state.State, error) {
return state.None, nil return state.None, nil
} }
func (d *Driver) Create() error { // PreCreateCheck checks that the machine creation process can be started safely.
err := hypervAvailable() func (d *Driver) PreCreateCheck() error {
if err != nil { if err := hypervAvailable(); err != nil {
return err return err
} }
// Downloading boot2docker to cache should be done here to make sure
// that a download failure will not leave a machine half created.
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.UpdateISOCache(d.Boot2DockerURL); err != nil {
return err
}
return nil
}
func (d *Driver) Create() error {
d.setMachineNameIfNotSet() d.setMachineNameIfNotSet()
b2dutils := mcnutils.NewB2dUtils(d.StorePath) b2dutils := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.CopyIsoToMachineDir(d.boot2DockerURL, d.MachineName); err != nil { if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
return err return err
} }

View File

@ -216,6 +216,13 @@ func (d *Driver) PreCreateCheck() error {
log.Warn("This computer doesn't have VT-X/AMD-v enabled. Enabling it in the BIOS is mandatory.") log.Warn("This computer doesn't have VT-X/AMD-v enabled. Enabling it in the BIOS is mandatory.")
} }
// Downloading boot2docker to cache should be done here to make sure
// that a download failure will not leave a machine half created.
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.UpdateISOCache(d.Boot2DockerURL); err != nil {
return err
}
return nil return nil
} }

View File

@ -206,6 +206,18 @@ func (d *Driver) GetState() (state.State, error) {
return state.Stopped, nil return state.Stopped, nil
} }
// PreCreateCheck checks that the machine creation process can be started safely.
func (d *Driver) PreCreateCheck() error {
// Downloading boot2docker to cache should be done here to make sure
// that a download failure will not leave a machine half created.
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.UpdateISOCache(d.Boot2DockerURL); err != nil {
return err
}
return nil
}
func (d *Driver) Create() error { func (d *Driver) Create() error {
b2dutils := mcnutils.NewB2dUtils(d.StorePath) b2dutils := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil { if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
@ -214,7 +226,6 @@ func (d *Driver) Create() error {
// download cloud-init config drive // download cloud-init config drive
if d.ConfigDriveURL != "" { if d.ConfigDriveURL != "" {
log.Infof("Downloading %s from %s", isoConfigDrive, d.ConfigDriveURL)
if err := b2dutils.DownloadISO(d.ResolveStorePath("."), isoConfigDrive, d.ConfigDriveURL); err != nil { if err := b2dutils.DownloadISO(d.ResolveStorePath("."), isoConfigDrive, d.ConfigDriveURL); err != nil {
return err return err
} }

View File

@ -212,16 +212,28 @@ func (d *Driver) GetState() (state.State, error) {
return state.None, nil return state.None, nil
} }
// PreCreateCheck checks that the machine creation process can be started safely.
func (d *Driver) PreCreateCheck() error {
if err := d.checkVsphereConfig(); err != nil {
return err
}
// Downloading boot2docker to cache should be done here to make sure
// that a download failure will not leave a machine half created.
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.UpdateISOCache(d.Boot2DockerURL); err != nil {
return err
}
return nil
}
// Create has the following implementation: // Create has the following implementation:
// 1. check whether the docker directory contains the boot2docker ISO // 1. check whether the docker directory contains the boot2docker ISO
// 2. generate an SSH keypair and bundle it in a tar. // 2. generate an SSH keypair and bundle it in a tar.
// 3. create a virtual machine with the boot2docker ISO mounted; // 3. create a virtual machine with the boot2docker ISO mounted;
// 4. reconfigure the virtual machine network and disk size; // 4. reconfigure the virtual machine network and disk size;
func (d *Driver) Create() error { func (d *Driver) Create() error {
if err := d.checkVsphereConfig(); err != nil {
return err
}
b2dutils := mcnutils.NewB2dUtils(d.StorePath) b2dutils := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil { if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
return err return err

View File

@ -43,11 +43,9 @@ func getClient() *http.Client {
Dial: defaultTimeout, Dial: defaultTimeout,
} }
client := http.Client{ return &http.Client{
Transport: &transport, Transport: &transport,
} }
return &client
} }
func getRequest(apiURL string) (*http.Request, error) { func getRequest(apiURL string) (*http.Request, error) {
@ -204,11 +202,7 @@ func (*b2dReleaseGetter) download(dir, file, isoURL string) error {
return err return err
} }
if err := os.Rename(f.Name(), dest); err != nil { return os.Rename(f.Name(), dest)
return err
}
return nil
} }
// iso is an ISO volume. // iso is an ISO volume.
@ -305,6 +299,7 @@ func NewB2dUtils(storePath string) *B2dUtils {
// DownloadISO downloads boot2docker ISO image for the given tag and save it at dest. // DownloadISO downloads boot2docker ISO image for the given tag and save it at dest.
func (b *B2dUtils) DownloadISO(dir, file, isoURL string) error { func (b *B2dUtils) DownloadISO(dir, file, isoURL string) error {
log.Infof("Downloading %s from %s...", b.path(), isoURL)
return b.download(dir, file, isoURL) return b.download(dir, file, isoURL)
} }
@ -351,31 +346,51 @@ func (b *B2dUtils) DownloadLatestBoot2Docker(apiURL string) error {
} }
func (b *B2dUtils) DownloadISOFromURL(latestReleaseURL string) error { func (b *B2dUtils) DownloadISOFromURL(latestReleaseURL string) error {
log.Infof("Downloading %s to %s...", latestReleaseURL, b.path()) return b.DownloadISO(b.imgCachePath, b.filename(), latestReleaseURL)
if err := b.DownloadISO(b.imgCachePath, b.filename(), latestReleaseURL); err != nil { }
func (b *B2dUtils) UpdateISOCache(isoURL string) error {
// recreate the cache dir if it has been manually deleted
if _, err := os.Stat(b.imgCachePath); os.IsNotExist(err) {
log.Infof("Image cache directory does not exist, creating it at %s...", b.imgCachePath)
if err := os.Mkdir(b.imgCachePath, 0700); err != nil {
return err return err
} }
}
if isoURL != "" {
// Non-default B2D are not cached
return nil
}
exists := b.exists()
if !exists {
log.Info("No default Boot2Docker ISO found locally, downloading the latest release...")
return b.DownloadLatestBoot2Docker("")
}
latest := b.isLatest()
if !latest {
log.Info("Default Boot2Docker ISO is out-of-date, downloading the latest release...")
return b.DownloadLatestBoot2Docker("")
}
return nil return nil
} }
func (b *B2dUtils) CopyIsoToMachineDir(isoURL, machineName string) error { func (b *B2dUtils) CopyIsoToMachineDir(isoURL, machineName string) error {
if err := b.UpdateISOCache(isoURL); err != nil {
return err
}
// TODO: This is a bit off-color. // TODO: This is a bit off-color.
machineDir := filepath.Join(b.storePath, "machines", machineName) machineDir := filepath.Join(b.storePath, "machines", machineName)
machineIsoPath := filepath.Join(machineDir, b.filename()) machineIsoPath := filepath.Join(machineDir, b.filename())
// just in case the cache dir has been manually deleted,
// check for it and recreate it if it's gone
if _, err := os.Stat(b.imgCachePath); os.IsNotExist(err) {
log.Infof("Image cache does not exist, creating it at %s...", b.imgCachePath)
if err := os.Mkdir(b.imgCachePath, 0700); err != nil {
return err
}
}
// By default just copy the existing "cached" iso to the machine's directory... // By default just copy the existing "cached" iso to the machine's directory...
if isoURL == "" { if isoURL == "" {
return b.copyDefaultISOToMachine(machineIsoPath) log.Infof("Copying %s to %s...", b.path(), machineIsoPath)
return CopyFile(b.path(), machineIsoPath)
} }
// if ISO is specified, check if it matches a github releases url or fallback to a direct download // if ISO is specified, check if it matches a github releases url or fallback to a direct download
@ -384,41 +399,9 @@ func (b *B2dUtils) CopyIsoToMachineDir(isoURL, machineName string) error {
return err return err
} }
log.Infof("Downloading %s from %s...", b.filename(), downloadURL)
return b.DownloadISO(machineDir, b.filename(), downloadURL) return b.DownloadISO(machineDir, b.filename(), downloadURL)
} }
func (b *B2dUtils) copyDefaultISOToMachine(machineIsoPath string) error {
// just in case the cache dir has been manually deleted,
// check for it and recreate it if it's gone
if _, err := os.Stat(b.imgCachePath); os.IsNotExist(err) {
log.Infof("Image cache directory does not exist, creating it at %s...", b.imgCachePath)
if err := os.Mkdir(b.imgCachePath, 0700); err != nil {
return err
}
}
exists := b.exists()
latest := b.isLatest()
if exists && latest {
log.Infof("Latest Boot2Docker ISO found locally, copying it to %s...", machineIsoPath)
return CopyFile(b.path(), machineIsoPath)
}
if !exists {
log.Info("No default Boot2Docker ISO found locally, downloading the latest release...")
} else if !latest {
log.Info("Default Boot2Docker ISO is out-of-date, downloading the latest release...")
}
if err := b.DownloadLatestBoot2Docker(""); err != nil {
return err
}
log.Infof("Copying %s to %s...", b.path(), machineIsoPath)
return CopyFile(b.path(), machineIsoPath)
}
// isLatest checks the latest release tag and // isLatest checks the latest release tag and
// reports whether the local ISO cache is the latest version. // reports whether the local ISO cache is the latest version.
// //

View File

@ -261,13 +261,14 @@ func TestCopyDefaultISOToMachine(t *testing.T) {
imgCachePath: imgCachePath, imgCachePath: imgCachePath,
} }
dir := filepath.Join(storePath, tt.machineName) dir := filepath.Join(storePath, "machines", tt.machineName)
err = os.MkdirAll(dir, 0700) err = os.MkdirAll(dir, 0700)
assert.NoError(t, err, "machine: %s", tt.machineName) assert.NoError(t, err, "machine: %s", tt.machineName)
err = b.CopyIsoToMachineDir("", tt.machineName)
assert.NoError(t, err)
dest := filepath.Join(dir, b.filename()) dest := filepath.Join(dir, b.filename())
err = b.copyDefaultISOToMachine(dest)
_, pathErr := os.Stat(dest) _, pathErr := os.Stat(dest)
assert.NoError(t, err, "machine: %s", tt.machineName) assert.NoError(t, err, "machine: %s", tt.machineName)