github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/runconfig/hostconfig_test.go (about)

     1  // +build !windows
     2  
     3  package runconfig // import "github.com/docker/docker/runconfig"
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"testing"
    10  
    11  	"github.com/docker/docker/api/types/container"
    12  	"github.com/docker/docker/pkg/sysinfo"
    13  	"gotest.tools/v3/assert"
    14  	is "gotest.tools/v3/assert/cmp"
    15  )
    16  
    17  func TestCgroupnsModeTest(t *testing.T) {
    18  	cgroupNsModes := map[container.CgroupnsMode][]bool{
    19  		// private, host, empty, valid
    20  		"":                {false, false, true, true},
    21  		"something:weird": {false, false, false, false},
    22  		"host":            {false, true, false, true},
    23  		"host:name":       {false, false, false, false},
    24  		"private":         {true, false, false, true},
    25  		"private:name":    {false, false, false, false},
    26  	}
    27  	for cgroupNsMode, state := range cgroupNsModes {
    28  		if cgroupNsMode.IsPrivate() != state[0] {
    29  			t.Fatalf("CgroupnsMode.IsPrivate for %v should have been %v but was %v", cgroupNsMode, state[0], cgroupNsMode.IsPrivate())
    30  		}
    31  		if cgroupNsMode.IsHost() != state[1] {
    32  			t.Fatalf("CgroupnsMode.IsHost for %v should have been %v but was %v", cgroupNsMode, state[1], cgroupNsMode.IsHost())
    33  		}
    34  		if cgroupNsMode.IsEmpty() != state[2] {
    35  			t.Fatalf("CgroupnsMode.Valid for %v should have been %v but was %v", cgroupNsMode, state[2], cgroupNsMode.Valid())
    36  		}
    37  		if cgroupNsMode.Valid() != state[3] {
    38  			t.Fatalf("CgroupnsMode.Valid for %v should have been %v but was %v", cgroupNsMode, state[2], cgroupNsMode.Valid())
    39  		}
    40  	}
    41  }
    42  
    43  // TODO Windows: This will need addressing for a Windows daemon.
    44  func TestNetworkModeTest(t *testing.T) {
    45  	networkModes := map[container.NetworkMode][]bool{
    46  		// private, bridge, host, container, none, default
    47  		"":                         {true, false, false, false, false, false},
    48  		"something:weird":          {true, false, false, false, false, false},
    49  		"bridge":                   {true, true, false, false, false, false},
    50  		DefaultDaemonNetworkMode(): {true, true, false, false, false, false},
    51  		"host":                     {false, false, true, false, false, false},
    52  		"container:name":           {false, false, false, true, false, false},
    53  		"none":                     {true, false, false, false, true, false},
    54  		"default":                  {true, false, false, false, false, true},
    55  	}
    56  	networkModeNames := map[container.NetworkMode]string{
    57  		"":                         "",
    58  		"something:weird":          "something:weird",
    59  		"bridge":                   "bridge",
    60  		DefaultDaemonNetworkMode(): "bridge",
    61  		"host":                     "host",
    62  		"container:name":           "container",
    63  		"none":                     "none",
    64  		"default":                  "default",
    65  	}
    66  	for networkMode, state := range networkModes {
    67  		if networkMode.IsPrivate() != state[0] {
    68  			t.Fatalf("NetworkMode.IsPrivate for %v should have been %v but was %v", networkMode, state[0], networkMode.IsPrivate())
    69  		}
    70  		if networkMode.IsBridge() != state[1] {
    71  			t.Fatalf("NetworkMode.IsBridge for %v should have been %v but was %v", networkMode, state[1], networkMode.IsBridge())
    72  		}
    73  		if networkMode.IsHost() != state[2] {
    74  			t.Fatalf("NetworkMode.IsHost for %v should have been %v but was %v", networkMode, state[2], networkMode.IsHost())
    75  		}
    76  		if networkMode.IsContainer() != state[3] {
    77  			t.Fatalf("NetworkMode.IsContainer for %v should have been %v but was %v", networkMode, state[3], networkMode.IsContainer())
    78  		}
    79  		if networkMode.IsNone() != state[4] {
    80  			t.Fatalf("NetworkMode.IsNone for %v should have been %v but was %v", networkMode, state[4], networkMode.IsNone())
    81  		}
    82  		if networkMode.IsDefault() != state[5] {
    83  			t.Fatalf("NetworkMode.IsDefault for %v should have been %v but was %v", networkMode, state[5], networkMode.IsDefault())
    84  		}
    85  		if networkMode.NetworkName() != networkModeNames[networkMode] {
    86  			t.Fatalf("Expected name %v, got %v", networkModeNames[networkMode], networkMode.NetworkName())
    87  		}
    88  	}
    89  }
    90  
    91  func TestIpcModeTest(t *testing.T) {
    92  	ipcModes := map[container.IpcMode]struct {
    93  		private   bool
    94  		host      bool
    95  		container bool
    96  		shareable bool
    97  		valid     bool
    98  		ctrName   string
    99  	}{
   100  		"":                      {valid: true},
   101  		"private":               {private: true, valid: true},
   102  		"something:weird":       {},
   103  		":weird":                {},
   104  		"host":                  {host: true, valid: true},
   105  		"container":             {},
   106  		"container:":            {container: true, valid: true, ctrName: ""},
   107  		"container:name":        {container: true, valid: true, ctrName: "name"},
   108  		"container:name1:name2": {container: true, valid: true, ctrName: "name1:name2"},
   109  		"shareable":             {shareable: true, valid: true},
   110  	}
   111  
   112  	for ipcMode, state := range ipcModes {
   113  		assert.Check(t, is.Equal(state.private, ipcMode.IsPrivate()), "IpcMode.IsPrivate() parsing failed for %q", ipcMode)
   114  		assert.Check(t, is.Equal(state.host, ipcMode.IsHost()), "IpcMode.IsHost()  parsing failed for %q", ipcMode)
   115  		assert.Check(t, is.Equal(state.container, ipcMode.IsContainer()), "IpcMode.IsContainer()  parsing failed for %q", ipcMode)
   116  		assert.Check(t, is.Equal(state.shareable, ipcMode.IsShareable()), "IpcMode.IsShareable()  parsing failed for %q", ipcMode)
   117  		assert.Check(t, is.Equal(state.valid, ipcMode.Valid()), "IpcMode.Valid()  parsing failed for %q", ipcMode)
   118  		assert.Check(t, is.Equal(state.ctrName, ipcMode.Container()), "IpcMode.Container() parsing failed for %q", ipcMode)
   119  	}
   120  }
   121  
   122  func TestUTSModeTest(t *testing.T) {
   123  	utsModes := map[container.UTSMode][]bool{
   124  		// private, host, valid
   125  		"":                {true, false, true},
   126  		"something:weird": {true, false, false},
   127  		"host":            {false, true, true},
   128  		"host:name":       {true, false, true},
   129  	}
   130  	for utsMode, state := range utsModes {
   131  		if utsMode.IsPrivate() != state[0] {
   132  			t.Fatalf("UtsMode.IsPrivate for %v should have been %v but was %v", utsMode, state[0], utsMode.IsPrivate())
   133  		}
   134  		if utsMode.IsHost() != state[1] {
   135  			t.Fatalf("UtsMode.IsHost for %v should have been %v but was %v", utsMode, state[1], utsMode.IsHost())
   136  		}
   137  		if utsMode.Valid() != state[2] {
   138  			t.Fatalf("UtsMode.Valid for %v should have been %v but was %v", utsMode, state[2], utsMode.Valid())
   139  		}
   140  	}
   141  }
   142  
   143  func TestUsernsModeTest(t *testing.T) {
   144  	usrensMode := map[container.UsernsMode][]bool{
   145  		// private, host, valid
   146  		"":                {true, false, true},
   147  		"something:weird": {true, false, false},
   148  		"host":            {false, true, true},
   149  		"host:name":       {true, false, true},
   150  	}
   151  	for usernsMode, state := range usrensMode {
   152  		if usernsMode.IsPrivate() != state[0] {
   153  			t.Fatalf("UsernsMode.IsPrivate for %v should have been %v but was %v", usernsMode, state[0], usernsMode.IsPrivate())
   154  		}
   155  		if usernsMode.IsHost() != state[1] {
   156  			t.Fatalf("UsernsMode.IsHost for %v should have been %v but was %v", usernsMode, state[1], usernsMode.IsHost())
   157  		}
   158  		if usernsMode.Valid() != state[2] {
   159  			t.Fatalf("UsernsMode.Valid for %v should have been %v but was %v", usernsMode, state[2], usernsMode.Valid())
   160  		}
   161  	}
   162  }
   163  
   164  func TestPidModeTest(t *testing.T) {
   165  	pidModes := map[container.PidMode][]bool{
   166  		// private, host, valid
   167  		"":                {true, false, true},
   168  		"something:weird": {true, false, false},
   169  		"host":            {false, true, true},
   170  		"host:name":       {true, false, true},
   171  	}
   172  	for pidMode, state := range pidModes {
   173  		if pidMode.IsPrivate() != state[0] {
   174  			t.Fatalf("PidMode.IsPrivate for %v should have been %v but was %v", pidMode, state[0], pidMode.IsPrivate())
   175  		}
   176  		if pidMode.IsHost() != state[1] {
   177  			t.Fatalf("PidMode.IsHost for %v should have been %v but was %v", pidMode, state[1], pidMode.IsHost())
   178  		}
   179  		if pidMode.Valid() != state[2] {
   180  			t.Fatalf("PidMode.Valid for %v should have been %v but was %v", pidMode, state[2], pidMode.Valid())
   181  		}
   182  	}
   183  }
   184  
   185  func TestRestartPolicy(t *testing.T) {
   186  	restartPolicies := map[container.RestartPolicy][]bool{
   187  		// none, always, failure
   188  		{}: {true, false, false},
   189  		{Name: "something", MaximumRetryCount: 0}:  {false, false, false},
   190  		{Name: "no", MaximumRetryCount: 0}:         {true, false, false},
   191  		{Name: "always", MaximumRetryCount: 0}:     {false, true, false},
   192  		{Name: "on-failure", MaximumRetryCount: 0}: {false, false, true},
   193  	}
   194  	for restartPolicy, state := range restartPolicies {
   195  		if restartPolicy.IsNone() != state[0] {
   196  			t.Fatalf("RestartPolicy.IsNone for %v should have been %v but was %v", restartPolicy, state[0], restartPolicy.IsNone())
   197  		}
   198  		if restartPolicy.IsAlways() != state[1] {
   199  			t.Fatalf("RestartPolicy.IsAlways for %v should have been %v but was %v", restartPolicy, state[1], restartPolicy.IsAlways())
   200  		}
   201  		if restartPolicy.IsOnFailure() != state[2] {
   202  			t.Fatalf("RestartPolicy.IsOnFailure for %v should have been %v but was %v", restartPolicy, state[2], restartPolicy.IsOnFailure())
   203  		}
   204  	}
   205  }
   206  func TestDecodeHostConfig(t *testing.T) {
   207  	fixtures := []struct {
   208  		file string
   209  	}{
   210  		{"fixtures/unix/container_hostconfig_1_14.json"},
   211  		{"fixtures/unix/container_hostconfig_1_19.json"},
   212  	}
   213  
   214  	for _, f := range fixtures {
   215  		b, err := ioutil.ReadFile(f.file)
   216  		if err != nil {
   217  			t.Fatal(err)
   218  		}
   219  
   220  		c, err := decodeHostConfig(bytes.NewReader(b))
   221  		if err != nil {
   222  			t.Fatal(fmt.Errorf("Error parsing %s: %v", f, err))
   223  		}
   224  
   225  		assert.Check(t, !c.Privileged)
   226  
   227  		if l := len(c.Binds); l != 1 {
   228  			t.Fatalf("Expected 1 bind, found %d\n", l)
   229  		}
   230  
   231  		if len(c.CapAdd) != 1 && c.CapAdd[0] != "NET_ADMIN" {
   232  			t.Fatalf("Expected CapAdd NET_ADMIN, got %v", c.CapAdd)
   233  		}
   234  
   235  		if len(c.CapDrop) != 1 && c.CapDrop[0] != "NET_ADMIN" {
   236  			t.Fatalf("Expected CapDrop NET_ADMIN, got %v", c.CapDrop)
   237  		}
   238  	}
   239  }
   240  
   241  func TestValidateResources(t *testing.T) {
   242  	type resourceTest struct {
   243  		ConfigCPURealtimePeriod   int64
   244  		ConfigCPURealtimeRuntime  int64
   245  		SysInfoCPURealtimePeriod  bool
   246  		SysInfoCPURealtimeRuntime bool
   247  		ErrorExpected             bool
   248  		FailureMsg                string
   249  	}
   250  
   251  	tests := []resourceTest{
   252  		{
   253  			ConfigCPURealtimePeriod:   1000,
   254  			ConfigCPURealtimeRuntime:  1000,
   255  			SysInfoCPURealtimePeriod:  true,
   256  			SysInfoCPURealtimeRuntime: true,
   257  			ErrorExpected:             false,
   258  			FailureMsg:                "Expected valid configuration",
   259  		},
   260  		{
   261  			ConfigCPURealtimePeriod:   5000,
   262  			ConfigCPURealtimeRuntime:  5000,
   263  			SysInfoCPURealtimePeriod:  false,
   264  			SysInfoCPURealtimeRuntime: true,
   265  			ErrorExpected:             true,
   266  			FailureMsg:                "Expected failure when cpu-rt-period is set but kernel doesn't support it",
   267  		},
   268  		{
   269  			ConfigCPURealtimePeriod:   5000,
   270  			ConfigCPURealtimeRuntime:  5000,
   271  			SysInfoCPURealtimePeriod:  true,
   272  			SysInfoCPURealtimeRuntime: false,
   273  			ErrorExpected:             true,
   274  			FailureMsg:                "Expected failure when cpu-rt-runtime is set but kernel doesn't support it",
   275  		},
   276  		{
   277  			ConfigCPURealtimePeriod:   5000,
   278  			ConfigCPURealtimeRuntime:  10000,
   279  			SysInfoCPURealtimePeriod:  true,
   280  			SysInfoCPURealtimeRuntime: false,
   281  			ErrorExpected:             true,
   282  			FailureMsg:                "Expected failure when cpu-rt-runtime is greater than cpu-rt-period",
   283  		},
   284  	}
   285  
   286  	for _, rt := range tests {
   287  		var hc container.HostConfig
   288  		hc.Resources.CPURealtimePeriod = rt.ConfigCPURealtimePeriod
   289  		hc.Resources.CPURealtimeRuntime = rt.ConfigCPURealtimeRuntime
   290  
   291  		var si sysinfo.SysInfo
   292  		si.CPURealtimePeriod = rt.SysInfoCPURealtimePeriod
   293  		si.CPURealtimeRuntime = rt.SysInfoCPURealtimeRuntime
   294  
   295  		if err := validateResources(&hc, &si); (err != nil) != rt.ErrorExpected {
   296  			t.Fatal(rt.FailureMsg, err)
   297  		}
   298  	}
   299  }