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
2 changes: 1 addition & 1 deletion Dockerfile.d/test-integration-rootless.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
set -eux -o pipefail
if [[ "$(id -u)" = "0" ]]; then
if [ -e /sys/kernel/security/apparmor/profiles ]; then
# Load the "prefix-default" profile for TestRunApparmor
# Load the default profile for TestRunApparmor
nerdctl apparmor load
fi

Expand Down
1 change: 0 additions & 1 deletion cmd/nerdctl/builder/builder_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ func TestBuildFromContainerd(t *testing.T) {
Setup: func(data test.Data, helpers test.Helpers) {
helpers.Ensure("pull", "--quiet", testutil.CommonImage)
helpers.Ensure("tag", testutil.CommonImage, data.Identifier("first"))

dockerfile := fmt.Sprintf(`FROM %s
RUN echo hello2 > /hello2
CMD ["cat", "/hello2"]`, data.Identifier("first"))
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/compose/compose_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ services:
defer comp.CleanUp()

// `--hash=*` is broken in Docker Compose v2.23.0: https://github.com/docker/compose/issues/11145
if base.Target == testutil.Nerdctl {
if base.Target == testutil.Nerdishctl {
base.ComposeCmd("-f", comp.YAMLFullPath(), "config", "--hash=*").AssertOutContains("hello1")
}

Expand Down
107 changes: 107 additions & 0 deletions cmd/nerdctl/image/image_remove_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
Copyright The containerd Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package image

import (
"testing"

"github.com/containerd/nerdctl/v2/pkg/testutil"
)

func TestRemoveImage(t *testing.T) {
base := testutil.NewBase(t)
tID := testutil.Identifier(t)
base.Cmd("image", "prune", "--force", "--all").AssertOK()

// ignore error
base.Cmd("rmi", "-f", tID).AssertOK()

base.Cmd("run", "--name", tID, testutil.CommonImage).AssertOK()
defer base.Cmd("rm", "-f", tID).AssertOK()

base.Cmd("rmi", testutil.CommonImage).AssertFail()
defer base.Cmd("rmi", "-f", testutil.CommonImage).Run()
base.Cmd("rmi", "-f", testutil.CommonImage).AssertOK()

base.Cmd("images").AssertOutNotContains(testutil.ImageRepo(testutil.CommonImage))
}

func TestRemoveRunningImage(t *testing.T) {
// If an image is associated with a running/paused containers, `docker rmi -f imageName`
// untags `imageName` (left a `<none>` image) without deletion; `docker rmi -rf imageID` fails.
// In both cases, `rmi -f` will fail.
testutil.DockerIncompatible(t)
base := testutil.NewBase(t)
tID := testutil.Identifier(t)

base.Cmd("run", "--name", tID, "-d", testutil.CommonImage, "sleep", "infinity").AssertOK()
defer base.Cmd("rm", "-f", tID).AssertOK()

base.Cmd("rmi", testutil.CommonImage).AssertFail()
base.Cmd("rmi", "-f", testutil.CommonImage).AssertFail()
base.Cmd("images").AssertOutContains(testutil.ImageRepo(testutil.CommonImage))

base.Cmd("kill", tID).AssertOK()
base.Cmd("rmi", testutil.CommonImage).AssertFail()
base.Cmd("rmi", "-f", testutil.CommonImage).AssertOK()
base.Cmd("images").AssertOutNotContains(testutil.ImageRepo(testutil.CommonImage))
}

func TestRemovePausedImage(t *testing.T) {
// If an image is associated with a running/paused containers, `docker rmi -f imageName`
// untags `imageName` (left a `<none>` image) without deletion; `docker rmi -rf imageID` fails.
// In both cases, `rmi -f` will fail.
testutil.DockerIncompatible(t)
base := testutil.NewBase(t)
switch base.Info().CgroupDriver {
case "none", "":
t.Skip("requires cgroup (for pausing)")
}
tID := testutil.Identifier(t)

base.Cmd("run", "--name", tID, "-d", testutil.CommonImage, "sleep", "infinity").AssertOK()
base.Cmd("pause", tID).AssertOK()
defer base.Cmd("rm", "-f", tID).AssertOK()

base.Cmd("rmi", testutil.CommonImage).AssertFail()
base.Cmd("rmi", "-f", testutil.CommonImage).AssertFail()
base.Cmd("images").AssertOutContains(testutil.ImageRepo(testutil.CommonImage))

base.Cmd("kill", tID).AssertOK()
base.Cmd("rmi", testutil.CommonImage).AssertFail()
base.Cmd("rmi", "-f", testutil.CommonImage).AssertOK()
base.Cmd("images").AssertOutNotContains(testutil.ImageRepo(testutil.CommonImage))
}

func TestRemoveImageWithCreatedContainer(t *testing.T) {
base := testutil.NewBase(t)
tID := testutil.Identifier(t)

base.Cmd("pull", testutil.AlpineImage).AssertOK()
base.Cmd("pull", testutil.NginxAlpineImage).AssertOK()

base.Cmd("create", "--name", tID, testutil.AlpineImage, "sleep", "infinity").AssertOK()
defer base.Cmd("rm", "-f", tID).AssertOK()

base.Cmd("rmi", testutil.AlpineImage).AssertFail()
base.Cmd("rmi", "-f", testutil.AlpineImage).AssertOK()
base.Cmd("images").AssertOutNotContains(testutil.ImageRepo(testutil.AlpineImage))

// a created container with removed image doesn't impact other `rmi` command
base.Cmd("rmi", "-f", testutil.NginxAlpineImage).AssertOK()
base.Cmd("images").AssertOutNotContains(testutil.ImageRepo(testutil.NginxAlpineImage))
}
36 changes: 36 additions & 0 deletions cmd/nerdctl/main_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
Copyright The containerd Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"testing"

"github.com/containerd/nerdctl/v2/pkg/testutil"
)

// TestIssue108 tests https://github.com/containerd/nerdctl/issues/108
// ("`run --net=host -it` fails while `run -it --net=host` works")
func TestIssue108(t *testing.T) {
base := testutil.NewBase(t)
// unbuffer(1) emulates tty, which is required by `run -t`.
// unbuffer(1) can be installed with `apt-get install expect`.
unbuffer := []string{"unbuffer"}
base.CmdWithHelper(unbuffer, "run", "-it", "--rm", "--net=host", testutil.AlpineImage,
"echo", "this was always working").AssertOK()
base.CmdWithHelper(unbuffer, "run", "--rm", "--net=host", "-it", testutil.AlpineImage,
"echo", "this was not working due to issue #108").AssertOK()
}
5 changes: 3 additions & 2 deletions pkg/clientutil/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ func NewClientWithPlatform(ctx context.Context, namespace, address, platform str
return containerd.NewClient(ctx, namespace, address, clientOpts...)
}

// DataStore returns a string like "/var/lib/nerdctl/1935db59".
// DataStore returns a string like "/var/lib/version.RootName/1935db59".
// "1935db9" is from `$(echo -n "/run/containerd/containerd.sock" | sha256sum | cut -c1-8)`
// on Windows it will return "%PROGRAMFILES%/nerdctl/1935db59"
// on Windows it will return "%PROGRAMFILES%/version.RootName/1935db59"
// where `version.RootName` is defined at build time
func DataStore(dataRoot, address string) (string, error) {
if err := os.MkdirAll(dataRoot, 0o700); err != nil {
return "", err
Expand Down
3 changes: 2 additions & 1 deletion pkg/imgutil/commit/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import (
"github.com/containerd/nerdctl/v2/pkg/containerutil"
imgutil "github.com/containerd/nerdctl/v2/pkg/imgutil"
"github.com/containerd/nerdctl/v2/pkg/labels"
"github.com/containerd/nerdctl/v2/pkg/version"
)

type Changes struct {
Expand Down Expand Up @@ -106,7 +107,7 @@ func Commit(ctx context.Context, client *containerd.Client, container containerd
// to commit container created by moby.
baseImgWithoutPlatform, err := client.ImageService().Get(ctx, info.Image)
if err != nil {
return emptyDigest, fmt.Errorf("container %q lacks image (wasn't created by nerdctl?): %w", id, err)
return emptyDigest, fmt.Errorf("container %q lacks image (wasn't created by %s?): %w", id, version.RootName, err)
}
platformLabel := info.Labels[labels.Platform]
if platformLabel == "" {
Expand Down
8 changes: 5 additions & 3 deletions pkg/imgutil/dockerconfigresolver/credentialsstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"testing"

"gotest.tools/v3/assert"

"github.com/containerd/nerdctl/v2/pkg/version"
)

func createTempDir(t *testing.T, mode os.FileMode) string {
Expand Down Expand Up @@ -370,13 +372,13 @@ func TestWorkingCredentialsStore(t *testing.T) {
t.Fatal(err)
}

content := `{
content := fmt.Sprintf(`{
"auths": {
"nerdctl-experimental://namespace.example:443/host/host.example:443/path": {
"%s-experimental://namespace.example:443/host/host.example:443/path": {
"username": "username"
}
}
}`
}`, version.RootName)
dir := writeContent(t, content)
cs, err := NewCredentialsStore(dir)
if err != nil {
Expand Down
6 changes: 4 additions & 2 deletions pkg/imgutil/dockerconfigresolver/registryurl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"testing"

"gotest.tools/v3/assert"

"github.com/containerd/nerdctl/v2/pkg/version"
)

func TestURLParsingAndID(t *testing.T) {
Expand Down Expand Up @@ -149,9 +151,9 @@ func TestURLParsingAndID(t *testing.T) {
},
{
address: "https://registry-host.com/subpath/something?bar=bar&ns=registry-namespace.com&foo=foo",
identifier: "nerdctl-experimental://registry-namespace.com:443/host/registry-host.com:443/subpath/something",
identifier: version.RootName + "-experimental://registry-namespace.com:443/host/registry-host.com:443/subpath/something",
allIDs: []string{
"nerdctl-experimental://registry-namespace.com:443/host/registry-host.com:443/subpath/something",
version.RootName + "-experimental://registry-namespace.com:443/host/registry-host.com:443/subpath/something",
},
},
{
Expand Down
5 changes: 3 additions & 2 deletions pkg/infoutil/infoutil_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/containerd/nerdctl/v2/pkg/defaults"
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
"github.com/containerd/nerdctl/v2/pkg/rootlessutil"
"github.com/containerd/nerdctl/v2/pkg/version"
)

const UnameO = "GNU/Linux"
Expand All @@ -39,8 +40,8 @@ func fulfillSecurityOptions(info *dockercompat.Info) {
if rootlessutil.IsRootless() && !apparmor.CanApplySpecificExistingProfile(defaults.AppArmorProfileName) {
info.Warnings = append(info.Warnings, fmt.Sprintf(strings.TrimSpace(`
WARNING: AppArmor profile %q is not loaded.
Use 'sudo nerdctl apparmor load' if you prefer to use AppArmor with rootless mode.
This warning is negligible if you do not intend to use AppArmor.`), defaults.AppArmorProfileName))
Use 'sudo %s apparmor load' if you prefer to use AppArmor with rootless mode.
This warning is negligible if you do not intend to use AppArmor.`), defaults.AppArmorProfileName, version.RootName))
}
}
info.SecurityOptions = append(info.SecurityOptions, "name=seccomp,profile="+defaults.SeccompProfileName)
Expand Down
4 changes: 2 additions & 2 deletions pkg/inspecttypes/dockercompat/dockercompat.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,9 @@ func NetworkFromNative(n *native.Network) (*Network, error) {
return &res, nil
}

func parseMounts(containersMounts string) ([]MountPoint, error) {
func parseMounts(mountList string) ([]MountPoint, error) {
var mounts []MountPoint
err := json.Unmarshal([]byte(containersMounts), &mounts)
err := json.Unmarshal([]byte(mountList), &mounts)
if err != nil {
return nil, err
}
Expand Down
12 changes: 7 additions & 5 deletions pkg/inspecttypes/dockercompat/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ type Info struct {
// Nfd is omitted because it does not make sense for us
OomKillDisable bool
// NGoroutines is omitted because it does not make sense for us
SystemTime string
LoggingDriver string
CgroupDriver cgroups.Manager
CgroupVersion string `json:",omitempty"`
// NEventsListener is omitted because it does not make sense for us
BridgeNfIptables bool
BridgeNfIP6tables bool `json:"BridgeNfIp6tables"`
SystemTime string
LoggingDriver string
CgroupDriver cgroups.Manager
CgroupVersion string `json:",omitempty"`
// NEventsListener is omitted because it does not make sense here
KernelVersion string
OperatingSystem string
OSType string
Expand Down
2 changes: 1 addition & 1 deletion pkg/testutil/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,8 @@ func (c *Cmd) OutLines() []string {
type Target = string

const (
Nerdctl = Target("nerdctl")
Docker = Target("docker")
Nerdctl = Target("nerdctl")
)

var (
Expand Down