Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/linters/urunc-dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,9 @@ hyperlight
Hyperlight
Odysseas
Kalaitsidis
nsexec
specconv
Readonlyfs
capab
werr
cerr
42 changes: 42 additions & 0 deletions .github/workflows/kind_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,48 @@ jobs:
grep "Hello world" /tmp/logs.txt
kubectl describe pod hello-spt-rumprun-block || true

# Re-run the hello-world deployment with urunc's libcontainer runtime
# enabled, reusing the same kind cluster and urunc install.
- name: Deploy and verify with libcontainer
run: |
docker exec urunc-test-control-plane bash -c '
cat >> /etc/urunc/config.toml <<EOF

[runtime]
libcontainer = true
EOF
'
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: hello-libcontainer
labels:
run: hello-libcontainer
spec:
runtimeClassName: urunc
restartPolicy: Never
containers:
- name: hello-libcontainer
image: harbor.nbfc.io/nubificus/urunc/hello-spt-rumprun-block:latest
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
resources:
requests:
cpu: 10m
EOF
kubectl wait --for=condition=Succeeded pod/hello-libcontainer --timeout=180s || true
kubectl logs hello-libcontainer | tee /tmp/logs-libcontainer.txt
if ! grep "Hello world" /tmp/logs-libcontainer.txt; then
echo "=== LOGS (libcontainer) ==="
cat /tmp/logs-libcontainer.txt
kubectl describe pod hello-libcontainer || true
exit 1
fi
kubectl describe pod hello-libcontainer || true

- name: Debug pod failure
if: failure()
run: |
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/vm_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,24 @@ jobs:
sudo -E env "PATH=$PATH" "GOROOT=$GOROOT" make ${{ matrix.test }}
fi

# Re-run the same suite with urunc's libcontainer runtime enabled,
# changinthe configuration.
- name: Run ${{ matrix.test }} with libcontainer
id: test_libcontainer
run: |
sudo tee -a /etc/urunc/config.toml > /dev/null <<'EOF'

[runtime]
libcontainer = true
EOF
export GOROOT=$(go env GOROOT)
export PATH="$GOROOT/bin:$PATH"
if [ "${{ matrix.arch }}" = "arm64" ]; then
sudo -E env "PATH=$PATH" "GOROOT=$GOROOT" make ${{ matrix.test }}_Spt
else
sudo -E env "PATH=$PATH" "GOROOT=$GOROOT" make ${{ matrix.test }} SKIP="Firecracker-unikraft-httpreply-static-net"
fi

- name: Dump urunc logs on failure
if: failure()
run: |
Expand Down
20 changes: 12 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ CGO := CGO_ENABLED=1
NOCGO := CGO_ENABLED=0
TEST_FLAGS := "-count=1"
TEST_OPTS += -timeout 20m
# Skip the execution of a test
# make test_crictl SKIP="Firecracker-unikraft-httpreply-static-net"
# make test_crictl SKIP="Crictl.*(CaseA|CaseB)"
GINKGO_SKIP := $(if $(SKIP),--ginkgo.skip="$(SKIP)")
BUILD_TAGS ?= netgo osusergo

# Linking variables
Expand Down Expand Up @@ -273,56 +277,56 @@ test_unikernels:
.PHONY: test_nerdctl
test_nerdctl:
@echo "Testing nerdctl"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Nerdctl"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Nerdctl" $(GINKGO_SKIP)
@echo " "

## test_ctr Run all end-to-end tests with ctr
.PHONY: test_ctr
test_ctr:
@echo "Testing ctr"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Ctr"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Ctr" $(GINKGO_SKIP)
@echo " "

## test_crictl Run all end-to-end tests with crictl
.PHONY: test_crictl
test_crictl:
@echo "Testing crictl"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Crictl"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Crictl" $(GINKGO_SKIP)
@echo " "

## test_docker Run all end-to-end tests with docker
.PHONY: test_docker
test_docker:
@echo "Testing docker"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Docker"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -run TestE2E -v --ginkgo.v --ginkgo.focus="Docker" $(GINKGO_SKIP)
@echo " "

## test_nerdctl_[pattern] Run all end-to-end tests with nerdctl that match pattern
.PHONY: test_nerdctl_%
test_nerdctl_%:
@echo "Testing nerdctl"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Nerdctl.*$*"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Nerdctl.*$*" $(GINKGO_SKIP)
@echo " "

