Add Driver.Prestart method
The Driver.Prestart method currently does very little but lays the foundation for where lifecycle plugins can interleave execution _after_ task environment setup but _before_ the task starts. Currently Prestart does two things: * Any driver specific task environment building * Download Docker images This change also attaches a TaskEvent emitter to Drivers, so they can emit events during task initialization.
This commit is contained in:
parent
1c4195b985
commit
770ed703d0
44
api/tasks.go
44
api/tasks.go
|
@ -252,30 +252,32 @@ const (
|
||||||
TaskSiblingFailed = "Sibling task failed"
|
TaskSiblingFailed = "Sibling task failed"
|
||||||
TaskSignaling = "Signaling"
|
TaskSignaling = "Signaling"
|
||||||
TaskRestartSignal = "Restart Signaled"
|
TaskRestartSignal = "Restart Signaled"
|
||||||
|
TaskInitializing = "Initializing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TaskEvent is an event that effects the state of a task and contains meta-data
|
// TaskEvent is an event that effects the state of a task and contains meta-data
|
||||||
// appropriate to the events type.
|
// appropriate to the events type.
|
||||||
type TaskEvent struct {
|
type TaskEvent struct {
|
||||||
Type string
|
Type string
|
||||||
Time int64
|
Time int64
|
||||||
FailsTask bool
|
FailsTask bool
|
||||||
RestartReason string
|
RestartReason string
|
||||||
SetupError string
|
SetupError string
|
||||||
DriverError string
|
DriverError string
|
||||||
ExitCode int
|
ExitCode int
|
||||||
Signal int
|
Signal int
|
||||||
Message string
|
Message string
|
||||||
KillReason string
|
KillReason string
|
||||||
KillTimeout time.Duration
|
KillTimeout time.Duration
|
||||||
KillError string
|
KillError string
|
||||||
StartDelay int64
|
StartDelay int64
|
||||||
DownloadError string
|
DownloadError string
|
||||||
ValidationError string
|
ValidationError string
|
||||||
DiskLimit int64
|
DiskLimit int64
|
||||||
DiskSize int64
|
DiskSize int64
|
||||||
FailedSibling string
|
FailedSibling string
|
||||||
VaultError string
|
VaultError string
|
||||||
TaskSignalReason string
|
TaskSignalReason string
|
||||||
TaskSignal string
|
TaskSignal string
|
||||||
|
InitializationMessage string
|
||||||
}
|
}
|
||||||
|
|
|
@ -792,7 +792,7 @@ func (c *Client) setupDrivers() error {
|
||||||
|
|
||||||
var avail []string
|
var avail []string
|
||||||
var skipped []string
|
var skipped []string
|
||||||
driverCtx := driver.NewDriverContext("", c.config, c.config.Node, c.logger, nil)
|
driverCtx := driver.NewDriverContext("", c.config, c.config.Node, c.logger, nil, nil)
|
||||||
for name := range driver.BuiltinDrivers {
|
for name := range driver.BuiltinDrivers {
|
||||||
// Skip fingerprinting drivers that are not in the whitelist if it is
|
// Skip fingerprinting drivers that are not in the whitelist if it is
|
||||||
// enabled.
|
// enabled.
|
||||||
|
|
|
@ -91,6 +91,10 @@ const (
|
||||||
|
|
||||||
type DockerDriver struct {
|
type DockerDriver struct {
|
||||||
DriverContext
|
DriverContext
|
||||||
|
|
||||||
|
imageID string
|
||||||
|
waitClient *docker.Client
|
||||||
|
driverConfig *DockerDriverConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type DockerDriverAuth struct {
|
type DockerDriverAuth struct {
|
||||||
|
@ -339,31 +343,29 @@ func (d *DockerDriver) Abilities() DriverAbilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (d *DockerDriver) Prestart(ctx *ExecContext, task *structs.Task) error {
|
||||||
// Set environment variables.
|
// Set environment variables.
|
||||||
d.taskEnv.SetAllocDir(allocdir.SharedAllocContainerPath).
|
d.taskEnv.SetAllocDir(allocdir.SharedAllocContainerPath).
|
||||||
SetTaskLocalDir(allocdir.TaskLocalContainerPath).SetSecretsDir(allocdir.TaskSecretsContainerPath).Build()
|
SetTaskLocalDir(allocdir.TaskLocalContainerPath).SetSecretsDir(allocdir.TaskSecretsContainerPath).Build()
|
||||||
|
|
||||||
driverConfig, err := NewDockerDriverConfig(task, d.taskEnv)
|
driverConfig, err := NewDockerDriverConfig(task, d.taskEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
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 fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize docker API clients
|
// Initialize docker API clients
|
||||||
client, waitClient, err := d.dockerClients()
|
client, waitClient, err := d.dockerClients()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to connect to docker daemon: %s", err)
|
return fmt.Errorf("Failed to connect to docker daemon: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.createImage(driverConfig, client, taskDir); err != nil {
|
if err := d.createImage(driverConfig, client, taskDir); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
image := driverConfig.ImageName
|
image := driverConfig.ImageName
|
||||||
|
@ -371,14 +373,27 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
|
||||||
dockerImage, err := client.InspectImage(image)
|
dockerImage, err := client.InspectImage(image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Printf("[ERR] driver.docker: failed getting image id for %s: %s", image, err)
|
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)
|
return 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)
|
||||||
|
|
||||||
|
// Set state needed by Start()
|
||||||
|
d.imageID = dockerImage.ID
|
||||||
|
d.waitClient = waitClient
|
||||||
|
d.driverConfig = driverConfig
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
bin, err := discover.NomadExecutable()
|
bin, err := discover.NomadExecutable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to find the nomad binary: %v", err)
|
return nil, fmt.Errorf("unable to find the nomad binary: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
|
||||||
|
}
|
||||||
pluginLogFile := filepath.Join(taskDir, fmt.Sprintf("%s-executor.out", task.Name))
|
pluginLogFile := filepath.Join(taskDir, fmt.Sprintf("%s-executor.out", task.Name))
|
||||||
pluginConfig := &plugin.ClientConfig{
|
pluginConfig := &plugin.ClientConfig{
|
||||||
Cmd: exec.Command(bin, "executor", pluginLogFile),
|
Cmd: exec.Command(bin, "executor", pluginLogFile),
|
||||||
|
@ -404,9 +419,9 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
|
||||||
|
|
||||||
// Only launch syslog server if we're going to use it!
|
// Only launch syslog server if we're going to use it!
|
||||||
syslogAddr := ""
|
syslogAddr := ""
|
||||||
if runtime.GOOS == "darwin" && len(driverConfig.Logging) == 0 {
|
if runtime.GOOS == "darwin" && len(d.driverConfig.Logging) == 0 {
|
||||||
d.logger.Printf("[DEBUG] driver.docker: disabling syslog driver as Docker for Mac workaround")
|
d.logger.Printf("[DEBUG] driver.docker: disabling syslog driver as Docker for Mac workaround")
|
||||||
} else if len(driverConfig.Logging) == 0 || driverConfig.Logging[0].Type == "syslog" {
|
} else if len(d.driverConfig.Logging) == 0 || d.driverConfig.Logging[0].Type == "syslog" {
|
||||||
ss, err := exec.LaunchSyslogServer()
|
ss, err := exec.LaunchSyslogServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pluginClient.Kill()
|
pluginClient.Kill()
|
||||||
|
@ -415,11 +430,11 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
|
||||||
syslogAddr = ss.Addr
|
syslogAddr = ss.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := d.createContainerConfig(ctx, task, driverConfig, syslogAddr)
|
config, err := d.createContainerConfig(ctx, task, d.driverConfig, syslogAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Printf("[ERR] driver.docker: failed to create container configuration for image %s: %s", image, err)
|
d.logger.Printf("[ERR] driver.docker: failed to create container configuration for image %s: %s", d.imageID, err)
|
||||||
pluginClient.Kill()
|
pluginClient.Kill()
|
||||||
return nil, fmt.Errorf("Failed to create container configuration for image %s: %s", image, err)
|
return nil, fmt.Errorf("Failed to create container configuration for image %s: %s", d.imageID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
container, rerr := d.createContainer(config)
|
container, rerr := d.createContainer(config)
|
||||||
|
@ -432,17 +447,17 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
|
||||||
|
|
||||||
d.logger.Printf("[INFO] driver.docker: created container %s", container.ID)
|
d.logger.Printf("[INFO] driver.docker: created container %s", container.ID)
|
||||||
|
|
||||||
|
cleanupImage := d.config.ReadBoolDefault("docker.cleanup.image", true)
|
||||||
|
|
||||||
// We don't need to start the container if the container is already running
|
// We don't need to start the container if the container is already running
|
||||||
// since we don't create containers which are already present on the host
|
// since we don't create containers which are already present on the host
|
||||||
// and are running
|
// and are running
|
||||||
if !container.State.Running {
|
if !container.State.Running {
|
||||||
// Start the container
|
// Start the container
|
||||||
err := d.startContainer(container)
|
if err := client.StartContainer(container.ID, container.HostConfig); err != nil {
|
||||||
if err != nil {
|
|
||||||
d.logger.Printf("[ERR] driver.docker: failed to start container %s: %s", container.ID, err)
|
d.logger.Printf("[ERR] driver.docker: failed to start container %s: %s", container.ID, err)
|
||||||
pluginClient.Kill()
|
pluginClient.Kill()
|
||||||
err.Err = fmt.Sprintf("Failed to start container %s: %s", container.ID, err)
|
return nil, fmt.Errorf("Failed to start container %s: %s", container.ID, err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
d.logger.Printf("[INFO] driver.docker: started container %s", container.ID)
|
d.logger.Printf("[INFO] driver.docker: started container %s", container.ID)
|
||||||
} else {
|
} else {
|
||||||
|
@ -454,12 +469,12 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
|
||||||
maxKill := d.DriverContext.config.MaxKillTimeout
|
maxKill := d.DriverContext.config.MaxKillTimeout
|
||||||
h := &DockerHandle{
|
h := &DockerHandle{
|
||||||
client: client,
|
client: client,
|
||||||
waitClient: waitClient,
|
waitClient: d.waitClient,
|
||||||
executor: exec,
|
executor: exec,
|
||||||
pluginClient: pluginClient,
|
pluginClient: pluginClient,
|
||||||
cleanupImage: cleanupImage,
|
cleanupImage: cleanupImage,
|
||||||
logger: d.logger,
|
logger: d.logger,
|
||||||
imageID: dockerImage.ID,
|
imageID: d.imageID,
|
||||||
containerID: container.ID,
|
containerID: container.ID,
|
||||||
version: d.config.Version,
|
version: d.config.Version,
|
||||||
killTimeout: GetKillTimeout(task.KillTimeout, maxKill),
|
killTimeout: GetKillTimeout(task.KillTimeout, maxKill),
|
||||||
|
|
|
@ -101,6 +101,10 @@ func dockerSetup(t *testing.T, task *structs.Task) (*docker.Client, DriverHandle
|
||||||
driver := NewDockerDriver(driverCtx)
|
driver := NewDockerDriver(driverCtx)
|
||||||
copyImage(execCtx, task, "busybox.tar", t)
|
copyImage(execCtx, task, "busybox.tar", t)
|
||||||
|
|
||||||
|
if err := driver.Prestart(execCtx, task); err != nil {
|
||||||
|
execCtx.AllocDir.Destroy()
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := driver.Start(execCtx, task)
|
handle, err := driver.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
execCtx.AllocDir.Destroy()
|
execCtx.AllocDir.Destroy()
|
||||||
|
@ -167,6 +171,9 @@ func TestDockerDriver_StartOpen_Wait(t *testing.T) {
|
||||||
d := NewDockerDriver(driverCtx)
|
d := NewDockerDriver(driverCtx)
|
||||||
copyImage(execCtx, task, "busybox.tar", t)
|
copyImage(execCtx, task, "busybox.tar", t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -256,6 +263,9 @@ func TestDockerDriver_Start_LoadImage(t *testing.T) {
|
||||||
// Copy the image into the task's directory
|
// Copy the image into the task's directory
|
||||||
copyImage(execCtx, task, "busybox.tar", t)
|
copyImage(execCtx, task, "busybox.tar", t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -316,9 +326,9 @@ func TestDockerDriver_Start_BadPull_Recoverable(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewDockerDriver(driverCtx)
|
d := NewDockerDriver(driverCtx)
|
||||||
|
|
||||||
_, err := d.Start(execCtx, task)
|
err := d.Prestart(execCtx, task)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("want err: %v", err)
|
t.Fatalf("want error in prestart: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rerr, ok := err.(*structs.RecoverableError); !ok {
|
if rerr, ok := err.(*structs.RecoverableError); !ok {
|
||||||
|
@ -366,6 +376,9 @@ func TestDockerDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
d := NewDockerDriver(driverCtx)
|
d := NewDockerDriver(driverCtx)
|
||||||
copyImage(execCtx, task, "busybox.tar", t)
|
copyImage(execCtx, task, "busybox.tar", t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -456,6 +469,9 @@ func TestDockerDriver_StartN(t *testing.T) {
|
||||||
d := NewDockerDriver(driverCtx)
|
d := NewDockerDriver(driverCtx)
|
||||||
copyImage(execCtx, task, "busybox.tar", t)
|
copyImage(execCtx, task, "busybox.tar", t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart #%d: %v", idx+1, err)
|
||||||
|
}
|
||||||
handles[idx], err = d.Start(execCtx, task)
|
handles[idx], err = d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed starting task #%d: %s", idx+1, err)
|
t.Errorf("Failed starting task #%d: %s", idx+1, err)
|
||||||
|
@ -513,6 +529,9 @@ func TestDockerDriver_StartNVersions(t *testing.T) {
|
||||||
copyImage(execCtx, task, "busybox_musl.tar", t)
|
copyImage(execCtx, task, "busybox_musl.tar", t)
|
||||||
copyImage(execCtx, task, "busybox_glibc.tar", t)
|
copyImage(execCtx, task, "busybox_glibc.tar", t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart #%d: %v", idx+1, err)
|
||||||
|
}
|
||||||
handles[idx], err = d.Start(execCtx, task)
|
handles[idx], err = d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed starting task #%d: %s", idx+1, err)
|
t.Errorf("Failed starting task #%d: %s", idx+1, err)
|
||||||
|
@ -804,6 +823,10 @@ func TestDockerDriver_User(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
copyImage(execCtx, task, "busybox.tar", t)
|
copyImage(execCtx, task, "busybox.tar", t)
|
||||||
|
|
||||||
|
if err := driver.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// It should fail because the user "alice" does not exist on the given
|
// It should fail because the user "alice" does not exist on the given
|
||||||
// image.
|
// image.
|
||||||
handle, err := driver.Start(execCtx, task)
|
handle, err := driver.Start(execCtx, task)
|
||||||
|
@ -953,6 +976,9 @@ done
|
||||||
fmt.Errorf("Failed to write data")
|
fmt.Errorf("Failed to write data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -1035,7 +1061,11 @@ func setupDockerVolumes(t *testing.T, cfg *config.Config, hostpath string) (*str
|
||||||
t.Fatalf("Failed to get task env: %v", err)
|
t.Fatalf("Failed to get task env: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
driverCtx := NewDriverContext(task.Name, cfg, cfg.Node, testLogger(), taskEnv)
|
logger := testLogger()
|
||||||
|
emitter := func(m string, args ...interface{}) {
|
||||||
|
logger.Printf("[EVENT] "+m, args...)
|
||||||
|
}
|
||||||
|
driverCtx := NewDriverContext(task.Name, cfg, cfg.Node, testLogger(), taskEnv, emitter)
|
||||||
driver := NewDockerDriver(driverCtx)
|
driver := NewDockerDriver(driverCtx)
|
||||||
copyImage(execCtx, task, "busybox.tar", t)
|
copyImage(execCtx, task, "busybox.tar", t)
|
||||||
|
|
||||||
|
@ -1058,6 +1088,9 @@ func TestDockerDriver_VolumesDisabled(t *testing.T) {
|
||||||
task, driver, execCtx, _, cleanup := setupDockerVolumes(t, cfg, tmpvol)
|
task, driver, execCtx, _, cleanup := setupDockerVolumes(t, cfg, tmpvol)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
|
if err := driver.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
if _, err := driver.Start(execCtx, task); err == nil {
|
if _, err := driver.Start(execCtx, task); err == nil {
|
||||||
t.Fatalf("Started driver successfully when volumes should have been disabled.")
|
t.Fatalf("Started driver successfully when volumes should have been disabled.")
|
||||||
}
|
}
|
||||||
|
@ -1068,6 +1101,9 @@ func TestDockerDriver_VolumesDisabled(t *testing.T) {
|
||||||
task, driver, execCtx, fn, cleanup := setupDockerVolumes(t, cfg, ".")
|
task, driver, execCtx, fn, cleanup := setupDockerVolumes(t, cfg, ".")
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
|
if err := driver.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := driver.Start(execCtx, task)
|
handle, err := driver.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -1106,6 +1142,9 @@ func TestDockerDriver_VolumesEnabled(t *testing.T) {
|
||||||
task, driver, execCtx, hostpath, cleanup := setupDockerVolumes(t, cfg, tmpvol)
|
task, driver, execCtx, hostpath, cleanup := setupDockerVolumes(t, cfg, tmpvol)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
|
if err := driver.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := driver.Start(execCtx, task)
|
handle, err := driver.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to start docker driver: %v", err)
|
t.Fatalf("Failed to start docker driver: %v", err)
|
||||||
|
|
|
@ -51,6 +51,10 @@ type Driver interface {
|
||||||
// Drivers must support the fingerprint interface for detection
|
// Drivers must support the fingerprint interface for detection
|
||||||
fingerprint.Fingerprint
|
fingerprint.Fingerprint
|
||||||
|
|
||||||
|
// Prestart prepares the task environment and performs expensive
|
||||||
|
// intialization steps like downloading images.
|
||||||
|
Prestart(*ExecContext, *structs.Task) error
|
||||||
|
|
||||||
// Start is used to being task execution
|
// Start is used to being task execution
|
||||||
Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error)
|
Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error)
|
||||||
|
|
||||||
|
@ -70,6 +74,9 @@ type DriverAbilities struct {
|
||||||
SendSignals bool
|
SendSignals bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogEventFn is a callback which allows Drivers to emit task events.
|
||||||
|
type LogEventFn func(message string, args ...interface{})
|
||||||
|
|
||||||
// DriverContext is a means to inject dependencies such as loggers, configs, and
|
// DriverContext is a means to inject dependencies such as loggers, configs, and
|
||||||
// node attributes into a Driver without having to change the Driver interface
|
// node attributes into a Driver without having to change the Driver interface
|
||||||
// each time we do it. Used in conjection with Factory, above.
|
// each time we do it. Used in conjection with Factory, above.
|
||||||
|
@ -79,18 +86,14 @@ type DriverContext struct {
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
node *structs.Node
|
node *structs.Node
|
||||||
taskEnv *env.TaskEnvironment
|
taskEnv *env.TaskEnvironment
|
||||||
|
|
||||||
|
emitEvent LogEventFn
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEmptyDriverContext returns a DriverContext with all fields set to their
|
// NewEmptyDriverContext returns a DriverContext with all fields set to their
|
||||||
// zero value.
|
// zero value.
|
||||||
func NewEmptyDriverContext() *DriverContext {
|
func NewEmptyDriverContext() *DriverContext {
|
||||||
return &DriverContext{
|
return &DriverContext{}
|
||||||
taskName: "",
|
|
||||||
config: nil,
|
|
||||||
node: nil,
|
|
||||||
logger: nil,
|
|
||||||
taskEnv: nil,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDriverContext initializes a new DriverContext with the specified fields.
|
// NewDriverContext initializes a new DriverContext with the specified fields.
|
||||||
|
@ -98,13 +101,14 @@ func NewEmptyDriverContext() *DriverContext {
|
||||||
// private to the driver. If we want to change this later we can gorename all of
|
// private to the driver. If we want to change this later we can gorename all of
|
||||||
// the fields in DriverContext.
|
// the fields in DriverContext.
|
||||||
func NewDriverContext(taskName string, config *config.Config, node *structs.Node,
|
func NewDriverContext(taskName string, config *config.Config, node *structs.Node,
|
||||||
logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext {
|
logger *log.Logger, taskEnv *env.TaskEnvironment, eventEmitter LogEventFn) *DriverContext {
|
||||||
return &DriverContext{
|
return &DriverContext{
|
||||||
taskName: taskName,
|
taskName: taskName,
|
||||||
config: config,
|
config: config,
|
||||||
node: node,
|
node: node,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
taskEnv: taskEnv,
|
taskEnv: taskEnv,
|
||||||
|
emitEvent: eventEmitter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,11 @@ func testDriverContexts(task *structs.Task) (*DriverContext, *ExecContext) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
driverCtx := NewDriverContext(task.Name, cfg, cfg.Node, testLogger(), taskEnv)
|
logger := testLogger()
|
||||||
|
emitter := func(m string, args ...interface{}) {
|
||||||
|
logger.Printf("[EVENT] "+m, args...)
|
||||||
|
}
|
||||||
|
driverCtx := NewDriverContext(task.Name, cfg, cfg.Node, logger, taskEnv, emitter)
|
||||||
return driverCtx, execCtx
|
return driverCtx, execCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,13 @@ func (d *ExecDriver) Periodic() (bool, time.Duration) {
|
||||||
return true, 15 * time.Second
|
return true, 15 * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *ExecDriver) Prestart(execctx *ExecContext, task *structs.Task) error {
|
||||||
|
// Set the host environment variables.
|
||||||
|
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
|
||||||
|
d.taskEnv.AppendHostEnvvars(filter)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
var driverConfig ExecDriverConfig
|
var driverConfig ExecDriverConfig
|
||||||
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
|
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
|
||||||
|
@ -104,10 +111,6 @@ func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the host environment variables.
|
|
||||||
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
|
|
||||||
d.taskEnv.AppendHostEnvvars(filter)
|
|
||||||
|
|
||||||
// Get the task directory for storing the executor logs.
|
// Get the task directory for storing the executor logs.
|
||||||
taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
|
taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -65,6 +65,9 @@ func TestExecDriver_StartOpen_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewExecDriver(driverCtx)
|
d := NewExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -105,6 +108,9 @@ func TestExecDriver_KillUserPid_OnPluginReconnectFailure(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewExecDriver(driverCtx)
|
d := NewExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -165,6 +171,9 @@ func TestExecDriver_Start_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewExecDriver(driverCtx)
|
d := NewExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -215,6 +224,9 @@ func TestExecDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewExecDriver(driverCtx)
|
d := NewExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -265,6 +277,9 @@ func TestExecDriver_Start_Kill_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewExecDriver(driverCtx)
|
d := NewExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -327,6 +342,9 @@ done
|
||||||
fmt.Errorf("Failed to write data")
|
fmt.Errorf("Failed to write data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -388,6 +406,9 @@ func TestExecDriverUser(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewExecDriver(driverCtx)
|
d := NewExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
handle.Kill()
|
handle.Kill()
|
||||||
|
|
|
@ -163,16 +163,19 @@ func (d *JavaDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool,
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *JavaDriver) Prestart(ctx *ExecContext, task *structs.Task) error {
|
||||||
|
// Set the host environment variables.
|
||||||
|
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
|
||||||
|
d.taskEnv.AppendHostEnvvars(filter)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *JavaDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (d *JavaDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
var driverConfig JavaDriverConfig
|
var driverConfig JavaDriverConfig
|
||||||
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
|
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the host environment variables.
|
|
||||||
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
|
|
||||||
d.taskEnv.AppendHostEnvvars(filter)
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -92,6 +92,9 @@ func TestJavaDriver_StartOpen_Wait(t *testing.T) {
|
||||||
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
||||||
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -142,6 +145,9 @@ func TestJavaDriver_Start_Wait(t *testing.T) {
|
||||||
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
||||||
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -204,6 +210,9 @@ func TestJavaDriver_Start_Kill_Wait(t *testing.T) {
|
||||||
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
||||||
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -262,6 +271,9 @@ func TestJavaDriver_Signal(t *testing.T) {
|
||||||
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
dst, _ := execCtx.AllocDir.TaskDirs[task.Name]
|
||||||
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -317,6 +329,9 @@ func TestJavaDriverUser(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewJavaDriver(driverCtx)
|
d := NewJavaDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
handle.Kill()
|
handle.Kill()
|
||||||
|
|
|
@ -168,6 +168,10 @@ func (d *LxcDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, e
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *LxcDriver) Prestart(ctx *ExecContext, task *structs.Task) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Start starts the LXC Driver
|
// Start starts the LXC Driver
|
||||||
func (d *LxcDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (d *LxcDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
var driverConfig LxcDriverConfig
|
var driverConfig LxcDriverConfig
|
||||||
|
|
|
@ -69,6 +69,9 @@ func TestLxcDriver_Start_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewLxcDriver(driverCtx)
|
d := NewLxcDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -141,6 +144,9 @@ func TestLxcDriver_Open_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewLxcDriver(driverCtx)
|
d := NewLxcDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
|
|
@ -75,6 +75,10 @@ func (d *MockDriver) Abilities() DriverAbilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *MockDriver) Prestart(ctx *ExecContext, task *structs.Task) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Start starts the mock driver
|
// Start starts the mock driver
|
||||||
func (m *MockDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (m *MockDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
var driverConfig MockDriverConfig
|
var driverConfig MockDriverConfig
|
||||||
|
|
|
@ -135,6 +135,10 @@ func (d *QemuDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool,
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *QemuDriver) Prestart(ctx *ExecContext, task *structs.Task) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Run an existing Qemu image. Start() will pull down an existing, valid Qemu
|
// Run an existing Qemu image. Start() will pull down an existing, valid Qemu
|
||||||
// image and save it to the Drivers Allocation Dir
|
// image and save it to the Drivers Allocation Dir
|
||||||
func (d *QemuDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (d *QemuDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
|
|
|
@ -107,6 +107,13 @@ func (d *RawExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (boo
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *RawExecDriver) Prestart(ctx *ExecContext, task *structs.Task) error {
|
||||||
|
// Set the host environment variables.
|
||||||
|
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
|
||||||
|
d.taskEnv.AppendHostEnvvars(filter)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
var driverConfig ExecDriverConfig
|
var driverConfig ExecDriverConfig
|
||||||
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
|
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
|
||||||
|
@ -125,10 +132,6 @@ func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandl
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the host environment variables.
|
|
||||||
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
|
|
||||||
d.taskEnv.AppendHostEnvvars(filter)
|
|
||||||
|
|
||||||
bin, err := discover.NomadExecutable()
|
bin, err := discover.NomadExecutable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to find the nomad binary: %v", err)
|
return nil, fmt.Errorf("unable to find the nomad binary: %v", err)
|
||||||
|
|
|
@ -75,6 +75,9 @@ func TestRawExecDriver_StartOpen_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRawExecDriver(driverCtx)
|
d := NewRawExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -120,6 +123,9 @@ func TestRawExecDriver_Start_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRawExecDriver(driverCtx)
|
d := NewRawExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -170,6 +176,9 @@ func TestRawExecDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRawExecDriver(driverCtx)
|
d := NewRawExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -219,6 +228,9 @@ func TestRawExecDriver_Start_Kill_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRawExecDriver(driverCtx)
|
d := NewRawExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -268,6 +280,9 @@ func TestRawExecDriverUser(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRawExecDriver(driverCtx)
|
d := NewRawExecDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
handle.Kill()
|
handle.Kill()
|
||||||
|
@ -313,6 +328,9 @@ done
|
||||||
fmt.Errorf("Failed to write data")
|
fmt.Errorf("Failed to write data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("prestart err: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
|
|
@ -206,6 +206,13 @@ func (d *RktDriver) Periodic() (bool, time.Duration) {
|
||||||
return true, 15 * time.Second
|
return true, 15 * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *RktDriver) Prestart(ctx *ExecContext, task *structs.Task) error {
|
||||||
|
d.taskEnv.SetAllocDir(allocdir.SharedAllocContainerPath)
|
||||||
|
d.taskEnv.SetTaskLocalDir(allocdir.TaskLocalContainerPath)
|
||||||
|
d.taskEnv.SetSecretsDir(allocdir.TaskSecretsContainerPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Run an existing Rkt image.
|
// Run an existing Rkt image.
|
||||||
func (d *RktDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
func (d *RktDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
|
||||||
var driverConfig RktDriverConfig
|
var driverConfig RktDriverConfig
|
||||||
|
@ -289,10 +296,6 @@ func (d *RktDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, e
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--debug=%t", debug))
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--debug=%t", debug))
|
||||||
|
|
||||||
// Inject environment variables
|
// Inject environment variables
|
||||||
d.taskEnv.SetAllocDir(allocdir.SharedAllocContainerPath)
|
|
||||||
d.taskEnv.SetTaskLocalDir(allocdir.TaskLocalContainerPath)
|
|
||||||
d.taskEnv.SetSecretsDir(allocdir.TaskSecretsContainerPath)
|
|
||||||
d.taskEnv.Build()
|
|
||||||
for k, v := range d.taskEnv.EnvMap() {
|
for k, v := range d.taskEnv.EnvMap() {
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--set-env=%v=%v", k, v))
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--set-env=%v=%v", k, v))
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,9 @@ func TestRktDriver_Start_DNS(t *testing.T) {
|
||||||
|
|
||||||
d := NewRktDriver(driverCtx)
|
d := NewRktDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -145,6 +148,9 @@ func TestRktDriver_Start_Wait(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRktDriver(driverCtx)
|
d := NewRktDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -202,6 +208,9 @@ func TestRktDriver_Start_Wait_Skip_Trust(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRktDriver(driverCtx)
|
d := NewRktDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -252,6 +261,7 @@ func TestRktDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
"-c",
|
"-c",
|
||||||
fmt.Sprintf(`echo -n %s > foo/%s`, string(exp), file),
|
fmt.Sprintf(`echo -n %s > foo/%s`, string(exp), file),
|
||||||
},
|
},
|
||||||
|
"net": []string{"none"},
|
||||||
"volumes": []string{fmt.Sprintf("%s:/foo", tmpvol)},
|
"volumes": []string{fmt.Sprintf("%s:/foo", tmpvol)},
|
||||||
},
|
},
|
||||||
LogConfig: &structs.LogConfig{
|
LogConfig: &structs.LogConfig{
|
||||||
|
@ -268,6 +278,9 @@ func TestRktDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRktDriver(driverCtx)
|
d := NewRktDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -326,6 +339,9 @@ func TestRktDriverUser(t *testing.T) {
|
||||||
defer execCtx.AllocDir.Destroy()
|
defer execCtx.AllocDir.Destroy()
|
||||||
d := NewRktDriver(driverCtx)
|
d := NewRktDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
handle.Kill()
|
handle.Kill()
|
||||||
|
@ -364,6 +380,9 @@ func TestRktTrustPrefix(t *testing.T) {
|
||||||
|
|
||||||
d := NewRktDriver(driverCtx)
|
d := NewRktDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
handle.Kill()
|
handle.Kill()
|
||||||
|
@ -438,6 +457,9 @@ func TestRktDriver_PortsMapping(t *testing.T) {
|
||||||
|
|
||||||
d := NewRktDriver(driverCtx)
|
d := NewRktDriver(driverCtx)
|
||||||
|
|
||||||
|
if err := d.Prestart(execCtx, task); err != nil {
|
||||||
|
t.Fatalf("error in prestart: %v", err)
|
||||||
|
}
|
||||||
handle, err := d.Start(execCtx, task)
|
handle, err := d.Start(execCtx, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
|
|
@ -346,7 +346,15 @@ func (r *TaskRunner) createDriver() (driver.Driver, error) {
|
||||||
return nil, fmt.Errorf("task environment not made for task %q in allocation %q", r.task.Name, r.alloc.ID)
|
return nil, fmt.Errorf("task environment not made for task %q in allocation %q", r.task.Name, r.alloc.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
driverCtx := driver.NewDriverContext(r.task.Name, r.config, r.config.Node, r.logger, env)
|
// Create a task-specific event emitter callback to expose minimal
|
||||||
|
// state to drivers
|
||||||
|
eventEmitter := func(m string, args ...interface{}) {
|
||||||
|
msg := fmt.Sprintf(m, args...)
|
||||||
|
r.logger.Printf("[DEBUG] client: initialization event for alloc %q: %s", r.alloc.ID, msg)
|
||||||
|
r.setState("", structs.NewTaskEvent(structs.TaskInitializing).SetInitializationMessage(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
driverCtx := driver.NewDriverContext(r.task.Name, r.config, r.config.Node, r.logger, env, eventEmitter)
|
||||||
driver, err := driver.NewDriver(r.task.Driver, driverCtx)
|
driver, err := driver.NewDriver(r.task.Driver, driverCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create driver '%s' for alloc %s: %v",
|
return nil, fmt.Errorf("failed to create driver '%s' for alloc %s: %v",
|
||||||
|
@ -1019,17 +1027,31 @@ func (r *TaskRunner) startTask() error {
|
||||||
// Create a driver
|
// Create a driver
|
||||||
driver, err := r.createDriver()
|
driver, err := r.createDriver()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create driver of task '%s' for alloc '%s': %v",
|
return fmt.Errorf("failed to create driver of task %q for alloc %q: %v",
|
||||||
r.task.Name, r.alloc.ID, err)
|
r.task.Name, r.alloc.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run prestart
|
||||||
|
if err := driver.Prestart(r.ctx, r.task); err != nil {
|
||||||
|
wrapped := fmt.Errorf("failed to initialize task %q for alloc %q: %v",
|
||||||
|
r.task.Name, r.alloc.ID, err)
|
||||||
|
|
||||||
|
r.logger.Printf("[WARN] client: %v", wrapped)
|
||||||
|
|
||||||
|
if rerr, ok := err.(*structs.RecoverableError); ok {
|
||||||
|
return structs.NewRecoverableError(wrapped, rerr.Recoverable)
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapped
|
||||||
|
}
|
||||||
|
|
||||||
// Start the job
|
// Start the job
|
||||||
handle, err := driver.Start(r.ctx, r.task)
|
handle, err := driver.Start(r.ctx, r.task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wrapped := fmt.Errorf("failed to start task '%s' for alloc '%s': %v",
|
wrapped := fmt.Errorf("failed to start task %q for alloc %q: %v",
|
||||||
r.task.Name, r.alloc.ID, err)
|
r.task.Name, r.alloc.ID, err)
|
||||||
|
|
||||||
r.logger.Printf("[INFO] client: %v", wrapped)
|
r.logger.Printf("[WARN] client: %v", wrapped)
|
||||||
|
|
||||||
if rerr, ok := err.(*structs.RecoverableError); ok {
|
if rerr, ok := err.(*structs.RecoverableError); ok {
|
||||||
return structs.NewRecoverableError(wrapped, rerr.Recoverable)
|
return structs.NewRecoverableError(wrapped, rerr.Recoverable)
|
||||||
|
|
|
@ -378,6 +378,8 @@ func (c *AllocStatusCommand) outputTaskStatus(state *api.TaskState) {
|
||||||
} else {
|
} else {
|
||||||
desc = "Task signaled to restart"
|
desc = "Task signaled to restart"
|
||||||
}
|
}
|
||||||
|
case api.TaskInitializing:
|
||||||
|
desc = event.InitializationMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse order so we are sorted by time
|
// Reverse order so we are sorted by time
|
||||||
|
|
|
@ -2555,6 +2555,10 @@ const (
|
||||||
// TaskSiblingFailed indicates that a sibling task in the task group has
|
// TaskSiblingFailed indicates that a sibling task in the task group has
|
||||||
// failed.
|
// failed.
|
||||||
TaskSiblingFailed = "Sibling task failed"
|
TaskSiblingFailed = "Sibling task failed"
|
||||||
|
|
||||||
|
// TaskInitializing indicates that a task is performing a potentially
|
||||||
|
// slow initialization action such as downloading a Docker image.
|
||||||
|
TaskInitializing = "Initializing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TaskEvent is an event that effects the state of a task and contains meta-data
|
// TaskEvent is an event that effects the state of a task and contains meta-data
|
||||||
|
@ -2613,6 +2617,9 @@ type TaskEvent struct {
|
||||||
|
|
||||||
// TaskSignal is the signal that was sent to the task
|
// TaskSignal is the signal that was sent to the task
|
||||||
TaskSignal string
|
TaskSignal string
|
||||||
|
|
||||||
|
// InitializationMessage indicates the initialization step being executed.
|
||||||
|
InitializationMessage string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (te *TaskEvent) GoString() string {
|
func (te *TaskEvent) GoString() string {
|
||||||
|
@ -2741,6 +2748,11 @@ func (e *TaskEvent) SetVaultRenewalError(err error) *TaskEvent {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *TaskEvent) SetInitializationMessage(m string) *TaskEvent {
|
||||||
|
e.InitializationMessage = m
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
// TaskArtifact is an artifact to download before running the task.
|
// TaskArtifact is an artifact to download before running the task.
|
||||||
type TaskArtifact struct {
|
type TaskArtifact struct {
|
||||||
// GetterSource is the source to download an artifact using go-getter
|
// GetterSource is the source to download an artifact using go-getter
|
||||||
|
|
Loading…
Reference in New Issue