github.com/kaisenlinux/docker@v0.0.0-20230510090727-ea55db55fac7/swarmkit/agent/exec/dockerapi/container_test.go (about)

     1  package dockerapi
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  	"time"
     7  
     8  	enginecontainer "github.com/docker/docker/api/types/container"
     9  	enginemount "github.com/docker/docker/api/types/mount"
    10  	"github.com/docker/docker/api/types/strslice"
    11  	"github.com/docker/go-units"
    12  	"github.com/docker/swarmkit/api"
    13  	gogotypes "github.com/gogo/protobuf/types"
    14  )
    15  
    16  func TestVolumesAndBinds(t *testing.T) {
    17  	type testCase struct {
    18  		explain string
    19  		config  api.Mount
    20  		x       enginemount.Mount
    21  	}
    22  
    23  	cases := []testCase{
    24  		{"Simple bind mount", api.Mount{Type: api.MountTypeBind, Source: "/banana", Target: "/kerfluffle"},
    25  			enginemount.Mount{Type: enginemount.TypeBind, Source: "/banana", Target: "/kerfluffle"}},
    26  		{"Bind mound with propagation", api.Mount{Type: api.MountTypeBind, Source: "/banana", Target: "/kerfluffle", BindOptions: &api.Mount_BindOptions{Propagation: api.MountPropagationRPrivate}},
    27  			enginemount.Mount{Type: enginemount.TypeBind, Source: "/banana", Target: "/kerfluffle", BindOptions: &enginemount.BindOptions{Propagation: enginemount.PropagationRPrivate}}},
    28  		{"Simple volume with source", api.Mount{Type: api.MountTypeVolume, Source: "banana", Target: "/kerfluffle"},
    29  			enginemount.Mount{Type: enginemount.TypeVolume, Source: "banana", Target: "/kerfluffle"}},
    30  		{"Volume with options", api.Mount{Type: api.MountTypeVolume, Source: "banana", Target: "/kerfluffle", VolumeOptions: &api.Mount_VolumeOptions{NoCopy: true}},
    31  			enginemount.Mount{Type: enginemount.TypeVolume, Source: "banana", Target: "/kerfluffle", VolumeOptions: &enginemount.VolumeOptions{NoCopy: true}}},
    32  		{"Volume with no source", api.Mount{Type: api.MountTypeVolume, Target: "/kerfluffle"},
    33  			enginemount.Mount{Type: enginemount.TypeVolume, Target: "/kerfluffle"}},
    34  		{"Named pipe using Windows format", api.Mount{Type: api.MountTypeNamedPipe, Source: `\\.\pipe\foo`, Target: `\\.\pipe\foo`},
    35  			enginemount.Mount{Type: enginemount.TypeNamedPipe, Source: `\\.\pipe\foo`, Target: `\\.\pipe\foo`}},
    36  		{"Named pipe using Unix format", api.Mount{Type: api.MountTypeNamedPipe, Source: "//./pipe/foo", Target: "//./pipe/foo"},
    37  			enginemount.Mount{Type: enginemount.TypeNamedPipe, Source: "//./pipe/foo", Target: "//./pipe/foo"}},
    38  	}
    39  
    40  	for _, c := range cases {
    41  		cfg := containerConfig{
    42  			task: &api.Task{
    43  				Spec: api.TaskSpec{Runtime: &api.TaskSpec_Container{
    44  					Container: &api.ContainerSpec{
    45  						Mounts: []api.Mount{c.config},
    46  					},
    47  				}},
    48  			},
    49  		}
    50  
    51  		if vols := cfg.config().Volumes; len(vols) != 0 {
    52  			t.Fatalf("expected no anonymous volumes: %v", vols)
    53  		}
    54  		mounts := cfg.hostConfig().Mounts
    55  		if len(mounts) != 1 {
    56  			t.Fatalf("expected 1 mount: %v", mounts)
    57  		}
    58  
    59  		if !reflect.DeepEqual(mounts[0], c.x) {
    60  			t.Log(c.explain)
    61  			t.Logf("expected: %+v, got: %+v", c.x, mounts[0])
    62  			switch c.x.Type {
    63  			case enginemount.TypeVolume:
    64  				t.Logf("expected volume opts: %+v, got: %+v", c.x.VolumeOptions, mounts[0].VolumeOptions)
    65  				if c.x.VolumeOptions.DriverConfig != nil {
    66  					t.Logf("expected volume driver config: %+v, got: %+v", c.x.VolumeOptions.DriverConfig, mounts[0].VolumeOptions.DriverConfig)
    67  				}
    68  			case enginemount.TypeBind:
    69  				t.Logf("expected bind opts: %+v, got: %+v", c.x.BindOptions, mounts[0].BindOptions)
    70  			}
    71  			t.Fail()
    72  		}
    73  	}
    74  }
    75  
    76  func TestTmpfsOptions(t *testing.T) {
    77  	type testCase struct {
    78  		explain string
    79  		config  api.Mount
    80  		x       string
    81  	}
    82  
    83  	cases := []testCase{
    84  		{"Tmpfs mount with exec option", api.Mount{Type: api.MountTypeTmpfs, Target: "/kerfluffle", TmpfsOptions: &api.Mount_TmpfsOptions{Options: "exec"}}, "exec"},
    85  		{"Tmpfs mount with noexec option", api.Mount{Type: api.MountTypeTmpfs, Target: "/kerfluffle", TmpfsOptions: &api.Mount_TmpfsOptions{Options: "noexec"}}, "noexec"},
    86  	}
    87  
    88  	for _, c := range cases {
    89  		cfg := containerConfig{
    90  			task: &api.Task{
    91  				Spec: api.TaskSpec{Runtime: &api.TaskSpec_Container{
    92  					Container: &api.ContainerSpec{
    93  						Mounts: []api.Mount{c.config},
    94  					},
    95  				}},
    96  			},
    97  		}
    98  
    99  		mountOpts, ok := cfg.hostConfig().Tmpfs["/kerfluffle"]
   100  		if !ok {
   101  			t.Fatalf("expected 1 mount, found none")
   102  		}
   103  
   104  		if mountOpts != c.x {
   105  			t.Log(c.explain)
   106  			t.Logf("expected Tmpfs opts: %+v, got: %+v", c.x, mountOpts)
   107  			t.Fail()
   108  		}
   109  	}
   110  }
   111  
   112  func TestHealthcheck(t *testing.T) {
   113  	c := containerConfig{
   114  		task: &api.Task{
   115  			Spec: api.TaskSpec{Runtime: &api.TaskSpec_Container{
   116  				Container: &api.ContainerSpec{
   117  					Healthcheck: &api.HealthConfig{
   118  						Test:        []string{"a", "b", "c"},
   119  						Interval:    gogotypes.DurationProto(time.Second),
   120  						Timeout:     gogotypes.DurationProto(time.Minute),
   121  						Retries:     10,
   122  						StartPeriod: gogotypes.DurationProto(time.Minute),
   123  					},
   124  				},
   125  			}},
   126  		},
   127  	}
   128  	config := c.config()
   129  	expected := &enginecontainer.HealthConfig{
   130  		Test:        []string{"a", "b", "c"},
   131  		Interval:    time.Second,
   132  		Timeout:     time.Minute,
   133  		Retries:     10,
   134  		StartPeriod: time.Minute,
   135  	}
   136  	if !reflect.DeepEqual(config.Healthcheck, expected) {
   137  		t.Fatalf("expected %#v, got %#v", expected, config.Healthcheck)
   138  	}
   139  }
   140  
   141  func TestExtraHosts(t *testing.T) {
   142  	c := containerConfig{
   143  		task: &api.Task{
   144  			Spec: api.TaskSpec{Runtime: &api.TaskSpec_Container{
   145  				Container: &api.ContainerSpec{
   146  					Hosts: []string{
   147  						"1.2.3.4 example.com",
   148  						"5.6.7.8 example.org",
   149  						"127.0.0.1 mylocal",
   150  					},
   151  				},
   152  			}},
   153  		},
   154  	}
   155  
   156  	hostConfig := c.hostConfig()
   157  	if len(hostConfig.ExtraHosts) != 3 {
   158  		t.Fatalf("expected 3 extra hosts: %v", hostConfig.ExtraHosts)
   159  	}
   160  
   161  	expected := "example.com:1.2.3.4"
   162  	actual := hostConfig.ExtraHosts[0]
   163  	if actual != expected {
   164  		t.Fatalf("expected %s, got %s", expected, actual)
   165  	}
   166  
   167  	expected = "example.org:5.6.7.8"
   168  	actual = hostConfig.ExtraHosts[1]
   169  	if actual != expected {
   170  		t.Fatalf("expected %s, got %s", expected, actual)
   171  	}
   172  
   173  	expected = "mylocal:127.0.0.1"
   174  	actual = hostConfig.ExtraHosts[2]
   175  	if actual != expected {
   176  		t.Fatalf("expected %s, got %s", expected, actual)
   177  	}
   178  }
   179  
   180  func TestPidLimit(t *testing.T) {
   181  	c := containerConfig{
   182  		task: &api.Task{
   183  			Spec: api.TaskSpec{Runtime: &api.TaskSpec_Container{
   184  				Container: &api.ContainerSpec{
   185  					PidsLimit: 10,
   186  				},
   187  			}},
   188  		},
   189  	}
   190  
   191  	hostConfig := c.hostConfig()
   192  	expected := int64(10)
   193  	actual := hostConfig.PidsLimit
   194  
   195  	if expected != *actual {
   196  		t.Fatalf("expected %d, got %d", expected, actual)
   197  	}
   198  }
   199  
   200  func TestStopSignal(t *testing.T) {
   201  	c := containerConfig{
   202  		task: &api.Task{
   203  			Spec: api.TaskSpec{Runtime: &api.TaskSpec_Container{
   204  				Container: &api.ContainerSpec{
   205  					StopSignal: "SIGWINCH",
   206  				},
   207  			}},
   208  		},
   209  	}
   210  
   211  	expected := "SIGWINCH"
   212  	actual := c.config().StopSignal
   213  	if actual != expected {
   214  		t.Fatalf("expected %s, got %s", expected, actual)
   215  	}
   216  }
   217  
   218  func TestInit(t *testing.T) {
   219  	c := containerConfig{
   220  		task: &api.Task{
   221  			Spec: api.TaskSpec{Runtime: &api.TaskSpec_Container{
   222  				Container: &api.ContainerSpec{
   223  					StopSignal: "SIGWINCH",
   224  				},
   225  			}},
   226  		},
   227  	}
   228  	var expected *bool
   229  	actual := c.hostConfig().Init
   230  	if actual != expected {
   231  		t.Fatalf("expected %v, got %v", expected, actual)
   232  	}
   233  	c.task.Spec.GetContainer().Init = &gogotypes.BoolValue{
   234  		Value: true,
   235  	}
   236  	actual = c.hostConfig().Init
   237  	if actual == nil || !*actual {
   238  		t.Fatalf("expected &true, got %v", actual)
   239  	}
   240  }
   241  
   242  func TestIsolation(t *testing.T) {
   243  	c := containerConfig{
   244  		task: &api.Task{
   245  			Spec: api.TaskSpec{
   246  				Runtime: &api.TaskSpec_Container{
   247  					Container: &api.ContainerSpec{
   248  						Isolation: api.ContainerIsolationHyperV,
   249  					},
   250  				},
   251  			},
   252  		},
   253  	}
   254  
   255  	expected := "hyperv"
   256  	actual := string(c.hostConfig().Isolation)
   257  	if actual != expected {
   258  		t.Fatalf("expected %s, got %s", expected, actual)
   259  	}
   260  }
   261  
   262  func TestCapabilityAdd(t *testing.T) {
   263  	c := containerConfig{
   264  		task: &api.Task{
   265  			Spec: api.TaskSpec{
   266  				Runtime: &api.TaskSpec_Container{
   267  					Container: &api.ContainerSpec{
   268  						CapabilityAdd: []string{"CAP_NET_RAW", "CAP_SYS_CHROOT"},
   269  					},
   270  				},
   271  			},
   272  		},
   273  	}
   274  
   275  	expected := strslice.StrSlice{"CAP_NET_RAW", "CAP_SYS_CHROOT"}
   276  	actual := c.hostConfig().CapAdd
   277  	if !reflect.DeepEqual(actual, expected) {
   278  		t.Fatalf("expected %s, got %s", expected, actual)
   279  	}
   280  }
   281  
   282  func TestCapabilityDrop(t *testing.T) {
   283  	c := containerConfig{
   284  		task: &api.Task{
   285  			Spec: api.TaskSpec{
   286  				Runtime: &api.TaskSpec_Container{
   287  					Container: &api.ContainerSpec{
   288  						CapabilityDrop: []string{"CAP_KILL"},
   289  					},
   290  				},
   291  			},
   292  		},
   293  	}
   294  
   295  	expected := strslice.StrSlice{"CAP_KILL"}
   296  	actual := c.hostConfig().CapDrop
   297  	if !reflect.DeepEqual(actual, expected) {
   298  		t.Fatalf("expected %s, got %s", expected, actual)
   299  	}
   300  }
   301  
   302  func TestUlimits(t *testing.T) {
   303  	c := containerConfig{
   304  		task: &api.Task{
   305  			Spec: api.TaskSpec{
   306  				Runtime: &api.TaskSpec_Container{
   307  					Container: &api.ContainerSpec{
   308  						Ulimits: []*api.ContainerSpec_Ulimit{
   309  							{
   310  								Name: "nofile",
   311  								Soft: 1024,
   312  								Hard: 2048,
   313  							},
   314  						},
   315  					},
   316  				},
   317  			},
   318  		},
   319  	}
   320  
   321  	expected := []*units.Ulimit{
   322  		{
   323  			Name: "nofile",
   324  			Soft: 1024,
   325  			Hard: 2048,
   326  		},
   327  	}
   328  	actual := c.resources().Ulimits
   329  	if !reflect.DeepEqual(actual, expected) {
   330  		t.Fatalf("expected %v, got %v", expected, actual)
   331  	}
   332  }