github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/client/driver/rkt_test.go (about)

     1  package driver
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"reflect"
    11  	"strings"
    12  	"syscall"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/hashicorp/nomad/client/config"
    17  	"github.com/hashicorp/nomad/nomad/structs"
    18  	"github.com/hashicorp/nomad/testutil"
    19  
    20  	ctestutils "github.com/hashicorp/nomad/client/testutil"
    21  )
    22  
    23  func TestRktVersionRegex(t *testing.T) {
    24  	if os.Getenv("NOMAD_TEST_RKT") == "" {
    25  		t.Skip("NOMAD_TEST_RKT unset, skipping")
    26  	}
    27  
    28  	input_rkt := "rkt version 0.8.1"
    29  	input_appc := "appc version 1.2.0"
    30  	expected_rkt := "0.8.1"
    31  	expected_appc := "1.2.0"
    32  	rktMatches := reRktVersion.FindStringSubmatch(input_rkt)
    33  	appcMatches := reAppcVersion.FindStringSubmatch(input_appc)
    34  	if rktMatches[1] != expected_rkt {
    35  		fmt.Printf("Test failed; got %q; want %q\n", rktMatches[1], expected_rkt)
    36  	}
    37  	if appcMatches[1] != expected_appc {
    38  		fmt.Printf("Test failed; got %q; want %q\n", appcMatches[1], expected_appc)
    39  	}
    40  }
    41  
    42  // The fingerprinter test should always pass, even if rkt is not installed.
    43  func TestRktDriver_Fingerprint(t *testing.T) {
    44  	if os.Getenv("NOMAD_TEST_RKT") == "" {
    45  		t.Skip("skipping rkt tests")
    46  	}
    47  
    48  	ctestutils.RktCompatible(t)
    49  	ctx := testDriverContexts(t, &structs.Task{Name: "foo", Driver: "rkt"})
    50  	d := NewRktDriver(ctx.DriverCtx)
    51  	node := &structs.Node{
    52  		Attributes: make(map[string]string),
    53  	}
    54  	apply, err := d.Fingerprint(&config.Config{}, node)
    55  	if err != nil {
    56  		t.Fatalf("err: %v", err)
    57  	}
    58  	if !apply {
    59  		t.Fatalf("should apply")
    60  	}
    61  	if node.Attributes["driver.rkt"] != "1" {
    62  		t.Fatalf("Missing Rkt driver")
    63  	}
    64  	if node.Attributes["driver.rkt.version"] == "" {
    65  		t.Fatalf("Missing Rkt driver version")
    66  	}
    67  	if node.Attributes["driver.rkt.appc.version"] == "" {
    68  		t.Fatalf("Missing appc version for the Rkt driver")
    69  	}
    70  }
    71  
    72  func TestRktDriver_Start_DNS(t *testing.T) {
    73  	if os.Getenv("NOMAD_TEST_RKT") == "" {
    74  		t.Skip("skipping rkt tests")
    75  	}
    76  
    77  	ctestutils.RktCompatible(t)
    78  	// TODO: use test server to load from a fixture
    79  	task := &structs.Task{
    80  		Name:   "etcd",
    81  		Driver: "rkt",
    82  		Config: map[string]interface{}{
    83  			"trust_prefix":       "coreos.com/etcd",
    84  			"image":              "coreos.com/etcd:v2.0.4",
    85  			"command":            "/etcd",
    86  			"dns_servers":        []string{"8.8.8.8", "8.8.4.4"},
    87  			"dns_search_domains": []string{"example.com", "example.org", "example.net"},
    88  		},
    89  		LogConfig: &structs.LogConfig{
    90  			MaxFiles:      10,
    91  			MaxFileSizeMB: 10,
    92  		},
    93  		Resources: &structs.Resources{
    94  			MemoryMB: 128,
    95  			CPU:      100,
    96  		},
    97  	}
    98  
    99  	ctx := testDriverContexts(t, task)
   100  	defer ctx.AllocDir.Destroy()
   101  	d := NewRktDriver(ctx.DriverCtx)
   102  
   103  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   104  		t.Fatalf("error in prestart: %v", err)
   105  	}
   106  	handle, err := d.Start(ctx.ExecCtx, task)
   107  	if err != nil {
   108  		t.Fatalf("err: %v", err)
   109  	}
   110  	if handle == nil {
   111  		t.Fatalf("missing handle")
   112  	}
   113  	defer handle.Kill()
   114  
   115  	// Attempt to open
   116  	handle2, err := d.Open(ctx.ExecCtx, handle.ID())
   117  	if err != nil {
   118  		t.Fatalf("err: %v", err)
   119  	}
   120  	if handle2 == nil {
   121  		t.Fatalf("missing handle")
   122  	}
   123  }
   124  
   125  func TestRktDriver_Start_Wait(t *testing.T) {
   126  	if os.Getenv("NOMAD_TEST_RKT") == "" {
   127  		t.Skip("skipping rkt tests")
   128  	}
   129  
   130  	ctestutils.RktCompatible(t)
   131  	task := &structs.Task{
   132  		Name:   "etcd",
   133  		Driver: "rkt",
   134  		Config: map[string]interface{}{
   135  			"trust_prefix": "coreos.com/etcd",
   136  			"image":        "coreos.com/etcd:v2.0.4",
   137  			"command":      "/etcd",
   138  			"args":         []string{"--version"},
   139  		},
   140  		LogConfig: &structs.LogConfig{
   141  			MaxFiles:      10,
   142  			MaxFileSizeMB: 10,
   143  		},
   144  		Resources: &structs.Resources{
   145  			MemoryMB: 128,
   146  			CPU:      100,
   147  		},
   148  	}
   149  
   150  	ctx := testDriverContexts(t, task)
   151  	defer ctx.AllocDir.Destroy()
   152  	d := NewRktDriver(ctx.DriverCtx)
   153  
   154  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   155  		t.Fatalf("error in prestart: %v", err)
   156  	}
   157  	handle, err := d.Start(ctx.ExecCtx, task)
   158  	if err != nil {
   159  		t.Fatalf("err: %v", err)
   160  	}
   161  	if handle == nil {
   162  		t.Fatalf("missing handle")
   163  	}
   164  	defer handle.Kill()
   165  
   166  	// Update should be a no-op
   167  	err = handle.Update(task)
   168  	if err != nil {
   169  		t.Fatalf("err: %v", err)
   170  	}
   171  
   172  	// Signal should be an error
   173  	if err = handle.Signal(syscall.SIGTERM); err == nil {
   174  		t.Fatalf("err: %v", err)
   175  	}
   176  
   177  	select {
   178  	case res := <-handle.WaitCh():
   179  		if !res.Successful() {
   180  			t.Fatalf("err: %v", res)
   181  		}
   182  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   183  		t.Fatalf("timeout")
   184  	}
   185  }
   186  
   187  func TestRktDriver_Start_Wait_Skip_Trust(t *testing.T) {
   188  	if os.Getenv("NOMAD_TEST_RKT") == "" {
   189  		t.Skip("skipping rkt tests")
   190  	}
   191  
   192  	ctestutils.RktCompatible(t)
   193  	task := &structs.Task{
   194  		Name:   "etcd",
   195  		Driver: "rkt",
   196  		Config: map[string]interface{}{
   197  			"image":   "coreos.com/etcd:v2.0.4",
   198  			"command": "/etcd",
   199  			"args":    []string{"--version"},
   200  		},
   201  		LogConfig: &structs.LogConfig{
   202  			MaxFiles:      10,
   203  			MaxFileSizeMB: 10,
   204  		},
   205  		Resources: &structs.Resources{
   206  			MemoryMB: 128,
   207  			CPU:      100,
   208  		},
   209  	}
   210  
   211  	ctx := testDriverContexts(t, task)
   212  	defer ctx.AllocDir.Destroy()
   213  	d := NewRktDriver(ctx.DriverCtx)
   214  
   215  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   216  		t.Fatalf("error in prestart: %v", err)
   217  	}
   218  	handle, err := d.Start(ctx.ExecCtx, task)
   219  	if err != nil {
   220  		t.Fatalf("err: %v", err)
   221  	}
   222  	if handle == nil {
   223  		t.Fatalf("missing handle")
   224  	}
   225  	defer handle.Kill()
   226  
   227  	// Update should be a no-op
   228  	err = handle.Update(task)
   229  	if err != nil {
   230  		t.Fatalf("err: %v", err)
   231  	}
   232  
   233  	select {
   234  	case res := <-handle.WaitCh():
   235  		if !res.Successful() {
   236  			t.Fatalf("err: %v", res)
   237  		}
   238  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   239  		t.Fatalf("timeout")
   240  	}
   241  }
   242  
   243  func TestRktDriver_Start_Wait_AllocDir(t *testing.T) {
   244  	if os.Getenv("NOMAD_TEST_RKT") == "" {
   245  		t.Skip("skipping rkt tests")
   246  	}
   247  
   248  	ctestutils.RktCompatible(t)
   249  
   250  	exp := []byte{'w', 'i', 'n'}
   251  	file := "output.txt"
   252  	tmpvol, err := ioutil.TempDir("", "nomadtest_rktdriver_volumes")
   253  	if err != nil {
   254  		t.Fatalf("error creating temporary dir: %v", err)
   255  	}
   256  	defer os.RemoveAll(tmpvol)
   257  	hostpath := filepath.Join(tmpvol, file)
   258  
   259  	task := &structs.Task{
   260  		Name:   "rkttest_alpine",
   261  		Driver: "rkt",
   262  		Config: map[string]interface{}{
   263  			"image":   "docker://alpine",
   264  			"command": "/bin/sh",
   265  			"args": []string{
   266  				"-c",
   267  				fmt.Sprintf(`echo -n %s > foo/%s`, string(exp), file),
   268  			},
   269  			"net":     []string{"none"},
   270  			"volumes": []string{fmt.Sprintf("%s:/foo", tmpvol)},
   271  		},
   272  		LogConfig: &structs.LogConfig{
   273  			MaxFiles:      10,
   274  			MaxFileSizeMB: 10,
   275  		},
   276  		Resources: &structs.Resources{
   277  			MemoryMB: 128,
   278  			CPU:      100,
   279  		},
   280  	}
   281  
   282  	ctx := testDriverContexts(t, task)
   283  	defer ctx.AllocDir.Destroy()
   284  	d := NewRktDriver(ctx.DriverCtx)
   285  
   286  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   287  		t.Fatalf("error in prestart: %v", err)
   288  	}
   289  	handle, err := d.Start(ctx.ExecCtx, task)
   290  	if err != nil {
   291  		t.Fatalf("err: %v", err)
   292  	}
   293  	if handle == nil {
   294  		t.Fatalf("missing handle")
   295  	}
   296  	defer handle.Kill()
   297  
   298  	select {
   299  	case res := <-handle.WaitCh():
   300  		if !res.Successful() {
   301  			t.Fatalf("err: %v", res)
   302  		}
   303  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   304  		t.Fatalf("timeout")
   305  	}
   306  
   307  	// Check that data was written to the shared alloc directory.
   308  	act, err := ioutil.ReadFile(hostpath)
   309  	if err != nil {
   310  		t.Fatalf("Couldn't read expected output: %v", err)
   311  	}
   312  
   313  	if !reflect.DeepEqual(act, exp) {
   314  		t.Fatalf("Command output is %v; expected %v", act, exp)
   315  	}
   316  }
   317  
   318  func TestRktDriverUser(t *testing.T) {
   319  	if os.Getenv("NOMAD_TEST_RKT") == "" {
   320  		t.Skip("skipping rkt tests")
   321  	}
   322  
   323  	ctestutils.RktCompatible(t)
   324  	task := &structs.Task{
   325  		Name:   "etcd",
   326  		Driver: "rkt",
   327  		User:   "alice",
   328  		Config: map[string]interface{}{
   329  			"trust_prefix": "coreos.com/etcd",
   330  			"image":        "coreos.com/etcd:v2.0.4",
   331  			"command":      "/etcd",
   332  			"args":         []string{"--version"},
   333  		},
   334  		LogConfig: &structs.LogConfig{
   335  			MaxFiles:      10,
   336  			MaxFileSizeMB: 10,
   337  		},
   338  		Resources: &structs.Resources{
   339  			MemoryMB: 128,
   340  			CPU:      100,
   341  		},
   342  	}
   343  
   344  	ctx := testDriverContexts(t, task)
   345  	defer ctx.AllocDir.Destroy()
   346  	d := NewRktDriver(ctx.DriverCtx)
   347  
   348  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   349  		t.Fatalf("error in prestart: %v", err)
   350  	}
   351  	handle, err := d.Start(ctx.ExecCtx, task)
   352  	if err == nil {
   353  		handle.Kill()
   354  		t.Fatalf("Should've failed")
   355  	}
   356  	msg := "unknown user alice"
   357  	if !strings.Contains(err.Error(), msg) {
   358  		t.Fatalf("Expecting '%v' in '%v'", msg, err)
   359  	}
   360  }
   361  
   362  func TestRktTrustPrefix(t *testing.T) {
   363  	if os.Getenv("NOMAD_TEST_RKT") == "" {
   364  		t.Skip("skipping rkt tests")
   365  	}
   366  	ctestutils.RktCompatible(t)
   367  	task := &structs.Task{
   368  		Name:   "etcd",
   369  		Driver: "rkt",
   370  		Config: map[string]interface{}{
   371  			"trust_prefix": "example.com/invalid",
   372  			"image":        "coreos.com/etcd:v2.0.4",
   373  			"command":      "/etcd",
   374  			"args":         []string{"--version"},
   375  		},
   376  		LogConfig: &structs.LogConfig{
   377  			MaxFiles:      10,
   378  			MaxFileSizeMB: 10,
   379  		},
   380  		Resources: &structs.Resources{
   381  			MemoryMB: 128,
   382  			CPU:      100,
   383  		},
   384  	}
   385  	ctx := testDriverContexts(t, task)
   386  	defer ctx.AllocDir.Destroy()
   387  	d := NewRktDriver(ctx.DriverCtx)
   388  
   389  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   390  		t.Fatalf("error in prestart: %v", err)
   391  	}
   392  	handle, err := d.Start(ctx.ExecCtx, task)
   393  	if err == nil {
   394  		handle.Kill()
   395  		t.Fatalf("Should've failed")
   396  	}
   397  	msg := "Error running rkt trust"
   398  	if !strings.Contains(err.Error(), msg) {
   399  		t.Fatalf("Expecting '%v' in '%v'", msg, err)
   400  	}
   401  }
   402  
   403  func TestRktTaskValidate(t *testing.T) {
   404  	ctestutils.RktCompatible(t)
   405  	task := &structs.Task{
   406  		Name:   "etcd",
   407  		Driver: "rkt",
   408  		Config: map[string]interface{}{
   409  			"trust_prefix":       "coreos.com/etcd",
   410  			"image":              "coreos.com/etcd:v2.0.4",
   411  			"command":            "/etcd",
   412  			"args":               []string{"--version"},
   413  			"dns_servers":        []string{"8.8.8.8", "8.8.4.4"},
   414  			"dns_search_domains": []string{"example.com", "example.org", "example.net"},
   415  		},
   416  		Resources: basicResources,
   417  	}
   418  	ctx := testDriverContexts(t, task)
   419  	defer ctx.AllocDir.Destroy()
   420  	d := NewRktDriver(ctx.DriverCtx)
   421  
   422  	if err := d.Validate(task.Config); err != nil {
   423  		t.Fatalf("Validation error in TaskConfig : '%v'", err)
   424  	}
   425  }
   426  
   427  // TODO: Port Mapping test should be ran with proper ACI image and test the port access.
   428  func TestRktDriver_PortsMapping(t *testing.T) {
   429  	if os.Getenv("NOMAD_TEST_RKT") == "" {
   430  		t.Skip("skipping rkt tests")
   431  	}
   432  
   433  	ctestutils.RktCompatible(t)
   434  	task := &structs.Task{
   435  		Name:   "etcd",
   436  		Driver: "rkt",
   437  		Config: map[string]interface{}{
   438  			"image": "docker://redis:latest",
   439  			"args":  []string{"--version"},
   440  			"port_map": []map[string]string{
   441  				map[string]string{
   442  					"main": "6379-tcp",
   443  				},
   444  			},
   445  			"debug": "true",
   446  		},
   447  		LogConfig: &structs.LogConfig{
   448  			MaxFiles:      10,
   449  			MaxFileSizeMB: 10,
   450  		},
   451  		Resources: &structs.Resources{
   452  			MemoryMB: 256,
   453  			CPU:      512,
   454  			Networks: []*structs.NetworkResource{
   455  				&structs.NetworkResource{
   456  					IP:            "127.0.0.1",
   457  					ReservedPorts: []structs.Port{{Label: "main", Value: 8080}},
   458  				},
   459  			},
   460  		},
   461  	}
   462  
   463  	ctx := testDriverContexts(t, task)
   464  	defer ctx.AllocDir.Destroy()
   465  	d := NewRktDriver(ctx.DriverCtx)
   466  
   467  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   468  		t.Fatalf("error in prestart: %v", err)
   469  	}
   470  	handle, err := d.Start(ctx.ExecCtx, task)
   471  	if err != nil {
   472  		t.Fatalf("err: %v", err)
   473  	}
   474  	if handle == nil {
   475  		t.Fatalf("missing handle")
   476  	}
   477  
   478  	failCh := make(chan error, 1)
   479  	go func() {
   480  		time.Sleep(1 * time.Second)
   481  		if err := handle.Kill(); err != nil {
   482  			failCh <- err
   483  		}
   484  	}()
   485  
   486  	select {
   487  	case err := <-failCh:
   488  		t.Fatalf("failed to kill handle: %v", err)
   489  	case <-handle.WaitCh():
   490  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   491  		t.Fatalf("timeout")
   492  	}
   493  }
   494  
   495  func TestRktDriver_HandlerExec(t *testing.T) {
   496  	if os.Getenv("NOMAD_TEST_RKT") == "" {
   497  		t.Skip("skipping rkt tests")
   498  	}
   499  
   500  	ctestutils.RktCompatible(t)
   501  	task := &structs.Task{
   502  		Name:   "etcd",
   503  		Driver: "rkt",
   504  		Config: map[string]interface{}{
   505  			"trust_prefix": "coreos.com/etcd",
   506  			"image":        "coreos.com/etcd:v2.0.4",
   507  			"command":      "/etcd",
   508  		},
   509  		LogConfig: &structs.LogConfig{
   510  			MaxFiles:      10,
   511  			MaxFileSizeMB: 10,
   512  		},
   513  		Resources: &structs.Resources{
   514  			MemoryMB: 128,
   515  			CPU:      100,
   516  		},
   517  	}
   518  
   519  	ctx := testDriverContexts(t, task)
   520  	defer ctx.AllocDir.Destroy()
   521  	d := NewRktDriver(ctx.DriverCtx)
   522  
   523  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   524  		t.Fatalf("error in prestart: %v", err)
   525  	}
   526  	handle, err := d.Start(ctx.ExecCtx, task)
   527  	if err != nil {
   528  		t.Fatalf("err: %v", err)
   529  	}
   530  	if handle == nil {
   531  		t.Fatalf("missing handle")
   532  	}
   533  
   534  	// Give the pod a second to start
   535  	time.Sleep(time.Second)
   536  
   537  	// Exec a command that should work
   538  	out, code, err := handle.Exec(context.TODO(), "/etcd", []string{"--version"})
   539  	if err != nil {
   540  		t.Fatalf("error exec'ing etcd --version: %v", err)
   541  	}
   542  	if code != 0 {
   543  		t.Fatalf("expected `etcd --version` to succeed but exit code was: %d\n%s", code, string(out))
   544  	}
   545  	if expected := []byte("etcd version "); !bytes.HasPrefix(out, expected) {
   546  		t.Fatalf("expected output to start with %q but found:\n%q", expected, out)
   547  	}
   548  
   549  	// Exec a command that should fail
   550  	out, code, err = handle.Exec(context.TODO(), "/etcd", []string{"--kaljdshf"})
   551  	if err != nil {
   552  		t.Fatalf("error exec'ing bad command: %v", err)
   553  	}
   554  	if code == 0 {
   555  		t.Fatalf("expected `stat` to fail but exit code was: %d", code)
   556  	}
   557  	if expected := "flag provided but not defined"; !bytes.Contains(out, []byte(expected)) {
   558  		t.Fatalf("expected output to contain %q but found: %q", expected, out)
   559  	}
   560  
   561  	if err := handle.Kill(); err != nil {
   562  		t.Fatalf("error killing handle: %v", err)
   563  	}
   564  }