Skip to content

Commit

Permalink
driver/exec: Add support for remote source artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
catsby committed Oct 19, 2015
1 parent a50a78a commit 465dbd6
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 2 deletions.
40 changes: 38 additions & 2 deletions client/driver/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ package driver

import (
"fmt"
"log"
"os/exec"
"path"
"path/filepath"
"runtime"
"syscall"
"time"

"github.com/hashicorp/go-getter"
"github.com/hashicorp/nomad/client/allocdir"
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/client/executor"
"github.com/hashicorp/nomad/nomad/structs"
Expand Down Expand Up @@ -41,10 +47,40 @@ func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool,
}

func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
// Get the command
// Get the command to be ran, or if omitted, download an artifact for
// execution. Currently a supplied command takes precedence, and an artifact
// is only downloaded if no command is supplied
command, ok := task.Config["command"]
if !ok || command == "" {
return nil, fmt.Errorf("missing command for exec driver")
source, sok := task.Config["artifact_source"]
if !sok || source == "" {
return nil, fmt.Errorf("missing command or source for exec driver")
}

// Proceed to download an artifact to be executed.
// We use go-getter to support a variety of protocols, but need to change
// file permissions of the resulted download to be executable
taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
if !ok {
return nil, fmt.Errorf("[Err] driver.Exec: Could not find task directory for task: %v", d.DriverContext.taskName)
}

destDir := filepath.Join(taskDir, allocdir.TaskLocal)

// Create a location to download the artifact.
artifactName := path.Base(source)
command = filepath.Join(destDir, artifactName)
if err := getter.GetFile(command, source); err != nil {
return nil, fmt.Errorf("[Err] driver.Exec: Error downloading source for Exec driver: %s", err)
}

cmd := exec.Command("chmod", "+x", command)
if err := cmd.Run(); err != nil {
log.Printf("[Err] driver.Exec: Error making artifact executable: %s", err)
}

// re-assign the command to be the local execution path
command = filepath.Join(allocdir.TaskLocal, artifactName)
}

// Get the environment variables.
Expand Down
40 changes: 40 additions & 0 deletions client/driver/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,46 @@ func TestExecDriver_Start_Wait(t *testing.T) {
}
}

func TestExecDriver_Start_Artifact_Wait(t *testing.T) {
ctestutils.ExecCompatible(t)
task := &structs.Task{
Name: "sleep",
Config: map[string]string{
"artifact_source": "https://dl.dropboxusercontent.com/u/47675/jar_thing/hi_linux_amd64",
},
Resources: basicResources,
}

driverCtx := testDriverContext(task.Name)
ctx := testDriverExecContext(task, driverCtx)
defer ctx.AllocDir.Destroy()
d := NewExecDriver(driverCtx)

handle, err := d.Start(ctx, task)
if err != nil {
t.Fatalf("err: %v", err)
}
if handle == nil {
t.Fatalf("missing handle")
}

// Update should be a no-op
err = handle.Update(task)
if err != nil {
t.Fatalf("err: %v", err)
}

// Task should terminate quickly
select {
case err := <-handle.WaitCh():
if err != nil {
t.Fatalf("err: %v", err)
}
case <-time.After(2 * time.Second):
t.Fatalf("timeout")
}
}

func TestExecDriver_Start_Wait_AllocDir(t *testing.T) {
ctestutils.ExecCompatible(t)

Expand Down

0 comments on commit 465dbd6

Please sign in to comment.