mirror of
				https://github.com/kata-containers/kata-containers.git
				synced 2025-10-31 09:26:52 +00:00 
			
		
		
		
	runtime: optimize test code
This PR includes these optimize changes: - Remove the dependency on the container engine. The old code uses runc to generate config.json and Docker to export rootfs, that will be heavy and need additional dependency. Using a fixed config for busybox image can avoid the heavy processing above. - Moved duplicate code to pkg/katatestutils package Fixes: #2752 Signed-off-by: bin <bin@hyper.sh>
This commit is contained in:
		| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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{} | ||||
| ) | ||||
|  | ||||
| // 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) | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
| 	} | ||||
|   | ||||
| @@ -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{ | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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") | ||||
|   | ||||
| @@ -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") | ||||
|   | ||||
| @@ -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{} | ||||
| ) | ||||
|  | ||||
| // 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) | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,6 @@ import ( | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	testFileMode    = os.FileMode(0640) | ||||
| 	invalidOperator = 1234 | ||||
|  | ||||
| 	skipUnknownDistroName = "skipping test as cannot determine distro name" | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
| @@ -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} | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user