Add and use bin2img for creating images for tests
Add tests which exercise image pulling, listing, and removal. When running tests, prepopulate the store with an image with the default infrastructure container's name, using the locally-built "pause" binary, so that tests won't have to pull it down from the network. Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
parent
c0333b102b
commit
636d5d8e9a
6 changed files with 337 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ pause/pause.o
|
||||||
ocid.conf
|
ocid.conf
|
||||||
*.orig
|
*.orig
|
||||||
*.rej
|
*.rej
|
||||||
|
test/bin2img/bin2img
|
||||||
|
|
7
Makefile
7
Makefile
|
@ -44,6 +44,9 @@ conmon:
|
||||||
pause:
|
pause:
|
||||||
make -C $@
|
make -C $@
|
||||||
|
|
||||||
|
bin2img:
|
||||||
|
make -C test/$@
|
||||||
|
|
||||||
ocid:
|
ocid:
|
||||||
ifndef GOPATH
|
ifndef GOPATH
|
||||||
$(error GOPATH is not set)
|
$(error GOPATH is not set)
|
||||||
|
@ -73,6 +76,7 @@ clean:
|
||||||
find . -name \#\* -delete
|
find . -name \#\* -delete
|
||||||
make -C conmon clean
|
make -C conmon clean
|
||||||
make -C pause clean
|
make -C pause clean
|
||||||
|
make -C test/bin2img clean
|
||||||
|
|
||||||
ocidimage:
|
ocidimage:
|
||||||
docker build -t ${OCID_IMAGE} .
|
docker build -t ${OCID_IMAGE} .
|
||||||
|
@ -86,7 +90,7 @@ integration: ocidimage
|
||||||
localintegration: binaries
|
localintegration: binaries
|
||||||
./test/test_runner.sh ${TESTFLAGS}
|
./test/test_runner.sh ${TESTFLAGS}
|
||||||
|
|
||||||
binaries: ocid ocic kpod conmon pause
|
binaries: ocid ocic kpod conmon pause bin2img
|
||||||
|
|
||||||
MANPAGES_MD := $(wildcard docs/*.md)
|
MANPAGES_MD := $(wildcard docs/*.md)
|
||||||
MANPAGES := $(MANPAGES_MD:%.md=%)
|
MANPAGES := $(MANPAGES_MD:%.md=%)
|
||||||
|
@ -180,6 +184,7 @@ install.tools: .install.gitvalidation .install.gometalinter .install.md2man
|
||||||
go get -u github.com/cpuguy83/go-md2man
|
go get -u github.com/cpuguy83/go-md2man
|
||||||
|
|
||||||
.PHONY: \
|
.PHONY: \
|
||||||
|
bin2img \
|
||||||
binaries \
|
binaries \
|
||||||
clean \
|
clean \
|
||||||
conmon \
|
conmon \
|
||||||
|
|
6
test/bin2img/Makefile
Normal file
6
test/bin2img/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
bin2img: $(wildcard *.go)
|
||||||
|
go build -o $@
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f bin2img
|
225
test/bin2img/bin2img.go
Normal file
225
test/bin2img/bin2img.go
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/containers/image/storage"
|
||||||
|
"github.com/containers/image/types"
|
||||||
|
"github.com/containers/storage/pkg/reexec"
|
||||||
|
sstorage "github.com/containers/storage/storage"
|
||||||
|
digest "github.com/opencontainers/go-digest"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go"
|
||||||
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if reexec.Init() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = "bin2img"
|
||||||
|
app.Usage = "barebones image builder"
|
||||||
|
app.Version = "0.0.1"
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "debug",
|
||||||
|
Usage: "turn on debug logging",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "root",
|
||||||
|
Usage: "graph root directory",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "runroot",
|
||||||
|
Usage: "run root directory",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "storage-driver",
|
||||||
|
Usage: "storage driver",
|
||||||
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "storage-option",
|
||||||
|
Usage: "storage option",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "image-name",
|
||||||
|
Usage: "set image name",
|
||||||
|
Value: "kubernetes/pause",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "source-binary",
|
||||||
|
Usage: "source binary",
|
||||||
|
Value: "../../pause/pause",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "image-binary",
|
||||||
|
Usage: "image binary",
|
||||||
|
Value: "/pause",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
debug := c.GlobalBool("debug")
|
||||||
|
rootDir := c.GlobalString("root")
|
||||||
|
runrootDir := c.GlobalString("runroot")
|
||||||
|
storageDriver := c.GlobalString("storage-driver")
|
||||||
|
storageOptions := c.GlobalStringSlice("storage-option")
|
||||||
|
imageName := c.GlobalString("image-name")
|
||||||
|
sourceBinary := c.GlobalString("source-binary")
|
||||||
|
imageBinary := c.GlobalString("image-binary")
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
} else {
|
||||||
|
logrus.SetLevel(logrus.ErrorLevel)
|
||||||
|
}
|
||||||
|
if rootDir == "" && runrootDir != "" {
|
||||||
|
logrus.Errorf("must set --root and --runroot, or neither")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if rootDir != "" && runrootDir == "" {
|
||||||
|
logrus.Errorf("must set --root and --runroot, or neither")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
storeOptions := sstorage.DefaultStoreOptions
|
||||||
|
if rootDir != "" && runrootDir != "" {
|
||||||
|
storeOptions.GraphDriverName = storageDriver
|
||||||
|
storeOptions.GraphDriverOptions = storageOptions
|
||||||
|
storeOptions.GraphRoot = rootDir
|
||||||
|
storeOptions.RunRoot = runrootDir
|
||||||
|
}
|
||||||
|
store, err := sstorage.GetStore(storeOptions)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error opening storage: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer store.Shutdown(false)
|
||||||
|
|
||||||
|
layerBuffer := &bytes.Buffer{}
|
||||||
|
binary, err := os.Open(sourceBinary)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error opening image binary: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
binInfo, err := binary.Stat()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error statting image binary: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
archive := tar.NewWriter(layerBuffer)
|
||||||
|
err = archive.WriteHeader(&tar.Header{
|
||||||
|
Name: imageBinary,
|
||||||
|
Size: binInfo.Size(),
|
||||||
|
Mode: 0555,
|
||||||
|
ModTime: binInfo.ModTime(),
|
||||||
|
Typeflag: tar.TypeReg,
|
||||||
|
Uname: "root",
|
||||||
|
Gname: "root",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error writing archive header: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(archive, binary)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error archiving image binary: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
archive.Close()
|
||||||
|
binary.Close()
|
||||||
|
layerInfo := types.BlobInfo{
|
||||||
|
Digest: digest.Canonical.FromBytes(layerBuffer.Bytes()),
|
||||||
|
Size: int64(layerBuffer.Len()),
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, err := storage.Transport.ParseStoreReference(store, imageName)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error parsing image name: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
img, err := ref.NewImageDestination(nil)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error preparing to write image: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer img.Close()
|
||||||
|
layer, err := img.PutBlob(layerBuffer, layerInfo)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error preparing to write image: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
config := &v1.Image{
|
||||||
|
Architecture: runtime.GOARCH,
|
||||||
|
OS: runtime.GOOS,
|
||||||
|
Config: v1.ImageConfig{
|
||||||
|
User: "root",
|
||||||
|
Entrypoint: []string{imageBinary},
|
||||||
|
},
|
||||||
|
RootFS: v1.RootFS{
|
||||||
|
Type: "layers",
|
||||||
|
DiffIDs: []string{
|
||||||
|
layer.Digest.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cbytes, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error encoding configuration: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
configInfo := types.BlobInfo{
|
||||||
|
Digest: digest.Canonical.FromBytes(cbytes),
|
||||||
|
Size: int64(len(cbytes)),
|
||||||
|
}
|
||||||
|
configInfo, err = img.PutBlob(bytes.NewBuffer(cbytes), configInfo)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error saving configuration: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
manifest := &v1.Manifest{
|
||||||
|
Versioned: specs.Versioned{
|
||||||
|
SchemaVersion: 2,
|
||||||
|
MediaType: v1.MediaTypeImageManifest,
|
||||||
|
},
|
||||||
|
Config: v1.Descriptor{
|
||||||
|
MediaType: v1.MediaTypeImageConfig,
|
||||||
|
Digest: configInfo.Digest.String(),
|
||||||
|
Size: int64(len(cbytes)),
|
||||||
|
},
|
||||||
|
Layers: []v1.Descriptor{{
|
||||||
|
MediaType: v1.MediaTypeImageLayer,
|
||||||
|
Digest: layer.Digest.String(),
|
||||||
|
Size: layer.Size,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
mbytes, err := json.Marshal(manifest)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error encoding manifest: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = img.PutManifest(mbytes)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error saving manifest: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = img.Commit()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("error committing image: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,8 @@ APPARMOR_TEST_PROFILE_NAME=${APPARMOR_TEST_PROFILE_NAME:-apparmor-test-deny-writ
|
||||||
BOOT_CONFIG_FILE_PATH=${BOOT_CONFIG_FILE_PATH:-/boot/config-`uname -r`}
|
BOOT_CONFIG_FILE_PATH=${BOOT_CONFIG_FILE_PATH:-/boot/config-`uname -r`}
|
||||||
# Path of apparmor parameters file.
|
# Path of apparmor parameters file.
|
||||||
APPARMOR_PARAMETERS_FILE_PATH=${APPARMOR_PARAMETERS_FILE_PATH:-/sys/module/apparmor/parameters/enabled}
|
APPARMOR_PARAMETERS_FILE_PATH=${APPARMOR_PARAMETERS_FILE_PATH:-/sys/module/apparmor/parameters/enabled}
|
||||||
|
# Path of the bin2img binary.
|
||||||
|
BIN2IMG_BINARY=${BIN2IMG_BINARY:-${OCID_ROOT}/cri-o/test/bin2img/bin2img}
|
||||||
|
|
||||||
TESTDIR=$(mktemp -d)
|
TESTDIR=$(mktemp -d)
|
||||||
if [ -e /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
|
if [ -e /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
|
||||||
|
@ -112,6 +114,10 @@ function start_ocid() {
|
||||||
apparmor="$APPARMOR_PROFILE"
|
apparmor="$APPARMOR_PROFILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Don't forget: bin2img and ocid have their own default drivers, so if you override either, you probably need to override both
|
||||||
|
if ! [ "$3" = "--no-pause-image" ] ; then
|
||||||
|
"$BIN2IMG_BINARY" --root "$TESTDIR/ocid" --runroot "$TESTDIR/ocid-run" --source-binary "$PAUSE_BINARY"
|
||||||
|
fi
|
||||||
"$OCID_BINARY" --conmon "$CONMON_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNC_BINARY" --root "$TESTDIR/ocid" --runroot "$TESTDIR/ocid-run" --seccomp-profile "$seccomp" --apparmor-profile "$apparmor" --cni-config-dir "$OCID_CNI_CONFIG" --signature-policy "$INTEGRATION_ROOT"/policy.json config >$OCID_CONFIG
|
"$OCID_BINARY" --conmon "$CONMON_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNC_BINARY" --root "$TESTDIR/ocid" --runroot "$TESTDIR/ocid-run" --seccomp-profile "$seccomp" --apparmor-profile "$apparmor" --cni-config-dir "$OCID_CNI_CONFIG" --signature-policy "$INTEGRATION_ROOT"/policy.json config >$OCID_CONFIG
|
||||||
"$OCID_BINARY" --debug --config "$OCID_CONFIG" & OCID_PID=$!
|
"$OCID_BINARY" --debug --config "$OCID_CONFIG" & OCID_PID=$!
|
||||||
wait_until_reachable
|
wait_until_reachable
|
||||||
|
|
93
test/image.bats
Normal file
93
test/image.bats
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
load helpers
|
||||||
|
|
||||||
|
IMAGE=kubernetes/pause
|
||||||
|
|
||||||
|
function teardown() {
|
||||||
|
cleanup_test
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "image pull" {
|
||||||
|
start_ocid "" "" --no-pause-image
|
||||||
|
run ocic image pull "$IMAGE"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
cleanup_images
|
||||||
|
stop_ocid
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "image list with filter" {
|
||||||
|
start_ocid "" "" --no-pause-image
|
||||||
|
run ocic image pull "$IMAGE"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ocic image list --quiet "$IMAGE"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
printf '%s\n' "$output" | while IFS= read -r id; do
|
||||||
|
run ocic image remove --id "$id"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
done
|
||||||
|
run ocic image list --quiet
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
printf '%s\n' "$output" | while IFS= read -r id; do
|
||||||
|
echo "$id"
|
||||||
|
status=1
|
||||||
|
done
|
||||||
|
cleanup_images
|
||||||
|
stop_ocid
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "image list/remove" {
|
||||||
|
start_ocid "" "" --no-pause-image
|
||||||
|
run ocic image pull "$IMAGE"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ocic image list --quiet
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
printf '%s\n' "$output" | while IFS= read -r id; do
|
||||||
|
run ocic image remove --id "$id"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
done
|
||||||
|
run ocic image list --quiet
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
printf '%s\n' "$output" | while IFS= read -r id; do
|
||||||
|
echo "$id"
|
||||||
|
status=1
|
||||||
|
done
|
||||||
|
cleanup_images
|
||||||
|
stop_ocid
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "image status/remove" {
|
||||||
|
start_ocid "" "" --no-pause-image
|
||||||
|
run ocic image pull "$IMAGE"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ocic image list --quiet
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
printf '%s\n' "$output" | while IFS= read -r id; do
|
||||||
|
run ocic image status --id "$id"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ocic image remove --id "$id"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
done
|
||||||
|
run ocic image list --quiet
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
printf '%s\n' "$output" | while IFS= read -r id; do
|
||||||
|
echo "$id"
|
||||||
|
status=1
|
||||||
|
done
|
||||||
|
cleanup_images
|
||||||
|
stop_ocid
|
||||||
|
}
|
Loading…
Reference in a new issue