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