github.com/jmitchell/nomad@v0.1.3-0.20151007230021-7ab84c2862d8/client/driver/docker_test.go (about)

     1  package driver
     2  
     3  import (
     4  	"os/exec"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/hashicorp/nomad/client/config"
     9  	"github.com/hashicorp/nomad/nomad/structs"
    10  )
    11  
    12  // dockerLocated looks to see whether docker is available on this system before
    13  // we try to run tests. We'll keep it simple and just check for the CLI.
    14  func dockerLocated() bool {
    15  	_, err := exec.Command("docker", "-v").CombinedOutput()
    16  	return err == nil
    17  }
    18  
    19  func TestDockerDriver_Handle(t *testing.T) {
    20  	h := &dockerHandle{
    21  		imageID:     "imageid",
    22  		containerID: "containerid",
    23  		doneCh:      make(chan struct{}),
    24  		waitCh:      make(chan error, 1),
    25  	}
    26  
    27  	actual := h.ID()
    28  	expected := `DOCKER:{"ImageID":"imageid","ContainerID":"containerid"}`
    29  	if actual != expected {
    30  		t.Errorf("Expected `%s`, found `%s`", expected, actual)
    31  	}
    32  }
    33  
    34  // The fingerprinter test should always pass, even if Docker is not installed.
    35  func TestDockerDriver_Fingerprint(t *testing.T) {
    36  	d := NewDockerDriver(testDriverContext(""))
    37  	node := &structs.Node{
    38  		Attributes: make(map[string]string),
    39  	}
    40  	apply, err := d.Fingerprint(&config.Config{}, node)
    41  	if err != nil {
    42  		t.Fatalf("err: %v", err)
    43  	}
    44  	if apply != dockerLocated() {
    45  		t.Fatalf("Fingerprinter should detect Docker when it is installed")
    46  	}
    47  	if node.Attributes["driver.docker"] == "" {
    48  		t.Log("Docker not found. The remainder of the docker tests will be skipped.")
    49  	}
    50  	t.Logf("Found docker version %s", node.Attributes["driver.docker.version"])
    51  }
    52  
    53  func TestDockerDriver_StartOpen_Wait(t *testing.T) {
    54  	if !dockerLocated() {
    55  		t.SkipNow()
    56  	}
    57  
    58  	task := &structs.Task{
    59  		Name: "python-demo",
    60  		Config: map[string]string{
    61  			"image": "redis",
    62  		},
    63  		Resources: basicResources,
    64  	}
    65  
    66  	driverCtx := testDriverContext(task.Name)
    67  	ctx := testDriverExecContext(task, driverCtx)
    68  	defer ctx.AllocDir.Destroy()
    69  	d := NewDockerDriver(driverCtx)
    70  
    71  	handle, err := d.Start(ctx, task)
    72  	if err != nil {
    73  		t.Fatalf("err: %v", err)
    74  	}
    75  	if handle == nil {
    76  		t.Fatalf("missing handle")
    77  	}
    78  	defer handle.Kill()
    79  
    80  	// Attempt to open
    81  	handle2, err := d.Open(ctx, handle.ID())
    82  	if err != nil {
    83  		t.Fatalf("err: %v", err)
    84  	}
    85  	if handle2 == nil {
    86  		t.Fatalf("missing handle")
    87  	}
    88  }
    89  
    90  func TestDockerDriver_Start_Wait(t *testing.T) {
    91  	if !dockerLocated() {
    92  		t.SkipNow()
    93  	}
    94  
    95  	task := &structs.Task{
    96  		Name: "python-demo",
    97  		Config: map[string]string{
    98  			"image":   "redis",
    99  			"command": "redis-server -v",
   100  		},
   101  		Resources: &structs.Resources{
   102  			MemoryMB: 256,
   103  			CPU:      512,
   104  		},
   105  	}
   106  
   107  	driverCtx := testDriverContext(task.Name)
   108  	ctx := testDriverExecContext(task, driverCtx)
   109  	defer ctx.AllocDir.Destroy()
   110  	d := NewDockerDriver(driverCtx)
   111  
   112  	handle, err := d.Start(ctx, task)
   113  	if err != nil {
   114  		t.Fatalf("err: %v", err)
   115  	}
   116  	if handle == nil {
   117  		t.Fatalf("missing handle")
   118  	}
   119  	defer handle.Kill()
   120  
   121  	// Update should be a no-op
   122  	err = handle.Update(task)
   123  	if err != nil {
   124  		t.Fatalf("err: %v", err)
   125  	}
   126  
   127  	select {
   128  	case err := <-handle.WaitCh():
   129  		if err != nil {
   130  			t.Fatalf("err: %v", err)
   131  		}
   132  	case <-time.After(5 * time.Second):
   133  		t.Fatalf("timeout")
   134  	}
   135  }
   136  
   137  func TestDockerDriver_Start_Kill_Wait(t *testing.T) {
   138  	if !dockerLocated() {
   139  		t.SkipNow()
   140  	}
   141  
   142  	task := &structs.Task{
   143  		Name: "python-demo",
   144  		Config: map[string]string{
   145  			"image":   "redis",
   146  			"command": "sleep 10",
   147  		},
   148  		Resources: basicResources,
   149  	}
   150  
   151  	driverCtx := testDriverContext(task.Name)
   152  	ctx := testDriverExecContext(task, driverCtx)
   153  	defer ctx.AllocDir.Destroy()
   154  	d := NewDockerDriver(driverCtx)
   155  
   156  	handle, err := d.Start(ctx, task)
   157  	if err != nil {
   158  		t.Fatalf("err: %v", err)
   159  	}
   160  	if handle == nil {
   161  		t.Fatalf("missing handle")
   162  	}
   163  	defer handle.Kill()
   164  
   165  	go func() {
   166  		time.Sleep(100 * time.Millisecond)
   167  		err := handle.Kill()
   168  		if err != nil {
   169  			t.Fatalf("err: %v", err)
   170  		}
   171  	}()
   172  
   173  	select {
   174  	case err := <-handle.WaitCh():
   175  		if err == nil {
   176  			t.Fatalf("should err: %v", err)
   177  		}
   178  	case <-time.After(10 * time.Second):
   179  		t.Fatalf("timeout")
   180  	}
   181  }
   182  
   183  func taskTemplate() *structs.Task {
   184  	return &structs.Task{
   185  		Config: map[string]string{
   186  			"image": "redis",
   187  		},
   188  		Resources: &structs.Resources{
   189  			MemoryMB: 256,
   190  			CPU:      512,
   191  			Networks: []*structs.NetworkResource{
   192  				&structs.NetworkResource{
   193  					IP:            "127.0.0.1",
   194  					ReservedPorts: []int{11110},
   195  					DynamicPorts:  []string{"REDIS"},
   196  				},
   197  			},
   198  		},
   199  	}
   200  }
   201  
   202  func TestDocker_StartN(t *testing.T) {
   203  	if !dockerLocated() {
   204  		t.SkipNow()
   205  	}
   206  
   207  	task1 := taskTemplate()
   208  	task1.Resources.Networks[0].ReservedPorts[0] = 11111
   209  
   210  	task2 := taskTemplate()
   211  	task2.Resources.Networks[0].ReservedPorts[0] = 22222
   212  
   213  	task3 := taskTemplate()
   214  	task3.Resources.Networks[0].ReservedPorts[0] = 33333
   215  
   216  	taskList := []*structs.Task{task1, task2, task3}
   217  
   218  	handles := make([]DriverHandle, len(taskList))
   219  
   220  	t.Logf("==> Starting %d tasks", len(taskList))
   221  
   222  	// Let's spin up a bunch of things
   223  	var err error
   224  	for idx, task := range taskList {
   225  		driverCtx := testDriverContext(task.Name)
   226  		ctx := testDriverExecContext(task, driverCtx)
   227  		defer ctx.AllocDir.Destroy()
   228  		d := NewDockerDriver(driverCtx)
   229  
   230  		handles[idx], err = d.Start(ctx, task)
   231  		if err != nil {
   232  			t.Errorf("Failed starting task #%d: %s", idx+1, err)
   233  		}
   234  	}
   235  
   236  	t.Log("==> All tasks are started. Terminating...")
   237  
   238  	for idx, handle := range handles {
   239  		err := handle.Kill()
   240  		if err != nil {
   241  			t.Errorf("Failed stopping task #%d: %s", idx+1, err)
   242  		}
   243  	}
   244  
   245  	t.Log("==> Test complete!")
   246  }
   247  
   248  func TestDocker_StartNVersions(t *testing.T) {
   249  	if !dockerLocated() {
   250  		t.SkipNow()
   251  	}
   252  
   253  	task1 := taskTemplate()
   254  	task1.Config["image"] = "redis"
   255  	task1.Resources.Networks[0].ReservedPorts[0] = 11111
   256  
   257  	task2 := taskTemplate()
   258  	task2.Config["image"] = "redis:latest"
   259  	task2.Resources.Networks[0].ReservedPorts[0] = 22222
   260  
   261  	task3 := taskTemplate()
   262  	task3.Config["image"] = "redis:3.0"
   263  	task3.Resources.Networks[0].ReservedPorts[0] = 33333
   264  
   265  	taskList := []*structs.Task{task1, task2, task3}
   266  
   267  	handles := make([]DriverHandle, len(taskList))
   268  
   269  	t.Logf("==> Starting %d tasks", len(taskList))
   270  
   271  	// Let's spin up a bunch of things
   272  	var err error
   273  	for idx, task := range taskList {
   274  		driverCtx := testDriverContext(task.Name)
   275  		ctx := testDriverExecContext(task, driverCtx)
   276  		defer ctx.AllocDir.Destroy()
   277  		d := NewDockerDriver(driverCtx)
   278  
   279  		handles[idx], err = d.Start(ctx, task)
   280  		if err != nil {
   281  			t.Errorf("Failed starting task #%d: %s", idx+1, err)
   282  		}
   283  	}
   284  
   285  	t.Log("==> All tasks are started. Terminating...")
   286  
   287  	for idx, handle := range handles {
   288  		err := handle.Kill()
   289  		if err != nil {
   290  			t.Errorf("Failed stopping task #%d: %s", idx+1, err)
   291  		}
   292  	}
   293  
   294  	t.Log("==> Test complete!")
   295  }
   296  
   297  func TestDockerHostNet(t *testing.T) {
   298  	if !dockerLocated() {
   299  		t.SkipNow()
   300  	}
   301  
   302  	task := &structs.Task{
   303  		Config: map[string]string{
   304  			"image":        "redis",
   305  			"network_mode": "host",
   306  		},
   307  		Resources: &structs.Resources{
   308  			MemoryMB: 256,
   309  			CPU:      512,
   310  		},
   311  	}
   312  	driverCtx := testDriverContext(task.Name)
   313  	ctx := testDriverExecContext(task, driverCtx)
   314  	defer ctx.AllocDir.Destroy()
   315  	d := NewDockerDriver(driverCtx)
   316  
   317  	handle, err := d.Start(ctx, task)
   318  	if err != nil {
   319  		t.Fatalf("err: %v", err)
   320  	}
   321  	if handle == nil {
   322  		t.Fatalf("missing handle")
   323  	}
   324  	defer handle.Kill()
   325  }