Added ability to create image from archive

This commit is contained in:
Diptanu Choudhury 2016-03-30 13:09:32 -07:00
parent 67cdf21c62
commit babbe86933

View file

@ -51,6 +51,7 @@ type DockerDriverAuth struct {
type DockerDriverConfig struct { type DockerDriverConfig struct {
ImageName string `mapstructure:"image"` // Container's Image Name ImageName string `mapstructure:"image"` // Container's Image Name
LoadImage string `mapstructure:"load"` // LoadImage is the path to the image archive
Command string `mapstructure:"command"` // The Command/Entrypoint to run when the container starts up Command string `mapstructure:"command"` // The Command/Entrypoint to run when the container starts up
Args []string `mapstructure:"args"` // The arguments to the Command/Entrypoint Args []string `mapstructure:"args"` // The arguments to the Command/Entrypoint
IpcMode string `mapstructure:"ipc_mode"` // The IPC mode of the container - host and none IpcMode string `mapstructure:"ipc_mode"` // The IPC mode of the container - host and none
@ -419,48 +420,15 @@ func (d *DockerDriver) Periodic() (bool, time.Duration) {
return true, 15 * time.Second return true, 15 * time.Second
} }
func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) { func (d *DockerDriver) createImage(driverConfig *DockerDriverConfig, client *docker.Client, taskDir string) error {
var driverConfig DockerDriverConfig
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
return nil, err
}
if err := driverConfig.Init(); err != nil {
return nil, err
}
image := driverConfig.ImageName image := driverConfig.ImageName
if err := driverConfig.Validate(); err != nil {
return nil, err
}
if task.Resources == nil {
return nil, fmt.Errorf("Resources are not specified")
}
if task.Resources.MemoryMB == 0 {
return nil, fmt.Errorf("Memory limit cannot be zero")
}
if task.Resources.CPU == 0 {
return nil, fmt.Errorf("CPU limit cannot be zero")
}
cleanupContainer := d.config.ReadBoolDefault("docker.cleanup.container", true)
cleanupImage := d.config.ReadBoolDefault("docker.cleanup.image", true)
// Initialize docker API client
client, err := d.dockerClient()
if err != nil {
return nil, fmt.Errorf("Failed to connect to docker daemon: %s", err)
}
repo, tag := docker.ParseRepositoryTag(image) repo, tag := docker.ParseRepositoryTag(image)
// Make sure tag is always explicitly set. We'll default to "latest" if it
// isn't, which is the expected behavior.
if tag == "" { if tag == "" {
tag = "latest" tag = "latest"
} }
var dockerImage *docker.Image var dockerImage *docker.Image
var err error
// We're going to check whether the image is already downloaded. If the tag // We're going to check whether the image is already downloaded. If the tag
// is "latest" we have to check for a new version every time so we don't // is "latest" we have to check for a new version every time so we don't
// bother to check and cache the id here. We'll download first, then cache. // bother to check and cache the id here. We'll download first, then cache.
@ -470,6 +438,18 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
// Download the image // Download the image
if dockerImage == nil { if dockerImage == nil {
if driverConfig.LoadImage != "" {
return d.loadImage(driverConfig, client, taskDir)
} else if driverConfig.ImageName != "" {
return d.pullImage(driverConfig, client, repo, tag)
} else {
return fmt.Errorf("either image name or load image has to be specified")
}
}
return err
}
func (d *DockerDriver) pullImage(driverConfig *DockerDriverConfig, client *docker.Client, repo string, tag string) error {
pullOptions := docker.PullImageOptions{ pullOptions := docker.PullImageOptions{
Repository: repo, Repository: repo,
Tag: tag, Tag: tag,
@ -490,7 +470,7 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
defer f.Close() defer f.Close()
var authConfigurations *docker.AuthConfigurations var authConfigurations *docker.AuthConfigurations
if authConfigurations, err = docker.NewAuthConfigurations(f); err != nil { if authConfigurations, err = docker.NewAuthConfigurations(f); err != nil {
return nil, fmt.Errorf("Failed to create docker auth object: %v", err) return fmt.Errorf("Failed to create docker auth object: %v", err)
} }
authConfigurationKey := "" authConfigurationKey := ""
@ -503,30 +483,70 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
authOptions = authConfiguration authOptions = authConfiguration
} }
} else { } else {
return nil, fmt.Errorf("Failed to open auth config file: %v, error: %v", authConfigFile, err) return fmt.Errorf("Failed to open auth config file: %v, error: %v", authConfigFile, err)
} }
} }
err = client.PullImage(pullOptions, authOptions) err := client.PullImage(pullOptions, authOptions)
if err != nil { if err != nil {
d.logger.Printf("[ERR] driver.docker: failed pulling container %s:%s: %s", repo, tag, err) d.logger.Printf("[ERR] driver.docker: failed pulling container %s:%s: %s", repo, tag, err)
return nil, d.recoverablePullError(err, image) return d.recoverablePullError(err, driverConfig.ImageName)
} }
d.logger.Printf("[DEBUG] driver.docker: docker pull %s:%s succeeded", repo, tag) d.logger.Printf("[DEBUG] driver.docker: docker pull %s:%s succeeded", repo, tag)
return nil
}
// Now that we have the image we can get the image id func (d *DockerDriver) loadImage(driverConfig *DockerDriverConfig, client *docker.Client, taskDir string) error {
dockerImage, err = client.InspectImage(image) archive := filepath.Join(taskDir, allocdir.TaskLocal, driverConfig.LoadImage)
d.logger.Printf("[DEBUG] driver.docker: loading image from: %v", archive)
f, err := os.Open(archive)
if err != nil { if err != nil {
d.logger.Printf("[ERR] driver.docker: failed getting image id for %s: %s", image, err) return fmt.Errorf("unable to open image archive: %v", err)
return nil, fmt.Errorf("Failed to determine image id for `%s`: %s", image, err)
} }
defer f.Close()
return client.LoadImage(docker.LoadImageOptions{InputStream: f})
}
func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
var driverConfig DockerDriverConfig
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
return nil, err
} }
if err := driverConfig.Init(); err != nil {
return nil, err
}
image := driverConfig.ImageName
if err := driverConfig.Validate(); err != nil {
return nil, err
}
cleanupContainer := d.config.ReadBoolDefault("docker.cleanup.container", true)
cleanupImage := d.config.ReadBoolDefault("docker.cleanup.image", true)
taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName] taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
if !ok { if !ok {
return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName) return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
} }
// Initialize docker API client
client, err := d.dockerClient()
if err != nil {
return nil, fmt.Errorf("Failed to connect to docker daemon: %s", err)
}
if err := d.createImage(&driverConfig, client, taskDir); err != nil {
return nil, fmt.Errorf("failed to pull image: %v", err)
}
// Now that we have the image we can get the image id
dockerImage, err := client.InspectImage(image)
if err != nil {
d.logger.Printf("[ERR] driver.docker: failed getting image id for %s: %s", image, err)
return nil, fmt.Errorf("Failed to determine image id for `%s`: %s", image, err)
}
d.logger.Printf("[DEBUG] driver.docker: identified image %s as %s", image, dockerImage.ID) d.logger.Printf("[DEBUG] driver.docker: identified image %s as %s", image, dockerImage.ID)
bin, err := discover.NomadExecutable() bin, err := discover.NomadExecutable()