containerd/integration-test/bundle_utils_test.go

116 lines
3 KiB
Go
Raw Normal View History

package main
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"reflect"
ocs "github.com/opencontainers/runtime-spec/specs-go"
)
var (
bundlesDir = filepath.Join("test-artifacts", "oci-bundles")
refOciSpecsPath = filepath.Join(bundlesDir, "config.json")
)
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 {
destination = filepath.Join(destination, "rootfs")
if err := os.MkdirAll(destination, 0755); err != nil {
return nil
}
tar := exec.Command("tar", "-C", destination, "-xf", source)
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
if f, err := os.Open(refOciSpecsPath); err != nil {
return fmt.Errorf("Failed to open default spec: %v", err)
} else {
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(bundlesDir, 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)
if err := untarRootfs(filepath.Join(archivesDir, source+".tar"), 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)
}