github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/client/driver/rkt_test.go (about)

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