diff --git a/src/runtime/cmd/kata-runtime/main.go b/src/runtime/cmd/kata-runtime/main.go index a2a930abbd..23cd3d07de 100644 --- a/src/runtime/cmd/kata-runtime/main.go +++ b/src/runtime/cmd/kata-runtime/main.go @@ -30,9 +30,6 @@ import ( "github.com/urfave/cli" ) -// specConfig is the name of the file holding the containers configuration -const specConfig = "config.json" - // arch is the architecture for the running program const arch = goruntime.GOARCH diff --git a/src/runtime/cmd/kata-runtime/main_test.go b/src/runtime/cmd/kata-runtime/main_test.go index c18d19b507..c90b9338d0 100644 --- a/src/runtime/cmd/kata-runtime/main_test.go +++ b/src/runtime/cmd/kata-runtime/main_test.go @@ -13,7 +13,6 @@ import ( "fmt" "io/ioutil" "os" - "os/exec" "path" "path/filepath" "regexp" @@ -22,9 +21,7 @@ import ( ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils" - "github.com/kata-containers/kata-containers/src/runtime/pkg/utils" vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" - "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/compatoci" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/oci" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/vcmock" specs "github.com/opencontainers/runtime-spec/specs-go" @@ -38,19 +35,12 @@ const ( testFileMode = os.FileMode(0640) testExeFileMode = os.FileMode(0750) - // small docker image used to create root filesystems from - testDockerImage = "busybox" - - testBundle = "bundle" testConsole = "/dev/pts/999" ) var ( // package variables set by calling TestMain() - testDir = "" - testBundleDir = "" - tc ktu.TestConstraint - ctrEngine = katautils.CtrEngine{} + tc ktu.TestConstraint ) // testingImpl is a concrete mock RVC implementation used for testing @@ -79,57 +69,6 @@ func init() { fmt.Printf("INFO: switching to fake virtcontainers implementation for testing\n") vci = testingImpl - var err error - - fmt.Printf("INFO: creating test directory\n") - testDir, err = ioutil.TempDir("", fmt.Sprintf("%s-", katautils.NAME)) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create test directory: %v", err)) - } - fmt.Printf("INFO: test directory is %v\n", testDir) - - var output string - for _, name := range katautils.DockerLikeCtrEngines { - fmt.Printf("INFO: checking for container engine: %s\n", name) - - output, err = ctrEngine.Init(name) - if err == nil { - break - } - } - - if ctrEngine.Name == "" { - panic(fmt.Sprintf("ERROR: Docker-like container engine not accessible to current user: %v (error %v)", - output, err)) - } - - // Do this now to avoid hitting the test timeout value due to - // slow network response. - fmt.Printf("INFO: ensuring required container image (%v) is available\n", testDockerImage) - // Only hit the network if the image doesn't exist locally - _, err = ctrEngine.Inspect(testDockerImage) - if err == nil { - fmt.Printf("INFO: container image %v already exists locally\n", testDockerImage) - } else { - fmt.Printf("INFO: pulling container image %v\n", testDockerImage) - _, err = ctrEngine.Pull(testDockerImage) - if err != nil { - panic(err) - } - } - - testBundleDir = filepath.Join(testDir, testBundle) - err = os.MkdirAll(testBundleDir, testDirMode) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create bundle directory %v: %v", testBundleDir, err)) - } - - fmt.Printf("INFO: creating OCI bundle in %v for tests to use\n", testBundleDir) - err = realMakeOCIBundle(testBundleDir) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create OCI bundle: %v", err)) - } - tc = ktu.NewTestConstraint(false) } @@ -143,8 +82,6 @@ func resetCLIGlobals() { func runUnitTests(m *testing.M) { ret := m.Run() - os.RemoveAll(testDir) - os.Exit(ret) } @@ -232,146 +169,6 @@ func newTestRuntimeConfig(dir, consolePath string, create bool) (oci.RuntimeConf }, nil } -// createOCIConfig creates an OCI configuration (spec) file in -// the bundle directory specified (which must exist). -func createOCIConfig(bundleDir string) error { - if bundleDir == "" { - return errors.New("BUG: Need bundle directory") - } - - if !katautils.FileExists(bundleDir) { - return fmt.Errorf("BUG: Bundle directory %s does not exist", bundleDir) - } - - var configCmd string - - // Search for a suitable version of runc to use to generate - // the OCI config file. - for _, cmd := range []string{"docker-runc", "runc"} { - fullPath, err := exec.LookPath(cmd) - if err == nil { - configCmd = fullPath - break - } - } - - if configCmd == "" { - return errors.New("Cannot find command to generate OCI config file") - } - - _, err := utils.RunCommand([]string{configCmd, "spec", "--bundle", bundleDir}) - if err != nil { - return err - } - - specFile := filepath.Join(bundleDir, specConfig) - if !katautils.FileExists(specFile) { - return fmt.Errorf("generated OCI config file does not exist: %v", specFile) - } - - return nil -} - -// createRootfs creates a minimal root filesystem below the specified -// directory. -func createRootfs(dir string) error { - err := os.MkdirAll(dir, testDirMode) - if err != nil { - return err - } - - container, err := ctrEngine.Create(testDockerImage) - if err != nil { - return err - } - - err = ctrEngine.GetRootfs(container, dir) - if err != nil { - return err - } - - // Clean up - _, err = ctrEngine.Rm(container) - if err != nil { - return err - } - - return nil -} - -// realMakeOCIBundle will create an OCI bundle (including the "config.json" -// config file) in the directory specified (which must already exist). -// -// XXX: Note that tests should *NOT* call this function - they should -// XXX: instead call makeOCIBundle(). -func realMakeOCIBundle(bundleDir string) error { - if bundleDir == "" { - return errors.New("BUG: Need bundle directory") - } - - if !katautils.FileExists(bundleDir) { - return fmt.Errorf("BUG: Bundle directory %v does not exist", bundleDir) - } - - err := createOCIConfig(bundleDir) - if err != nil { - return err - } - - // Note the unusual parameter (a directory, not the config - // file to parse!) - spec, err := compatoci.ParseConfigJSON(bundleDir) - if err != nil { - return err - } - - // Determine the rootfs directory name the OCI config refers to - ociRootPath := spec.Root.Path - - rootfsDir := filepath.Join(bundleDir, ociRootPath) - - if strings.HasPrefix(ociRootPath, "/") { - return fmt.Errorf("Cannot handle absolute rootfs as bundle must be unique to each test") - } - - err = createRootfs(rootfsDir) - if err != nil { - return err - } - - return nil -} - -// Create an OCI bundle in the specified directory. -// -// Note that the directory will be created, but it's parent is expected to exist. -// -// This function works by copying the already-created test bundle. Ideally, -// the bundle would be recreated for each test, but createRootfs() uses -// docker which on some systems is too slow, resulting in the tests timing -// out. -func makeOCIBundle(bundleDir string) error { - from := testBundleDir - to := bundleDir - - // only the basename of bundleDir needs to exist as bundleDir - // will get created by cp(1). - base := filepath.Dir(bundleDir) - - for _, dir := range []string{from, base} { - if !katautils.FileExists(dir) { - return fmt.Errorf("BUG: directory %v should exist", dir) - } - } - - output, err := utils.RunCommandFull([]string{"cp", "-a", from, to}, true) - if err != nil { - return fmt.Errorf("failed to copy test OCI bundle from %v to %v: %v (output: %v)", from, to, err, output) - } - - return nil -} - func createCLIContextWithApp(flagSet *flag.FlagSet, app *cli.App) *cli.Context { ctx := cli.NewContext(app, flagSet, nil) @@ -390,69 +187,6 @@ func createCLIContext(flagset *flag.FlagSet) *cli.Context { return createCLIContextWithApp(flagset, cli.NewApp()) } -func TestMakeOCIBundle(t *testing.T) { - assert := assert.New(t) - - tmpdir, err := ioutil.TempDir(testDir, "") - assert.NoError(err) - defer os.RemoveAll(tmpdir) - - bundleDir := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundleDir) - assert.NoError(err) - - specFile := filepath.Join(bundleDir, specConfig) - assert.True(katautils.FileExists(specFile)) -} - -func TestCreateOCIConfig(t *testing.T) { - assert := assert.New(t) - - tmpdir, err := ioutil.TempDir(testDir, "") - assert.NoError(err) - defer os.RemoveAll(tmpdir) - - bundleDir := filepath.Join(tmpdir, "bundle") - - err = createOCIConfig(bundleDir) - // ENOENT - assert.Error(err) - - err = os.MkdirAll(bundleDir, testDirMode) - assert.NoError(err) - - err = createOCIConfig(bundleDir) - assert.NoError(err) - - specFile := filepath.Join(bundleDir, specConfig) - assert.True(katautils.FileExists(specFile)) -} - -func TestCreateRootfs(t *testing.T) { - assert := assert.New(t) - - tmpdir, err := ioutil.TempDir(testDir, "") - assert.NoError(err) - defer os.RemoveAll(tmpdir) - - rootfsDir := filepath.Join(tmpdir, "rootfs") - assert.False(katautils.FileExists(rootfsDir)) - - err = createRootfs(rootfsDir) - assert.NoError(err) - - // non-comprehensive list of expected directories - expectedDirs := []string{"bin", "dev", "etc", "usr", "var"} - - assert.True(katautils.FileExists(rootfsDir)) - - for _, dir := range expectedDirs { - dirPath := filepath.Join(rootfsDir, dir) - assert.True(katautils.FileExists(dirPath)) - } -} - func TestMainUserWantsUsage(t *testing.T) { assert := assert.New(t) @@ -525,7 +259,7 @@ func TestMainBeforeSubCommands(t *testing.T) { func TestMainBeforeSubCommandsInvalidLogFile(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir(testDir, "") + tmpdir, err := ioutil.TempDir("", "katatest") assert.NoError(err) defer os.RemoveAll(tmpdir) @@ -548,7 +282,7 @@ func TestMainBeforeSubCommandsInvalidLogFile(t *testing.T) { func TestMainBeforeSubCommandsInvalidLogFormat(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir(testDir, "") + tmpdir, err := ioutil.TempDir("", "katatest") assert.NoError(err) defer os.RemoveAll(tmpdir) @@ -577,7 +311,7 @@ func TestMainBeforeSubCommandsInvalidLogFormat(t *testing.T) { func TestMainBeforeSubCommandsLoadConfigurationFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir(testDir, "") + tmpdir, err := ioutil.TempDir("", "katatest") assert.NoError(err) defer os.RemoveAll(tmpdir) @@ -612,7 +346,7 @@ func TestMainBeforeSubCommandsLoadConfigurationFail(t *testing.T) { func TestMainBeforeSubCommandsShowCCConfigPaths(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir(testDir, "") + tmpdir, err := ioutil.TempDir("", "katatest") assert.NoError(err) defer os.RemoveAll(tmpdir) @@ -676,7 +410,7 @@ func TestMainBeforeSubCommandsShowCCConfigPaths(t *testing.T) { func TestMainFatal(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir(testDir, "") + tmpdir, err := ioutil.TempDir("", "katatest") assert.NoError(err) defer os.RemoveAll(tmpdir) @@ -900,7 +634,7 @@ func TestMainCreateRuntime(t *testing.T) { func TestMainVersionPrinter(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") + tmpdir, err := ioutil.TempDir("", "katatest") assert.NoError(err) defer os.RemoveAll(tmpdir) diff --git a/src/runtime/cmd/kata-runtime/utils_test.go b/src/runtime/cmd/kata-runtime/utils_test.go index a222b940b0..12bba4e2bf 100644 --- a/src/runtime/cmd/kata-runtime/utils_test.go +++ b/src/runtime/cmd/kata-runtime/utils_test.go @@ -18,7 +18,7 @@ import ( ) func TestFileExists(t *testing.T) { - dir, err := ioutil.TempDir(testDir, "") + dir, err := ioutil.TempDir("", "katatest") if err != nil { t.Fatal(err) } diff --git a/src/runtime/pkg/containerd-shim-v2/create_test.go b/src/runtime/pkg/containerd-shim-v2/create_test.go index d2e0b58244..5ad96f1499 100644 --- a/src/runtime/pkg/containerd-shim-v2/create_test.go +++ b/src/runtime/pkg/containerd-shim-v2/create_test.go @@ -12,7 +12,6 @@ import ( "io/ioutil" "os" "path" - "path/filepath" "testing" "github.com/containerd/containerd/namespaces" @@ -23,7 +22,6 @@ import ( "github.com/stretchr/testify/assert" ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" - "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils" vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" vcAnnotations "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/annotations" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/compatoci" @@ -52,21 +50,12 @@ func TestCreateSandboxSuccess(t *testing.T) { testingImpl.CreateSandboxFunc = nil }() - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) - defer os.RemoveAll(tmpdir) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) + // defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(katautils.FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -82,7 +71,7 @@ func TestCreateSandboxSuccess(t *testing.T) { } // Rewrite the file - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) s := &service{ @@ -110,25 +99,16 @@ func TestCreateSandboxFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(katautils.FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) s := &service{ @@ -157,21 +137,12 @@ func TestCreateSandboxConfigFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, _ := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(katautils.FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -216,21 +187,12 @@ func TestCreateContainerSuccess(t *testing.T) { }, } - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(katautils.FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -240,7 +202,7 @@ func TestCreateContainerSuccess(t *testing.T) { spec.Annotations[testSandboxIDAnnotation] = testSandboxID // rewrite file - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) s := &service{ @@ -265,21 +227,12 @@ func TestCreateContainerSuccess(t *testing.T) { func TestCreateContainerFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(katautils.FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -287,7 +240,7 @@ func TestCreateContainerFail(t *testing.T) { spec.Annotations[testContainerTypeAnnotation] = testContainerTypeContainer spec.Annotations[testSandboxIDAnnotation] = testSandboxID - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) // doesn't create sandbox first @@ -325,21 +278,12 @@ func TestCreateContainerConfigFail(t *testing.T) { sandbox.CreateContainerFunc = nil }() - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(katautils.FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -348,7 +292,7 @@ func TestCreateContainerConfigFail(t *testing.T) { spec.Annotations[testContainerTypeAnnotation] = "errorType" spec.Annotations[testSandboxIDAnnotation] = testSandboxID - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) s := &service{ diff --git a/src/runtime/pkg/containerd-shim-v2/delete_test.go b/src/runtime/pkg/containerd-shim-v2/delete_test.go index b19d3d141a..f84f5e596e 100644 --- a/src/runtime/pkg/containerd-shim-v2/delete_test.go +++ b/src/runtime/pkg/containerd-shim-v2/delete_test.go @@ -7,14 +7,13 @@ package containerdshim import ( - "io/ioutil" "os" - "path/filepath" "testing" taskAPI "github.com/containerd/containerd/runtime/v2/task" "github.com/stretchr/testify/assert" + ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/compatoci" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/vcmock" ) @@ -26,7 +25,7 @@ func TestDeleteContainerSuccessAndFail(t *testing.T) { MockID: testSandboxID, } - rootPath, bundlePath := testConfigSetup(t) + rootPath, bundlePath, _ := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(rootPath) _, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -43,19 +42,3 @@ func TestDeleteContainerSuccessAndFail(t *testing.T) { s.containers[testContainerID], err = newContainer(s, reqCreate, "", nil, true) assert.NoError(err) } - -func testConfigSetup(t *testing.T) (rootPath string, bundlePath string) { - assert := assert.New(t) - - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) - - bundlePath = filepath.Join(tmpdir, "bundle") - err = os.MkdirAll(bundlePath, testDirMode) - assert.NoError(err) - - err = createOCIConfig(bundlePath) - assert.NoError(err) - - return tmpdir, bundlePath -} diff --git a/src/runtime/pkg/containerd-shim-v2/service_test.go b/src/runtime/pkg/containerd-shim-v2/service_test.go index f49d7f4f3d..b501df99cc 100644 --- a/src/runtime/pkg/containerd-shim-v2/service_test.go +++ b/src/runtime/pkg/containerd-shim-v2/service_test.go @@ -8,9 +8,7 @@ package containerdshim import ( "context" "fmt" - "io/ioutil" "os" - "path/filepath" "strings" "testing" @@ -43,13 +41,9 @@ func TestServiceCreate(t *testing.T) { assert := assert.New(t) - tmpdir, _ := ioutil.TempDir("", "") + tmpdir, bundleDir, _ := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) - bundleDir := filepath.Join(tmpdir, "bundle") - err := makeOCIBundle(bundleDir) - assert.NoError(err) - ctx := context.Background() s, err := newService("foo") diff --git a/src/runtime/pkg/containerd-shim-v2/stream_test.go b/src/runtime/pkg/containerd-shim-v2/stream_test.go index a973f218f0..a3c7c72688 100644 --- a/src/runtime/pkg/containerd-shim-v2/stream_test.go +++ b/src/runtime/pkg/containerd-shim-v2/stream_test.go @@ -9,6 +9,7 @@ import ( "context" "io" "io/ioutil" + "os" "path/filepath" "syscall" "testing" @@ -24,6 +25,11 @@ func TestNewTtyIOFifoReopen(t *testing.T) { var tty *ttyIO assert := assert.New(t) ctx := context.TODO() + + testDir, err := ioutil.TempDir("", "kata-") + assert.NoError(err) + defer os.RemoveAll(testDir) + fifoPath, err := ioutil.TempDir(testDir, "fifo-path-") assert.NoError(err) stdout := filepath.Join(fifoPath, "stdout") @@ -100,6 +106,10 @@ func TestIoCopy(t *testing.T) { testBytes2 := []byte("Test2") testBytes3 := []byte("Test3") + testDir, err := ioutil.TempDir("", "kata-") + assert.NoError(err) + defer os.RemoveAll(testDir) + fifoPath, err := ioutil.TempDir(testDir, "fifo-path-") assert.NoError(err) dstStdoutPath := filepath.Join(fifoPath, "dststdout") diff --git a/src/runtime/pkg/containerd-shim-v2/utils_test.go b/src/runtime/pkg/containerd-shim-v2/utils_test.go index 3ff22787ac..dc118ca1c1 100644 --- a/src/runtime/pkg/containerd-shim-v2/utils_test.go +++ b/src/runtime/pkg/containerd-shim-v2/utils_test.go @@ -7,46 +7,28 @@ package containerdshim import ( - "encoding/json" - "errors" "fmt" "io/ioutil" "os" - sysExec "os/exec" "path" - "path/filepath" - "strings" "testing" "github.com/stretchr/testify/assert" - "github.com/opencontainers/runtime-spec/specs-go" - ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" - "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils" - "github.com/kata-containers/kata-containers/src/runtime/pkg/utils" vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" - "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/compatoci" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/oci" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/vcmock" + "github.com/pkg/errors" ) const ( - // specConf is the name of the file holding the containers configuration - specConf = "config.json" - TestID = "container_test" - testDirMode = os.FileMode(0750) testFileMode = os.FileMode(0640) - // testExeFileMode = os.FileMode(0750) - - // small docker image used to create root filesystems from - testDockerImage = "busybox" testSandboxID = "777-77-77777777" testContainerID = "42" - testBundle = "bundle" testConsole = "/dev/pts/888" testContainerTypeAnnotation = "io.kubernetes.cri.container-type" @@ -57,10 +39,7 @@ const ( var ( // package variables set by calling TestMain() - testDir = "" - testBundleDir = "" - tc ktu.TestConstraint - ctrEngine = katautils.CtrEngine{} + tc ktu.TestConstraint ) // testingImpl is a concrete mock RVC implementation used for testing @@ -73,57 +52,6 @@ func init() { fmt.Printf("INFO: switching to fake virtcontainers implementation for testing\n") vci = testingImpl - var err error - - fmt.Printf("INFO: creating test directory\n") - testDir, err = ioutil.TempDir("", "shimV2-") - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create test directory: %v", err)) - } - fmt.Printf("INFO: test directory is %v\n", testDir) - - var output string - for _, name := range katautils.DockerLikeCtrEngines { - fmt.Printf("INFO: checking for container engine: %s\n", name) - - output, err = ctrEngine.Init(name) - if err == nil { - break - } - } - - if ctrEngine.Name == "" { - panic(fmt.Sprintf("ERROR: Docker-like container engine not accessible to current user: %v (error %v)", - output, err)) - } - - // Do this now to avoid hitting the test timeout value due to - // slow network response. - fmt.Printf("INFO: ensuring required container image (%v) is available\n", testDockerImage) - // Only hit the network if the image doesn't exist locally - _, err = ctrEngine.Inspect(testDockerImage) - if err == nil { - fmt.Printf("INFO: container image %v already exists locally\n", testDockerImage) - } else { - fmt.Printf("INFO: pulling container image %v\n", testDockerImage) - _, err = ctrEngine.Pull(testDockerImage) - if err != nil { - panic(err) - } - } - - testBundleDir = filepath.Join(testDir, testBundle) - err = os.MkdirAll(testBundleDir, testDirMode) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create bundle directory %v: %v", testBundleDir, err)) - } - - fmt.Printf("INFO: creating OCI bundle in %v for tests to use\n", testBundleDir) - err = realMakeOCIBundle(testBundleDir) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create OCI bundle: %v", err)) - } - tc = ktu.NewTestConstraint(false) // disable shim management server. @@ -131,46 +59,6 @@ func init() { defaultStartManagementServerFunc = nil } -// createOCIConfig creates an OCI configuration (spec) file in -// the bundle directory specified (which must exist). -func createOCIConfig(bundleDir string) error { - if bundleDir == "" { - return errors.New("BUG: Need bundle directory") - } - - if !katautils.FileExists(bundleDir) { - return fmt.Errorf("BUG: Bundle directory %s does not exist", bundleDir) - } - - var configCmd string - - // Search for a suitable version of runc to use to generate - // the OCI config file. - for _, cmd := range []string{"docker-runc", "runc"} { - fullPath, err := sysExec.LookPath(cmd) - if err == nil { - configCmd = fullPath - break - } - } - - if configCmd == "" { - return errors.New("Cannot find command to generate OCI config file") - } - - _, err := utils.RunCommand([]string{configCmd, "spec", "--bundle", bundleDir}) - if err != nil { - return err - } - - specFile := filepath.Join(bundleDir, specConf) - if !katautils.FileExists(specFile) { - return fmt.Errorf("generated OCI config file does not exist: %v", specFile) - } - - return nil -} - func createEmptyFile(path string) (err error) { return ioutil.WriteFile(path, []byte(""), testFileMode) } @@ -221,119 +109,6 @@ func newTestRuntimeConfig(dir, consolePath string, create bool) (oci.RuntimeConf }, nil } -// realMakeOCIBundle will create an OCI bundle (including the "config.json" -// config file) in the directory specified (which must already exist). -// -// XXX: Note that tests should *NOT* call this function - they should -// XXX: instead call makeOCIBundle(). -func realMakeOCIBundle(bundleDir string) error { - if bundleDir == "" { - return errors.New("BUG: Need bundle directory") - } - - if !katautils.FileExists(bundleDir) { - return fmt.Errorf("BUG: Bundle directory %v does not exist", bundleDir) - } - - err := createOCIConfig(bundleDir) - if err != nil { - return err - } - - // Note the unusual parameter (a directory, not the config - // file to parse!) - spec, err := compatoci.ParseConfigJSON(bundleDir) - if err != nil { - return err - } - - // Determine the rootfs directory name the OCI config refers to - ociRootPath := spec.Root.Path - - rootfsDir := filepath.Join(bundleDir, ociRootPath) - - if strings.HasPrefix(ociRootPath, "/") { - return fmt.Errorf("Cannot handle absolute rootfs as bundle must be unique to each test") - } - - err = createRootfs(rootfsDir) - if err != nil { - return err - } - - return nil -} - -// Create an OCI bundle in the specified directory. -// -// Note that the directory will be created, but it's parent is expected to exist. -// -// This function works by copying the already-created test bundle. Ideally, -// the bundle would be recreated for each test, but createRootfs() uses -// docker which on some systems is too slow, resulting in the tests timing -// out. -func makeOCIBundle(bundleDir string) error { - from := testBundleDir - to := bundleDir - - // only the basename of bundleDir needs to exist as bundleDir - // will get created by cp(1). - base := filepath.Dir(bundleDir) - - for _, dir := range []string{from, base} { - if !katautils.FileExists(dir) { - return fmt.Errorf("BUG: directory %v should exist", dir) - } - } - - output, err := utils.RunCommandFull([]string{"cp", "-a", from, to}, true) - if err != nil { - return fmt.Errorf("failed to copy test OCI bundle from %v to %v: %v (output: %v)", from, to, err, output) - } - - return nil -} - -// createRootfs creates a minimal root filesystem below the specified -// directory. -func createRootfs(dir string) error { - err := os.MkdirAll(dir, testDirMode) - if err != nil { - return err - } - - container, err := ctrEngine.Create(testDockerImage) - if err != nil { - return err - } - - err = ctrEngine.GetRootfs(container, dir) - if err != nil { - return err - } - - // Clean up - _, err = ctrEngine.Rm(container) - if err != nil { - return err - } - - return nil -} - -func writeOCIConfigFile(spec specs.Spec, configPath string) error { - if configPath == "" { - return errors.New("BUG: need config file path") - } - - bytes, err := json.MarshalIndent(spec, "", "\t") - if err != nil { - return err - } - - return ioutil.WriteFile(configPath, bytes, testFileMode) -} - func TestNoNeedForOutput(t *testing.T) { assert := assert.New(t) diff --git a/src/runtime/pkg/katatestutils/constraints_test.go b/src/runtime/pkg/katatestutils/constraints_test.go index 8a95a9c800..9444fe8e02 100644 --- a/src/runtime/pkg/katatestutils/constraints_test.go +++ b/src/runtime/pkg/katatestutils/constraints_test.go @@ -21,7 +21,6 @@ import ( ) const ( - testFileMode = os.FileMode(0640) invalidOperator = 1234 skipUnknownDistroName = "skipping test as cannot determine distro name" diff --git a/src/runtime/pkg/katatestutils/utils.go b/src/runtime/pkg/katatestutils/utils.go index 4a286a212c..617943a03e 100644 --- a/src/runtime/pkg/katatestutils/utils.go +++ b/src/runtime/pkg/katatestutils/utils.go @@ -7,8 +7,203 @@ package katatestutils import ( + "encoding/json" + "errors" + "io/ioutil" "os" + "path/filepath" "strconv" + "testing" + + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" +) + +const ( + testDirMode = os.FileMode(0750) + testFileMode = os.FileMode(0640) + + busyboxConfigJson = ` +{ + "ociVersion": "1.0.1-dev", + "process": { + "terminal": true, + "user": { + "uid": 0, + "gid": 0 + }, + "args": [ + "sh" + ], + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm" + ], + "cwd": "/", + "capabilities": { + "bounding": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "effective": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "inheritable": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "permitted": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "ambient": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ] + }, + "rlimits": [ + { + "type": "RLIMIT_NOFILE", + "hard": 1024, + "soft": 1024 + } + ], + "noNewPrivileges": true + }, + "root": { + "path": "rootfs", + "readonly": true + }, + "hostname": "runc", + "mounts": [ + { + "destination": "/proc", + "type": "proc", + "source": "proc" + }, + { + "destination": "/dev", + "type": "tmpfs", + "source": "tmpfs", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ] + }, + { + "destination": "/dev/pts", + "type": "devpts", + "source": "devpts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ] + }, + { + "destination": "/dev/shm", + "type": "tmpfs", + "source": "shm", + "options": [ + "nosuid", + "noexec", + "nodev", + "mode=1777", + "size=65536k" + ] + }, + { + "destination": "/dev/mqueue", + "type": "mqueue", + "source": "mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ] + }, + { + "destination": "/sys", + "type": "sysfs", + "source": "sysfs", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ] + }, + { + "destination": "/sys/fs/cgroup", + "type": "cgroup", + "source": "cgroup", + "options": [ + "nosuid", + "noexec", + "nodev", + "relatime", + "ro" + ] + } + ], + "linux": { + "resources": { + "devices": [ + { + "allow": false, + "access": "rwm" + } + ] + }, + "namespaces": [ + { + "type": "pid" + }, + { + "type": "network" + }, + { + "type": "ipc" + }, + { + "type": "uts" + }, + { + "type": "mount" + } + ], + "maskedPaths": [ + "/proc/acpi", + "/proc/asound", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/sys/firmware", + "/proc/scsi" + ], + "readonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + } +}` ) type RuntimeConfigOptions struct { @@ -154,3 +349,34 @@ func IsInGitHubActions() bool { // https://docs.github.com/en/actions/reference/environment-variables#default-environment-variables return os.Getenv("GITHUB_ACTIONS") == "true" } + +func SetupOCIConfigFile(t *testing.T) (rootPath string, bundlePath, ociConfigFile string) { + assert := assert.New(t) + + tmpdir, err := ioutil.TempDir("", "katatest-") + assert.NoError(err) + + bundlePath = filepath.Join(tmpdir, "bundle") + err = os.MkdirAll(bundlePath, testDirMode) + assert.NoError(err) + + ociConfigFile = filepath.Join(bundlePath, "config.json") + err = ioutil.WriteFile(ociConfigFile, []byte(busyboxConfigJson), testFileMode) + assert.NoError(err) + + return tmpdir, bundlePath, ociConfigFile +} + +// WriteOCIConfigFile using spec to update OCI config file by path configPath +func WriteOCIConfigFile(spec specs.Spec, configPath string) error { + if configPath == "" { + return errors.New("BUG: need config file path") + } + + bytes, err := json.MarshalIndent(spec, "", "\t") + if err != nil { + return err + } + + return ioutil.WriteFile(configPath, bytes, testFileMode) +} diff --git a/src/runtime/pkg/katautils/container_engine.go b/src/runtime/pkg/katautils/container_engine.go deleted file mode 100644 index 39f2f563f3..0000000000 --- a/src/runtime/pkg/katautils/container_engine.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2019 SUSE LLC -// -// SPDX-License-Identifier: Apache-2.0 -// - -package katautils - -import ( - "os/exec" - - "github.com/kata-containers/kata-containers/src/runtime/pkg/utils" -) - -type CtrEngine struct { - Name string -} - -var ( - DockerLikeCtrEngines = []string{"docker", "podman"} -) - -func (e *CtrEngine) Init(name string) (string, error) { - var out string - out, err := utils.RunCommandFull([]string{name, "version"}, true) - if err != nil { - return out, err - } - - e.Name = name - return out, nil -} - -func (e *CtrEngine) Inspect(image string) (string, error) { - // Only hit the network if the image doesn't exist locally - return utils.RunCommand([]string{e.Name, "inspect", "--type=image", image}) -} - -func (e *CtrEngine) Pull(image string) (string, error) { - return utils.RunCommand([]string{e.Name, "pull", image}) -} - -func (e *CtrEngine) Create(image string) (string, error) { - return utils.RunCommand([]string{e.Name, "create", image}) -} - -func (e *CtrEngine) Rm(ctrID string) (string, error) { - return utils.RunCommand([]string{e.Name, "rm", ctrID}) -} - -func (e *CtrEngine) GetRootfs(ctrID string, dir string) error { - cmd1 := exec.Command(e.Name, "export", ctrID) - cmd2 := exec.Command("tar", "-C", dir, "-xvf", "-") - - cmd1Stdout, err := cmd1.StdoutPipe() - if err != nil { - return err - } - - cmd2.Stdin = cmd1Stdout - - err = cmd2.Start() - if err != nil { - return err - } - - err = cmd1.Run() - if err != nil { - return err - } - - err = cmd2.Wait() - if err != nil { - return err - } - - return nil -} diff --git a/src/runtime/pkg/katautils/create_test.go b/src/runtime/pkg/katautils/create_test.go index 46693fcaa6..910ff18a18 100644 --- a/src/runtime/pkg/katautils/create_test.go +++ b/src/runtime/pkg/katautils/create_test.go @@ -8,7 +8,6 @@ package katautils import ( "context" - "encoding/json" "errors" "fmt" "io/ioutil" @@ -20,7 +19,6 @@ import ( "testing" ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" - "github.com/kata-containers/kata-containers/src/runtime/pkg/utils" vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/compatoci" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/oci" @@ -37,8 +35,6 @@ const ( ) var ( - testBundleDir = "" - // testingImpl is a concrete mock RVC implementation used for testing testingImpl = &vcmock.VCMock{} // mock sandbox @@ -53,49 +49,6 @@ func init() { tc = ktu.NewTestConstraint(false) } -func writeOCIConfigFile(spec specs.Spec, configPath string) error { - if configPath == "" { - return errors.New("BUG: need config file path") - } - - bytes, err := json.MarshalIndent(spec, "", "\t") - if err != nil { - return err - } - - return ioutil.WriteFile(configPath, bytes, testFileMode) -} - -// Create an OCI bundle in the specified directory. -// -// Note that the directory will be created, but it's parent is expected to exist. -// -// This function works by copying the already-created test bundle. Ideally, -// the bundle would be recreated for each test, but createRootfs() uses -// docker which on some systems is too slow, resulting in the tests timing -// out. -func makeOCIBundle(bundleDir string) error { - from := testBundleDir - to := bundleDir - - // only the basename of bundleDir needs to exist as bundleDir - // will get created by cp(1). - base := filepath.Dir(bundleDir) - - for _, dir := range []string{from, base} { - if !FileExists(dir) { - return fmt.Errorf("BUG: directory %v should exist", dir) - } - } - - output, err := utils.RunCommandFull([]string{"cp", "-a", from, to}, true) - if err != nil { - return fmt.Errorf("failed to copy test OCI bundle from %v to %v: %v (output: %v)", from, to, err, output) - } - - return nil -} - // newTestRuntimeConfig creates a new RuntimeConfig func newTestRuntimeConfig(dir, consolePath string, create bool) (oci.RuntimeConfig, error) { if dir == "" { @@ -262,21 +215,12 @@ func TestSetKernelParamsUserOptionTakesPriority(t *testing.T) { func TestCreateSandboxConfigFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, _ := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -305,21 +249,12 @@ func TestCreateSandboxFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, _ := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true) assert.NoError(err) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -375,18 +310,9 @@ func TestCheckForFips(t *testing.T) { func TestCreateContainerContainerConfigFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -396,7 +322,7 @@ func TestCreateContainerContainerConfigFail(t *testing.T) { spec.Annotations[testContainerTypeAnnotation] = containerType // rewrite file - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) rootFs := vc.RootFs{Mounted: true} @@ -412,18 +338,9 @@ func TestCreateContainerContainerConfigFail(t *testing.T) { func TestCreateContainerFail(t *testing.T) { assert := assert.New(t) - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -433,7 +350,7 @@ func TestCreateContainerFail(t *testing.T) { spec.Annotations[testSandboxIDAnnotation] = testSandboxID // rewrite file - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) rootFs := vc.RootFs{Mounted: true} @@ -456,18 +373,9 @@ func TestCreateContainer(t *testing.T) { mockSandbox.CreateContainerFunc = nil }() - tmpdir, err := ioutil.TempDir("", "") - assert.NoError(err) + tmpdir, bundlePath, ociConfigFile := ktu.SetupOCIConfigFile(t) defer os.RemoveAll(tmpdir) - bundlePath := filepath.Join(tmpdir, "bundle") - - err = makeOCIBundle(bundlePath) - assert.NoError(err) - - ociConfigFile := filepath.Join(bundlePath, "config.json") - assert.True(FileExists(ociConfigFile)) - spec, err := compatoci.ParseConfigJSON(bundlePath) assert.NoError(err) @@ -477,7 +385,7 @@ func TestCreateContainer(t *testing.T) { spec.Annotations[testSandboxIDAnnotation] = testSandboxID // rewrite file - err = writeOCIConfigFile(spec, ociConfigFile) + err = ktu.WriteOCIConfigFile(spec, ociConfigFile) assert.NoError(err) rootFs := vc.RootFs{Mounted: true} diff --git a/src/runtime/pkg/katautils/utils_test.go b/src/runtime/pkg/katautils/utils_test.go index af95931184..30ad2ccc7c 100644 --- a/src/runtime/pkg/katautils/utils_test.go +++ b/src/runtime/pkg/katautils/utils_test.go @@ -7,20 +7,15 @@ package katautils import ( - "errors" "fmt" "io/ioutil" "os" - "os/exec" "path" "path/filepath" - "strings" "syscall" "testing" ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" - "github.com/kata-containers/kata-containers/src/runtime/pkg/utils" - "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/compatoci" "github.com/stretchr/testify/assert" ) @@ -28,173 +23,14 @@ const ( testDirMode = os.FileMode(0750) testFileMode = os.FileMode(0640) - // small docker image used to create root filesystems from - testDockerImage = "busybox" - testSandboxID = "99999999-9999-9999-99999999999999999" testContainerID = "1" - testBundle = "bundle" - specConfig = "config.json" ) var ( testDir = "" ) -func init() { - var err error - - fmt.Printf("INFO: creating test directory\n") - testDir, err = ioutil.TempDir("", fmt.Sprintf("%s-", NAME)) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create test directory: %v", err)) - } - - fmt.Printf("INFO: test directory is %v\n", testDir) - - testBundleDir = filepath.Join(testDir, testBundle) - err = os.MkdirAll(testBundleDir, testDirMode) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create bundle directory %v: %v", testBundleDir, err)) - } - - fmt.Printf("INFO: creating OCI bundle in %v for tests to use\n", testBundleDir) - err = realMakeOCIBundle(testBundleDir) - if err != nil { - panic(fmt.Sprintf("ERROR: failed to create OCI bundle: %v", err)) - } -} - -// createOCIConfig creates an OCI configuration (spec) file in -// the bundle directory specified (which must exist). -func createOCIConfig(bundleDir string) error { - if bundleDir == "" { - return errors.New("BUG: Need bundle directory") - } - - if !FileExists(bundleDir) { - return fmt.Errorf("BUG: Bundle directory %s does not exist", bundleDir) - } - - var configCmd string - - // Search for a suitable version of runc to use to generate - // the OCI config file. - for _, cmd := range []string{"docker-runc", "runc"} { - fullPath, err := exec.LookPath(cmd) - if err == nil { - configCmd = fullPath - break - } - } - - if configCmd == "" { - return errors.New("Cannot find command to generate OCI config file") - } - - _, err := utils.RunCommand([]string{configCmd, "spec", "--bundle", bundleDir}) - if err != nil { - return err - } - - specFile := filepath.Join(bundleDir, specConfig) - if !FileExists(specFile) { - return fmt.Errorf("generated OCI config file does not exist: %v", specFile) - } - - return nil -} - -// realMakeOCIBundle will create an OCI bundle (including the "config.json" -// config file) in the directory specified (which must already exist). -// -// XXX: Note that tests should *NOT* call this function - they should -// XXX: instead call makeOCIBundle(). -func realMakeOCIBundle(bundleDir string) error { - if bundleDir == "" { - return errors.New("BUG: Need bundle directory") - } - - if !FileExists(bundleDir) { - return fmt.Errorf("BUG: Bundle directory %v does not exist", bundleDir) - } - - err := createOCIConfig(bundleDir) - if err != nil { - return err - } - - // Note the unusual parameter (a directory, not the config - // file to parse!) - spec, err := compatoci.ParseConfigJSON(bundleDir) - if err != nil { - return err - } - - // Determine the rootfs directory name the OCI config refers to - ociRootPath := spec.Root.Path - - rootfsDir := filepath.Join(bundleDir, ociRootPath) - - if strings.HasPrefix(ociRootPath, "/") { - return fmt.Errorf("Cannot handle absolute rootfs as bundle must be unique to each test") - } - - err = createRootfs(rootfsDir) - if err != nil { - return err - } - - return nil -} - -// createRootfs creates a minimal root filesystem below the specified -// directory. -func createRootfs(dir string) error { - var ( - output string - err error - ) - - ctrEngine := CtrEngine{} - for _, name := range DockerLikeCtrEngines { - fmt.Printf("INFO: checking for container engine: %s\n", name) - - output, err = ctrEngine.Init(name) - if err == nil { - break - } - } - - if ctrEngine.Name == "" { - panic(fmt.Sprintf("ERROR: Docker-like container engine not accessible to current user: %v (error %v)", - output, err)) - } - - err = os.MkdirAll(dir, testDirMode) - if err != nil { - return err - } - - container, err := ctrEngine.Create(testDockerImage) - if err != nil { - return err - } - - err = ctrEngine.GetRootfs(container, dir) - if err != nil { - return err - } - - // Clean up - _, err = ctrEngine.Rm(container) - if err != nil { - return err - } - - return nil -} - func createFile(file, contents string) error { return ioutil.WriteFile(file, []byte(contents), testFileMode) }