github.com/tri-adam/singularity@v3.1.1+incompatible/cmd/singularity/docker_test.go (about)

     1  // Copyright (c) 2018, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package main
     7  
     8  import (
     9  	"fmt"
    10  	"os"
    11  	"os/exec"
    12  	"path"
    13  	"strings"
    14  	"testing"
    15  
    16  	"github.com/sylabs/singularity/internal/pkg/test"
    17  	"golang.org/x/sys/unix"
    18  )
    19  
    20  func TestDocker(t *testing.T) {
    21  	tests := []struct {
    22  		name          string
    23  		imagePath     string
    24  		expectSuccess bool
    25  	}{
    26  		{"BusyBox", "docker://busybox", true},
    27  		{"DoesNotExist", "docker://something_that_doesnt_exist_ever", false},
    28  	}
    29  
    30  	for _, tt := range tests {
    31  		t.Run(tt.name, test.WithPrivilege(func(t *testing.T) {
    32  			imagePath := path.Join(testDir, "container")
    33  			defer os.Remove(imagePath)
    34  
    35  			b, err := imageBuild(buildOpts{}, imagePath, tt.imagePath)
    36  			if tt.expectSuccess {
    37  				if err != nil {
    38  					t.Log(string(b))
    39  					t.Fatalf("unexpected failure: %v", err)
    40  				}
    41  				imageVerify(t, imagePath, false)
    42  			} else if !tt.expectSuccess && err == nil {
    43  				t.Log(string(b))
    44  				t.Fatal("unexpected success")
    45  			}
    46  		}))
    47  	}
    48  }
    49  
    50  // AUFS sanity tests
    51  func TestDockerAUFS(t *testing.T) {
    52  	test.EnsurePrivilege(t)
    53  
    54  	imagePath := path.Join(testDir, "container")
    55  	defer os.Remove(imagePath)
    56  
    57  	b, err := imageBuild(buildOpts{}, imagePath, "docker://dctrud/docker-aufs-sanity")
    58  	if err != nil {
    59  		t.Log(string(b))
    60  		t.Fatalf("unexpected failure: %v", err)
    61  	}
    62  
    63  	fileTests := []struct {
    64  		name          string
    65  		execArgs      []string
    66  		expectSuccess bool
    67  	}{
    68  		{"File2", []string{"ls", "/test/whiteout-dir/file2", "/test/whiteout-file/file2", "/test/normal-dir/file2"}, true},
    69  		{"File1", []string{"ls", "/test/whiteout-dir/file1", "/test/whiteout-file/file1"}, false},
    70  		{"Glob", []string{"ls", "/test/*/.wh*"}, false},
    71  	}
    72  	for _, tt := range fileTests {
    73  		t.Run(tt.name, test.WithoutPrivilege(func(t *testing.T) {
    74  			_, stderr, exitCode, err := imageExec(t, "exec", opts{}, imagePath, tt.execArgs)
    75  			if tt.expectSuccess && (exitCode != 0) {
    76  				t.Log(stderr)
    77  				t.Fatalf("unexpected failure running '%v': %v", strings.Join(tt.execArgs, " "), err)
    78  			} else if !tt.expectSuccess && (exitCode != 1) {
    79  				t.Log(stderr)
    80  				t.Fatalf("unexpected success running '%v'", strings.Join(tt.execArgs, " "))
    81  			}
    82  		}))
    83  	}
    84  }
    85  
    86  // Check force permissions for user builds #977
    87  func TestDockerPermissions(t *testing.T) {
    88  	test.DropPrivilege(t)
    89  	defer test.ResetPrivilege(t)
    90  
    91  	imagePath := path.Join(testDir, "container")
    92  	defer os.Remove(imagePath)
    93  
    94  	b, err := imageBuild(buildOpts{}, imagePath, "docker://dctrud/docker-singularity-userperms")
    95  	if err != nil {
    96  		t.Log(string(b))
    97  		t.Fatalf("unexpected failure: %v", err)
    98  	}
    99  
   100  	fileTests := []struct {
   101  		name          string
   102  		execArgs      []string
   103  		expectSuccess bool
   104  	}{
   105  		{"TestDir", []string{"ls", "/testdir/"}, true},
   106  		{"TestDirFile", []string{"ls", "/testdir/testfile"}, false},
   107  	}
   108  	for _, tt := range fileTests {
   109  		t.Run(tt.name, test.WithoutPrivilege(func(t *testing.T) {
   110  			_, stderr, exitCode, err := imageExec(t, "exec", opts{}, imagePath, tt.execArgs)
   111  			if tt.expectSuccess && (exitCode != 0) {
   112  				t.Log(stderr)
   113  				t.Fatalf("unexpected failure running '%v': %v", strings.Join(tt.execArgs, " "), err)
   114  			} else if !tt.expectSuccess && (exitCode != 1) {
   115  				t.Log(stderr)
   116  				t.Fatalf("unexpected success running '%v'", strings.Join(tt.execArgs, " "))
   117  			}
   118  		}))
   119  	}
   120  }
   121  
   122  // Check whiteout of symbolic links #1592 #1576
   123  func TestDockerWhiteoutSymlink(t *testing.T) {
   124  	test.DropPrivilege(t)
   125  	defer test.ResetPrivilege(t)
   126  
   127  	imagePath := path.Join(testDir, "container")
   128  	defer os.Remove(imagePath)
   129  
   130  	b, err := imageBuild(buildOpts{}, imagePath, "docker://dctrud/docker-singularity-linkwh")
   131  	if err != nil {
   132  		t.Log(string(b))
   133  		t.Fatalf("unexpected failure: %v", err)
   134  	}
   135  	imageVerify(t, imagePath, false)
   136  }
   137  
   138  func getKernelMajor(t *testing.T) (major int) {
   139  	var buf unix.Utsname
   140  	if err := unix.Uname(&buf); err != nil {
   141  		t.Fatalf("uname failed: %v", err)
   142  	}
   143  	n, err := fmt.Sscanf(string(buf.Release[:]), "%d.", &major)
   144  	if n != 1 || err != nil {
   145  		t.Fatalf("Sscanf failed: %v %v", n, err)
   146  	}
   147  	return
   148  }
   149  
   150  func TestDockerDefFile(t *testing.T) {
   151  	tests := []struct {
   152  		name                string
   153  		kernelMajorRequired int
   154  		from                string
   155  	}{
   156  		{"Arch", 3, "dock0/arch:latest"},
   157  		{"BusyBox", 0, "busybox:latest"},
   158  		{"CentOS", 0, "centos:latest"},
   159  		{"Ubuntu", 0, "ubuntu:16.04"},
   160  	}
   161  
   162  	for _, tt := range tests {
   163  		t.Run(tt.name, test.WithPrivilege(func(t *testing.T) {
   164  			if getKernelMajor(t) < tt.kernelMajorRequired {
   165  				t.Skipf("kernel >=%v.x required", tt.kernelMajorRequired)
   166  			}
   167  
   168  			imagePath := path.Join(testDir, "container")
   169  			defer os.Remove(imagePath)
   170  
   171  			deffile := prepareDefFile(DefFileDetail{
   172  				Bootstrap: "docker",
   173  				From:      tt.from,
   174  			})
   175  			defer os.Remove(deffile)
   176  
   177  			if b, err := imageBuild(buildOpts{}, imagePath, deffile); err != nil {
   178  				t.Log(string(b))
   179  				t.Fatalf("unexpected failure: %v", err)
   180  			}
   181  			imageVerify(t, imagePath, false)
   182  		}))
   183  	}
   184  }
   185  
   186  func prepRegistry(t *testing.T) {
   187  	commands := [][]string{
   188  		{"run", "-d", "-p", "5000:5000", "--restart=always", "--name", "registry", "registry:2"},
   189  		{"pull", "busybox"},
   190  		{"tag", "busybox", "localhost:5000/my-busybox"},
   191  		{"push", "localhost:5000/my-busybox"},
   192  	}
   193  
   194  	for _, command := range commands {
   195  		cmd := exec.Command("docker", command...)
   196  		if b, err := cmd.CombinedOutput(); err != nil {
   197  			t.Logf(string(b))
   198  			t.Fatalf("command failed: %v", strings.Join(command, " "))
   199  		}
   200  	}
   201  }
   202  
   203  func killRegistry(t *testing.T) {
   204  	commands := [][]string{
   205  		{"kill", "registry"},
   206  		{"rm", "registry"},
   207  	}
   208  
   209  	for _, command := range commands {
   210  		cmd := exec.Command("docker", command...)
   211  		if b, err := cmd.CombinedOutput(); err != nil {
   212  			t.Logf(string(b))
   213  			t.Fatalf("command failed: %v", strings.Join(command, " "))
   214  		}
   215  	}
   216  }
   217  
   218  func TestDockerRegistry(t *testing.T) {
   219  	test.EnsurePrivilege(t)
   220  
   221  	if _, err := exec.LookPath("docker"); err != nil {
   222  		t.Skip("docker not installed")
   223  	}
   224  
   225  	prepRegistry(t)
   226  	defer killRegistry(t)
   227  
   228  	tests := []struct {
   229  		name          string
   230  		expectSuccess bool
   231  		dfd           DefFileDetail
   232  	}{
   233  		{"BusyBox", true, DefFileDetail{
   234  			Bootstrap: "docker",
   235  			From:      "localhost:5000/my-busybox",
   236  		}},
   237  		{"BusyBoxRegistry", true, DefFileDetail{
   238  			Bootstrap: "docker",
   239  			From:      "my-busybox",
   240  			Registry:  "localhost:5000",
   241  		}},
   242  		{"BusyBoxNamespace", false, DefFileDetail{
   243  			Bootstrap: "docker",
   244  			From:      "my-busybox",
   245  			Registry:  "localhost:5000",
   246  			Namespace: "not-a-namespace",
   247  		}},
   248  	}
   249  
   250  	for _, tt := range tests {
   251  		t.Run(tt.name, test.WithPrivilege(func(t *testing.T) {
   252  			opts := buildOpts{
   253  				env: append(os.Environ(), "SINGULARITY_NOHTTPS=true"),
   254  			}
   255  			imagePath := path.Join(testDir, "container")
   256  			defer os.Remove(imagePath)
   257  
   258  			defFile := prepareDefFile(tt.dfd)
   259  
   260  			b, err := imageBuild(opts, imagePath, defFile)
   261  			if tt.expectSuccess {
   262  				if err != nil {
   263  					t.Log(string(b))
   264  					t.Fatalf("unexpected failure: %v", err)
   265  				}
   266  				imageVerify(t, imagePath, false)
   267  			} else if !tt.expectSuccess && (err == nil) {
   268  				t.Log(string(b))
   269  				t.Fatalf("unexpected success")
   270  			}
   271  		}))
   272  	}
   273  }