containerd/integration-test/bundle_utils_test.go

131 lines
3.3 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"reflect"
"runtime"
utils "github.com/containerd/containerd/testutils"
ocs "github.com/opencontainers/runtime-spec/specs-go"
)
type OciProcessArgs struct {
Cmd string
Args []string
}
type Bundle struct {
Source string
Name string
Spec ocs.Spec
Path string
}
var bundleMap map[string]Bundle
// untarRootfs untars the given `source` tarPath into `destination/rootfs`
func untarRootfs(source string, destination string) error {
var tar *exec.Cmd
if runtime.GOOS == "solaris" {
destination = filepath.Join(destination, "/rootfs/root")
tar = exec.Command("gtar", "-C", destination, "-xf", source)
} else {
destination = filepath.Join(destination, "rootfs")
tar = exec.Command("tar", "-C", destination, "-xf", source)
}
if err := os.MkdirAll(destination, 0755); err != nil {
return nil
}
return tar.Run()
}
// CreateBundleWithFilter generate a new oci-bundle named `name` from
// the provide `source` rootfs. It starts from the default spec
// generated by `runc spec`, overrides the `spec.Process.Args` value
// with `args` and set `spec.Process.Terminal` to false. It then apply
// `filter()` to the resulting spec if it is provided.
func CreateBundleWithFilter(source, name string, args []string, filter func(spec *ocs.Spec)) error {
// Generate the spec
var spec ocs.Spec
f, err := os.Open(utils.RefOciSpecsPath)
if err != nil {
return fmt.Errorf("Failed to open default spec: %v", err)
}
if err := json.NewDecoder(f).Decode(&spec); err != nil {
return fmt.Errorf("Failed to load default spec: %v", err)
}
f.Close()
spec.Process.Args = args
spec.Process.Terminal = false
if filter != nil {
filter(&spec)
}
bundlePath := filepath.Join(utils.BundlesRoot, name)
nb := Bundle{source, name, spec, bundlePath}
// Check that we don't already have such a bundle
if b, ok := bundleMap[name]; ok {
if reflect.DeepEqual(b, nb) == false {
return fmt.Errorf("A bundle name named '%s' already exist but with different properties! %#v != %#v",
name, b, nb)
}
return nil
}
// Nothing should be there, but just in case
os.RemoveAll(bundlePath)
var sourceStr string
if runtime.GOOS == "solaris" {
sourceStr = source + ".tar.gz"
} else {
sourceStr = source + ".tar"
}
if err := untarRootfs(filepath.Join(utils.ArchivesDir, sourceStr), bundlePath); err != nil {
return fmt.Errorf("Failed to untar %s.tar: %v", source, err)
}
// create a place for the io fifo
if err := os.Mkdir(filepath.Join(bundlePath, "io"), 0755); err != nil {
return fmt.Errorf("Failed to create bundle io directory: %v", err)
}
// Write the updated spec to the right location
config, e := os.Create(filepath.Join(bundlePath, "config.json"))
if e != nil {
return fmt.Errorf("Failed to create oci spec: %v", e)
}
defer config.Close()
if err := json.NewEncoder(config).Encode(&spec); err != nil {
return fmt.Errorf("Failed to encore oci spec: %v", e)
}
bundleMap[name] = nb
return nil
}
func GetBundle(name string) *Bundle {
bundle, ok := bundleMap[name]
if !ok {
return nil
}
return &bundle
}
func CreateBusyboxBundle(name string, args []string) error {
return CreateBundleWithFilter("busybox", name, args, nil)
}
func CreateSolarisBundle(name string, args []string) error {
return CreateBundleWithFilter("rootfs", name, args, nil)
}