## test_ctr_[pattern] Run all end-to-end tests with ctr that match pattern
.PHONY: test_ctr_%
test_ctr_%:
@echo "Testing ctr"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Ctr.*$*"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Ctr.*$*" $(GINKGO_SKIP)
@echo " "

## test_crictl_[pattern] Run all end-to-end tests with crictl that match pattern
.PHONY: test_crictl_%
test_crictl_%:
@echo "Testing crictl"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Crictl.*$*"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Crictl.*$*" $(GINKGO_SKIP)
@echo " "

## test_docker_[pattern] Run all end-to-end tests with docker that match pattern
.PHONY: test_docker_%
test_docker_%:
@echo "Testing docker"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Docker.*$*"
@GOFLAGS=$(TEST_FLAGS) $(GO) test $(TEST_OPTS) ./tests/e2e -v --ginkgo.v -run TestE2E --ginkgo.focus="Docker.*$*" $(GINKGO_SKIP)
@echo " "

## help Show this help message
Expand Down
55 changes: 35 additions & 20 deletions cmd/urunc/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,28 @@ var createCommand = &cli.Command{
if err := checkArgs(cmd, 1, exactArgs); err != nil {
return err
}
if !cmd.Bool("reexec") {
uruncCfg, _ := unikontainers.LoadUruncConfig(unikontainers.UruncConfigPath) // ignore the error and use default config
return createUnikontainer(cmd, uruncCfg)
if cmd.Bool("reexec") {
return reexecUnikontainer(cmd)
}

return reexecUnikontainer(cmd)
uruncCfg, _ := unikontainers.LoadUruncConfig(unikontainers.UruncConfigPath) // ignore the error and use default config
if uruncCfg.Runtime.Libcontainer {
return libcontainerCreate(cmd, uruncCfg)
}

return createUnikontainer(cmd, uruncCfg)
},
}

// createUnikontainer creates a Unikernel struct from bundle data,
// initializes it's base dir and state.json,
// setups terminal if required and spawns reexec process,
// waits for reexec process to notify, executes CreateRuntime hooks,
// sends ACK to reexec process
func createUnikontainer(cmd *cli.Command, uruncCfg *unikontainers.UruncConfig) (err error) {
err = nil
// newUnikontainer parses the bundle and performs the host-side preparation for
// the monitor execution environment (Unikontainer, base directory, state and
// monitor resources). It never returns for a container that is not a urunc
// container: those are handed over to the real runc with an execve.
func newUnikontainer(cmd *cli.Command, uruncCfg *unikontainers.UruncConfig) (*unikontainers.Unikontainer, error) {
containerID := cmd.Args().First()
if err = validateID(containerID); err != nil {
return err
err := validateID(containerID)
if err != nil {
return nil, err
}
metrics.SetLoggerContainerID(containerID)
metrics.Capture(m.TS00)
Expand All @@ -105,7 +108,7 @@ func createUnikontainer(cmd *cli.Command, uruncCfg *unikontainers.UruncConfig) (
if bundlePath == "" {
bundlePath, err = os.Getwd()
if err != nil {
return err
return nil, err
}
}

Expand All @@ -114,21 +117,33 @@ func createUnikontainer(cmd *cli.Command, uruncCfg *unikontainers.UruncConfig) (
if err != nil {
if errors.Is(err, unikontainers.ErrQueueProxy) ||
errors.Is(err, unikontainers.ErrNotUnikernel) {
// Exec runc to handle non unikernel containers
err = runcExec()
return err
// Exec runc to handle non urunc containers.
// It should never return.
return nil, runcExec()
}
return err
return nil, err
}
metrics.Capture(m.TS01)

err = unikontainer.InitialSetup()
if err != nil {
return err
return nil, err
}

metrics.Capture(m.TS02)

return unikontainer, nil
}

// createUnikontainer creates a Unikernel struct from bundle data, initializes
// it's base dir and state.json, setups terminal if required and spawns reexec
// process, waits for reexec process to notify, executes CreateRuntime hooks,
// sends ACK to reexec process
func createUnikontainer(cmd *cli.Command, uruncCfg *unikontainers.UruncConfig) (err error) {
unikontainer, err := newUnikontainer(cmd, uruncCfg)
if err != nil {
return err
}

// Create socket for nsenter
initSockParent, initSockChild, err := newSockPair("init")
if err != nil {
Expand Down
Loading
Loading