github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/daemon/daemon_unix_test.go (about) 1 // +build !windows 2 3 package daemon 4 5 import ( 6 "errors" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "testing" 11 12 containertypes "github.com/docker/docker/api/types/container" 13 "github.com/docker/docker/container" 14 "github.com/docker/docker/daemon/config" 15 "github.com/docker/docker/pkg/idtools" 16 "github.com/docker/docker/volume" 17 "github.com/docker/docker/volume/drivers" 18 "github.com/docker/docker/volume/local" 19 "github.com/docker/docker/volume/store" 20 "github.com/stretchr/testify/require" 21 ) 22 23 type fakeContainerGetter struct { 24 containers map[string]*container.Container 25 } 26 27 func (f *fakeContainerGetter) GetContainer(cid string) (*container.Container, error) { 28 container, ok := f.containers[cid] 29 if !ok { 30 return nil, errors.New("container not found") 31 } 32 return container, nil 33 } 34 35 // Unix test as uses settings which are not available on Windows 36 func TestAdjustSharedNamespaceContainerName(t *testing.T) { 37 fakeID := "abcdef1234567890" 38 hostConfig := &containertypes.HostConfig{ 39 IpcMode: containertypes.IpcMode("container:base"), 40 PidMode: containertypes.PidMode("container:base"), 41 NetworkMode: containertypes.NetworkMode("container:base"), 42 } 43 containerStore := &fakeContainerGetter{} 44 containerStore.containers = make(map[string]*container.Container) 45 containerStore.containers["base"] = &container.Container{ 46 ID: fakeID, 47 } 48 49 adaptSharedNamespaceContainer(containerStore, hostConfig) 50 if hostConfig.IpcMode != containertypes.IpcMode("container:"+fakeID) { 51 t.Errorf("Expected IpcMode to be container:%s", fakeID) 52 } 53 if hostConfig.PidMode != containertypes.PidMode("container:"+fakeID) { 54 t.Errorf("Expected PidMode to be container:%s", fakeID) 55 } 56 if hostConfig.NetworkMode != containertypes.NetworkMode("container:"+fakeID) { 57 t.Errorf("Expected NetworkMode to be container:%s", fakeID) 58 } 59 } 60 61 // Unix test as uses settings which are not available on Windows 62 func TestAdjustCPUShares(t *testing.T) { 63 tmp, err := ioutil.TempDir("", "docker-daemon-unix-test-") 64 if err != nil { 65 t.Fatal(err) 66 } 67 defer os.RemoveAll(tmp) 68 daemon := &Daemon{ 69 repository: tmp, 70 root: tmp, 71 } 72 73 hostConfig := &containertypes.HostConfig{ 74 Resources: containertypes.Resources{CPUShares: linuxMinCPUShares - 1}, 75 } 76 daemon.adaptContainerSettings(hostConfig, true) 77 if hostConfig.CPUShares != linuxMinCPUShares { 78 t.Errorf("Expected CPUShares to be %d", linuxMinCPUShares) 79 } 80 81 hostConfig.CPUShares = linuxMaxCPUShares + 1 82 daemon.adaptContainerSettings(hostConfig, true) 83 if hostConfig.CPUShares != linuxMaxCPUShares { 84 t.Errorf("Expected CPUShares to be %d", linuxMaxCPUShares) 85 } 86 87 hostConfig.CPUShares = 0 88 daemon.adaptContainerSettings(hostConfig, true) 89 if hostConfig.CPUShares != 0 { 90 t.Error("Expected CPUShares to be unchanged") 91 } 92 93 hostConfig.CPUShares = 1024 94 daemon.adaptContainerSettings(hostConfig, true) 95 if hostConfig.CPUShares != 1024 { 96 t.Error("Expected CPUShares to be unchanged") 97 } 98 } 99 100 // Unix test as uses settings which are not available on Windows 101 func TestAdjustCPUSharesNoAdjustment(t *testing.T) { 102 tmp, err := ioutil.TempDir("", "docker-daemon-unix-test-") 103 if err != nil { 104 t.Fatal(err) 105 } 106 defer os.RemoveAll(tmp) 107 daemon := &Daemon{ 108 repository: tmp, 109 root: tmp, 110 } 111 112 hostConfig := &containertypes.HostConfig{ 113 Resources: containertypes.Resources{CPUShares: linuxMinCPUShares - 1}, 114 } 115 daemon.adaptContainerSettings(hostConfig, false) 116 if hostConfig.CPUShares != linuxMinCPUShares-1 { 117 t.Errorf("Expected CPUShares to be %d", linuxMinCPUShares-1) 118 } 119 120 hostConfig.CPUShares = linuxMaxCPUShares + 1 121 daemon.adaptContainerSettings(hostConfig, false) 122 if hostConfig.CPUShares != linuxMaxCPUShares+1 { 123 t.Errorf("Expected CPUShares to be %d", linuxMaxCPUShares+1) 124 } 125 126 hostConfig.CPUShares = 0 127 daemon.adaptContainerSettings(hostConfig, false) 128 if hostConfig.CPUShares != 0 { 129 t.Error("Expected CPUShares to be unchanged") 130 } 131 132 hostConfig.CPUShares = 1024 133 daemon.adaptContainerSettings(hostConfig, false) 134 if hostConfig.CPUShares != 1024 { 135 t.Error("Expected CPUShares to be unchanged") 136 } 137 } 138 139 // Unix test as uses settings which are not available on Windows 140 func TestParseSecurityOptWithDeprecatedColon(t *testing.T) { 141 container := &container.Container{} 142 config := &containertypes.HostConfig{} 143 144 // test apparmor 145 config.SecurityOpt = []string{"apparmor=test_profile"} 146 if err := parseSecurityOpt(container, config); err != nil { 147 t.Fatalf("Unexpected parseSecurityOpt error: %v", err) 148 } 149 if container.AppArmorProfile != "test_profile" { 150 t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", container.AppArmorProfile) 151 } 152 153 // test seccomp 154 sp := "/path/to/seccomp_test.json" 155 config.SecurityOpt = []string{"seccomp=" + sp} 156 if err := parseSecurityOpt(container, config); err != nil { 157 t.Fatalf("Unexpected parseSecurityOpt error: %v", err) 158 } 159 if container.SeccompProfile != sp { 160 t.Fatalf("Unexpected AppArmorProfile, expected: %q, got %q", sp, container.SeccompProfile) 161 } 162 163 // test valid label 164 config.SecurityOpt = []string{"label=user:USER"} 165 if err := parseSecurityOpt(container, config); err != nil { 166 t.Fatalf("Unexpected parseSecurityOpt error: %v", err) 167 } 168 169 // test invalid label 170 config.SecurityOpt = []string{"label"} 171 if err := parseSecurityOpt(container, config); err == nil { 172 t.Fatal("Expected parseSecurityOpt error, got nil") 173 } 174 175 // test invalid opt 176 config.SecurityOpt = []string{"test"} 177 if err := parseSecurityOpt(container, config); err == nil { 178 t.Fatal("Expected parseSecurityOpt error, got nil") 179 } 180 } 181 182 func TestParseSecurityOpt(t *testing.T) { 183 container := &container.Container{} 184 config := &containertypes.HostConfig{} 185 186 // test apparmor 187 config.SecurityOpt = []string{"apparmor=test_profile"} 188 if err := parseSecurityOpt(container, config); err != nil { 189 t.Fatalf("Unexpected parseSecurityOpt error: %v", err) 190 } 191 if container.AppArmorProfile != "test_profile" { 192 t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", container.AppArmorProfile) 193 } 194 195 // test seccomp 196 sp := "/path/to/seccomp_test.json" 197 config.SecurityOpt = []string{"seccomp=" + sp} 198 if err := parseSecurityOpt(container, config); err != nil { 199 t.Fatalf("Unexpected parseSecurityOpt error: %v", err) 200 } 201 if container.SeccompProfile != sp { 202 t.Fatalf("Unexpected SeccompProfile, expected: %q, got %q", sp, container.SeccompProfile) 203 } 204 205 // test valid label 206 config.SecurityOpt = []string{"label=user:USER"} 207 if err := parseSecurityOpt(container, config); err != nil { 208 t.Fatalf("Unexpected parseSecurityOpt error: %v", err) 209 } 210 211 // test invalid label 212 config.SecurityOpt = []string{"label"} 213 if err := parseSecurityOpt(container, config); err == nil { 214 t.Fatal("Expected parseSecurityOpt error, got nil") 215 } 216 217 // test invalid opt 218 config.SecurityOpt = []string{"test"} 219 if err := parseSecurityOpt(container, config); err == nil { 220 t.Fatal("Expected parseSecurityOpt error, got nil") 221 } 222 } 223 224 func TestParseNNPSecurityOptions(t *testing.T) { 225 daemon := &Daemon{ 226 configStore: &config.Config{NoNewPrivileges: true}, 227 } 228 container := &container.Container{} 229 config := &containertypes.HostConfig{} 230 231 // test NNP when "daemon:true" and "no-new-privileges=false"" 232 config.SecurityOpt = []string{"no-new-privileges=false"} 233 234 if err := daemon.parseSecurityOpt(container, config); err != nil { 235 t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err) 236 } 237 if container.NoNewPrivileges { 238 t.Fatalf("container.NoNewPrivileges should be FALSE: %v", container.NoNewPrivileges) 239 } 240 241 // test NNP when "daemon:false" and "no-new-privileges=true"" 242 daemon.configStore.NoNewPrivileges = false 243 config.SecurityOpt = []string{"no-new-privileges=true"} 244 245 if err := daemon.parseSecurityOpt(container, config); err != nil { 246 t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err) 247 } 248 if !container.NoNewPrivileges { 249 t.Fatalf("container.NoNewPrivileges should be TRUE: %v", container.NoNewPrivileges) 250 } 251 } 252 253 func TestNetworkOptions(t *testing.T) { 254 daemon := &Daemon{} 255 dconfigCorrect := &config.Config{ 256 CommonConfig: config.CommonConfig{ 257 ClusterStore: "consul://localhost:8500", 258 ClusterAdvertise: "192.168.0.1:8000", 259 }, 260 } 261 262 if _, err := daemon.networkOptions(dconfigCorrect, nil, nil); err != nil { 263 t.Fatalf("Expect networkOptions success, got error: %v", err) 264 } 265 266 dconfigWrong := &config.Config{ 267 CommonConfig: config.CommonConfig{ 268 ClusterStore: "consul://localhost:8500://test://bbb", 269 }, 270 } 271 272 if _, err := daemon.networkOptions(dconfigWrong, nil, nil); err == nil { 273 t.Fatal("Expected networkOptions error, got nil") 274 } 275 } 276 277 func TestMigratePre17Volumes(t *testing.T) { 278 rootDir, err := ioutil.TempDir("", "test-daemon-volumes") 279 if err != nil { 280 t.Fatal(err) 281 } 282 defer os.RemoveAll(rootDir) 283 284 volumeRoot := filepath.Join(rootDir, "volumes") 285 err = os.MkdirAll(volumeRoot, 0755) 286 if err != nil { 287 t.Fatal(err) 288 } 289 290 containerRoot := filepath.Join(rootDir, "containers") 291 cid := "1234" 292 err = os.MkdirAll(filepath.Join(containerRoot, cid), 0755) 293 require.NoError(t, err) 294 295 vid := "5678" 296 vfsPath := filepath.Join(rootDir, "vfs", "dir", vid) 297 err = os.MkdirAll(vfsPath, 0755) 298 require.NoError(t, err) 299 300 config := []byte(` 301 { 302 "ID": "` + cid + `", 303 "Volumes": { 304 "/foo": "` + vfsPath + `", 305 "/bar": "/foo", 306 "/quux": "/quux" 307 }, 308 "VolumesRW": { 309 "/foo": true, 310 "/bar": true, 311 "/quux": false 312 } 313 } 314 `) 315 316 volStore, err := store.New(volumeRoot) 317 if err != nil { 318 t.Fatal(err) 319 } 320 drv, err := local.New(volumeRoot, idtools.IDPair{UID: 0, GID: 0}) 321 if err != nil { 322 t.Fatal(err) 323 } 324 volumedrivers.Register(drv, volume.DefaultDriverName) 325 326 daemon := &Daemon{ 327 root: rootDir, 328 repository: containerRoot, 329 volumes: volStore, 330 } 331 err = ioutil.WriteFile(filepath.Join(containerRoot, cid, "config.v2.json"), config, 600) 332 if err != nil { 333 t.Fatal(err) 334 } 335 c, err := daemon.load(cid) 336 if err != nil { 337 t.Fatal(err) 338 } 339 if err := daemon.verifyVolumesInfo(c); err != nil { 340 t.Fatal(err) 341 } 342 343 expected := map[string]volume.MountPoint{ 344 "/foo": {Destination: "/foo", RW: true, Name: vid}, 345 "/bar": {Source: "/foo", Destination: "/bar", RW: true}, 346 "/quux": {Source: "/quux", Destination: "/quux", RW: false}, 347 } 348 for id, mp := range c.MountPoints { 349 x, exists := expected[id] 350 if !exists { 351 t.Fatal("volume not migrated") 352 } 353 if mp.Source != x.Source || mp.Destination != x.Destination || mp.RW != x.RW || mp.Name != x.Name { 354 t.Fatalf("got unexpected mountpoint, expected: %+v, got: %+v", x, mp) 355 } 356 } 357 }