From 552f67c44b5590291c3be9369ce18760b6a7ad60 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Sun, 11 Apr 2021 10:50:55 -0700 Subject: [PATCH] Updates to build on windows --- Makefile | 12 +- client.go => client_linux.go | 0 client_windows.go | 70 +++++++++++ exec.go | 14 +-- exec_linux.go | 41 +++++++ exec_windows.go | 26 +++++ login.go | 20 +--- login_linux.go | 45 ++++++++ login_windows.go | 29 +++++ main.go | 96 ++------------- main_linux.go | 108 +++++++++++++++++ main_windows.go | 37 ++++++ pkg/containerinspector/containerinspector.go | 53 +-------- .../containerinspector_linux.go | 77 +++++++++++++ .../containerinspector_windows.go | 29 +++++ pkg/defaults/{cgroup.go => cgroup_linux.go} | 8 ++ .../{defaults.go => defaults_linux.go} | 0 pkg/defaults/defaults_windows.go | 57 +++++++++ pkg/infoutil/infoutil.go | 91 +-------------- pkg/infoutil/infoutil_linux.go | 109 ++++++++++++++++++ ...nfoutil_test.go => infoutil_linux_test.go} | 0 pkg/infoutil/infoutil_windows.go | 31 +++++ .../{lockutil.go => lockutil_linux.go} | 0 pkg/lockutil/lockutil_windows.go | 69 +++++++++++ pkg/mountutil/mountutil.go | 35 ------ pkg/mountutil/mountutil_linux.go | 55 +++++++++ pkg/mountutil/mountutil_windows.go | 22 ++++ pkg/netutil/netutil.go | 49 -------- pkg/netutil/netutil_linux.go | 66 +++++++++++ pkg/netutil/netutil_windows.go | 58 ++++++++++ pkg/ocihook/ocihook.go | 7 +- pkg/ocihook/ocihook_linux.go | 32 +++++ pkg/ocihook/ocihook_windows.go | 22 ++++ run.go | 52 +-------- run_cgroup.go => run_cgroup_linux.go | 0 ...cgroup_test.go => run_cgroup_linux_test.go | 0 run_cgroup_windows.go | 26 +++++ run_linux.go | 82 +++++++++++++ run_windows.go | 33 ++++++ 39 files changed, 1156 insertions(+), 405 deletions(-) rename client.go => client_linux.go (100%) create mode 100644 client_windows.go create mode 100644 exec_linux.go create mode 100644 exec_windows.go create mode 100644 login_linux.go create mode 100644 login_windows.go create mode 100644 main_linux.go create mode 100644 main_windows.go create mode 100644 pkg/containerinspector/containerinspector_linux.go create mode 100644 pkg/containerinspector/containerinspector_windows.go rename pkg/defaults/{cgroup.go => cgroup_linux.go} (92%) rename pkg/defaults/{defaults.go => defaults_linux.go} (100%) create mode 100644 pkg/defaults/defaults_windows.go create mode 100644 pkg/infoutil/infoutil_linux.go rename pkg/infoutil/{infoutil_test.go => infoutil_linux_test.go} (100%) create mode 100644 pkg/infoutil/infoutil_windows.go rename pkg/lockutil/{lockutil.go => lockutil_linux.go} (100%) create mode 100644 pkg/lockutil/lockutil_windows.go create mode 100644 pkg/mountutil/mountutil_linux.go create mode 100644 pkg/mountutil/mountutil_windows.go create mode 100644 pkg/netutil/netutil_linux.go create mode 100644 pkg/netutil/netutil_windows.go create mode 100644 pkg/ocihook/ocihook_linux.go create mode 100644 pkg/ocihook/ocihook_windows.go rename run_cgroup.go => run_cgroup_linux.go (100%) rename run_cgroup_test.go => run_cgroup_linux_test.go (100%) create mode 100644 run_cgroup_windows.go create mode 100644 run_linux.go create mode 100644 run_windows.go diff --git a/Makefile b/Makefile index 32ad948dfba..68ce68911b5 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,10 @@ # ----------------------------------------------------------------------------- GO ?= go - +GOOS ?= $(shell go env GOOS) +ifeq ($(GOOS),windows) + BIN_EXT := .exe +endif PACKAGE := github.com/containerd/nerdctl BINDIR ?= /usr/local/bin @@ -28,7 +31,7 @@ VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags) VERSION_TRIMMED := $(VERSION:v%=%) REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi) -export GO_BUILD=GO111MODULE=on CGO_ENABLED=0 $(GO) build -ldflags "-s -w -X $(PACKAGE)/pkg/version.Version=$(VERSION) -X $(PACKAGE)/pkg/version.Revision=$(REVISION)" +export GO_BUILD=GO111MODULE=on CGO_ENABLED=0 GOOS=$(GOOS) $(GO) build -ldflags "-s -w -X $(PACKAGE)/pkg/version.Version=$(VERSION) -X $(PACKAGE)/pkg/version.Revision=$(REVISION)" all: binaries @@ -40,7 +43,7 @@ help: @echo " * 'clean' - Clean artifacts." nerdctl: - $(GO_BUILD) -o $(CURDIR)/_output/nerdctl $(PACKAGE) + $(GO_BUILD) -o $(CURDIR)/_output/nerdctl$(BIN_EXT) $(PACKAGE) clean: find . -name \*~ -delete @@ -72,6 +75,9 @@ artifacts: clean GOOS=linux GOARCH=s390x make -C $(CURDIR) binaries tar $(TAR_FLAGS) -czvf $(CURDIR)/_output/nerdctl-$(VERSION_TRIMMED)-linux-s390x.tar.gz _output/nerdctl extras/rootless/* + GOOS=windows GOARCH=amd64 make -C $(CURDIR) binaries + tar $(TAR_FLAGS) -czvf $(CURDIR)/_output/nerdctl-$(VERSION_TRIMMED)-windows-amd64.tar.gz + rm -f $(CURDIR)/_output/nerdctl DOCKER_BUILDKIT=1 docker build --output type=tar,dest=$(CURDIR)/_output/nerdctl-full-$(VERSION_TRIMMED)-linux-amd64.tar --target out-full $(CURDIR) diff --git a/client.go b/client_linux.go similarity index 100% rename from client.go rename to client_linux.go diff --git a/client_windows.go b/client_windows.go new file mode 100644 index 00000000000..30e1b3a85e8 --- /dev/null +++ b/client_windows.go @@ -0,0 +1,70 @@ +/* + 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 ( + "context" + "os" + "path/filepath" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/namespaces" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli/v2" +) + +func newClient(clicontext *cli.Context) (*containerd.Client, context.Context, context.CancelFunc, error) { + ctx := context.Background() + namespace := clicontext.String("namespace") + ctx = namespaces.WithNamespace(ctx, namespace) + address := clicontext.String("address") + const dockerContainerdaddress = "\\\\.\\pipe\\containerd-containerd" + //TODO fall back? + client, err := containerd.New(address) + if err != nil { + return nil, nil, nil, err + } + var cancel context.CancelFunc + ctx, cancel = context.WithCancel(ctx) + return client, ctx, cancel, nil +} + +// getDataStore returns a string like "/var/lib/nerdctl/1935db59". +// "1935db9" is from `$(echo -n "/run/containerd/containerd.sock" | sha256sum | cut -c1-8)`` +func getDataStore(clicontext *cli.Context) (string, error) { + dataRoot := clicontext.String("data-root") + if err := os.MkdirAll(dataRoot, 0700); err != nil { + return "", err + } + addrHash, err := getAddrHash(clicontext.String("address")) + if err != nil { + return "", err + } + dataStore := filepath.Join(dataRoot, addrHash) + if err := os.MkdirAll(dataStore, 0700); err != nil { + return "", err + } + return dataStore, nil +} + +func getAddrHash(addr string) (string, error) { + const addrHashLen = 8 + + d := digest.SHA256.FromString(addr) + h := d.Encoded()[0:addrHashLen] + return h, nil +} diff --git a/exec.go b/exec.go index 340f65cc4dd..7ed388269d4 100644 --- a/exec.go +++ b/exec.go @@ -26,7 +26,6 @@ import ( "github.com/containerd/containerd/cio" "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/cmd/ctr/commands/tasks" - "github.com/containerd/containerd/pkg/cap" "github.com/containerd/nerdctl/pkg/idgen" "github.com/containerd/nerdctl/pkg/idutil/containerwalker" "github.com/containerd/nerdctl/pkg/strutil" @@ -224,21 +223,10 @@ func generateExecProcessSpec(ctx context.Context, clicontext *cli.Context, conta } if clicontext.Bool("privileged") { - if pspec.Capabilities == nil { - pspec.Capabilities = &specs.LinuxCapabilities{} - } - allCaps, err := cap.Current() + err = setExecCapabilities(pspec) if err != nil { return nil, err } - pspec.Capabilities.Bounding = allCaps - pspec.Capabilities.Permitted = pspec.Capabilities.Bounding - pspec.Capabilities.Inheritable = pspec.Capabilities.Bounding - pspec.Capabilities.Effective = pspec.Capabilities.Bounding - - // https://github.com/moby/moby/pull/36466/files - // > `docker exec --privileged` does not currently disable AppArmor - // > profiles. Privileged configuration of the container is inherited } return pspec, nil diff --git a/exec_linux.go b/exec_linux.go new file mode 100644 index 00000000000..6101a1a75a6 --- /dev/null +++ b/exec_linux.go @@ -0,0 +1,41 @@ +/* + 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 ( + "github.com/containerd/containerd/pkg/cap" + "github.com/opencontainers/runtime-spec/specs-go" +) + +func setExecCapabilities(pspec *specs.Process) error { + if pspec.Capabilities == nil { + pspec.Capabilities = &specs.LinuxCapabilities{} + } + allCaps, err := cap.Current() + if err != nil { + return err + } + pspec.Capabilities.Bounding = allCaps + pspec.Capabilities.Permitted = pspec.Capabilities.Bounding + pspec.Capabilities.Inheritable = pspec.Capabilities.Bounding + pspec.Capabilities.Effective = pspec.Capabilities.Bounding + + // https://github.com/moby/moby/pull/36466/files + // > `docker exec --privileged` does not currently disable AppArmor + // > profiles. Privileged configuration of the container is inherited + return nil +} \ No newline at end of file diff --git a/exec_windows.go b/exec_windows.go new file mode 100644 index 00000000000..88ed1bcc369 --- /dev/null +++ b/exec_windows.go @@ -0,0 +1,26 @@ +/* + 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 ( + "github.com/opencontainers/runtime-spec/specs-go" +) + +func setExecCapabilities(pspec *specs.Process) error { + //no op windows + return nil +} diff --git a/login.go b/login.go index d3b09be463e..5086bf0ea2d 100644 --- a/login.go +++ b/login.go @@ -20,10 +20,8 @@ import ( "context" "fmt" "io/ioutil" - "os" "runtime" "strings" - "syscall" "github.com/containerd/nerdctl/pkg/version" dockercliconfig "github.com/docker/cli/cli/config" @@ -35,7 +33,6 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" - "golang.org/x/term" ) type loginOptions struct { @@ -210,22 +207,11 @@ func ConfigureAuthentification(clicontext *cli.Context, authConfig *types.AuthCo if options.password == "" { fmt.Print("Enter Password: ") - var fd int - if term.IsTerminal(syscall.Stdin) { - fd = syscall.Stdin - } else { - tty, err := os.Open("/dev/tty") - if err != nil { - return errors.Wrap(err, "error allocating terminal") - } - defer tty.Close() - fd = int(tty.Fd()) - } - bytePassword, err := term.ReadPassword(fd) + pwd, err := readPassword() if err != nil { - return errors.Wrap(err, "error reading password") + return err } - options.password = string(bytePassword) + options.password = pwd } if options.password == "" { diff --git a/login_linux.go b/login_linux.go new file mode 100644 index 00000000000..ae689e5e78a --- /dev/null +++ b/login_linux.go @@ -0,0 +1,45 @@ +/* + 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 ( + "os" + "syscall" + + "github.com/pkg/errors" + "golang.org/x/term" +) + +func readPassword() (string, error) { + var fd int + if term.IsTerminal(syscall.Stdin) { + fd = syscall.Stdin + } else { + tty, err := os.Open("/dev/tty") + if err != nil { + return "", errors.Wrap(err, "error allocating terminal") + } + defer tty.Close() + fd = int(tty.Fd()) + } + bytePassword, err := term.ReadPassword(fd) + if err != nil { + return "", errors.Wrap(err, "error reading password") + } + + return string(bytePassword), nil +} diff --git a/login_windows.go b/login_windows.go new file mode 100644 index 00000000000..f272b90af0a --- /dev/null +++ b/login_windows.go @@ -0,0 +1,29 @@ +/* + 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 ( + "bufio" + "os" +) + +func readPassword() (string, error) { + reader := bufio.NewReader(os.Stdin) + pwd, _ := reader.ReadString('\n') + + return pwd, nil +} diff --git a/main.go b/main.go index 27027af3469..0e7b2ad58ca 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "os" "strings" @@ -25,7 +24,6 @@ import ( "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/namespaces" ncdefaults "github.com/containerd/nerdctl/pkg/defaults" - "github.com/containerd/nerdctl/pkg/infoutil" "github.com/containerd/nerdctl/pkg/logging" "github.com/containerd/nerdctl/pkg/rootlessutil" "github.com/containerd/nerdctl/pkg/strutil" @@ -35,6 +33,12 @@ import ( "github.com/urfave/cli/v2" ) +type Category = string + +const ( + CategoryManagement = Category("Management") +) + func main() { if err := xmain(); err != nil { logrus.Fatal(err) @@ -72,7 +76,7 @@ func newApp() *cli.App { Aliases: []string{"a", "host", "H"}, Usage: "containerd address, optionally with \"unix://\" prefix", EnvVars: []string{"CONTAINERD_ADDRESS"}, - Value: "unix://" + defaults.DefaultAddress, // same for rootless as well (mount-namespaced) + Value: defaults.DefaultAddress, // same for rootless as well (mount-namespaced) }, &cli.StringFlag{ Name: "namespace", @@ -191,92 +195,6 @@ func newApp() *cli.App { return app } -func appNeedsRootlessParentMain(clicontext *cli.Context) bool { - if !rootlessutil.IsRootlessParent() { - return false - } - // TODO: allow `nerdctl --help` without nsentering into RootlessKit - switch clicontext.Args().First() { - case "", "completion", "login", "logout": - return false - } - return true -} - -type Category = string - -const ( - CategoryManagement = Category("Management") -) - -func appBashComplete(clicontext *cli.Context) { - w := clicontext.App.Writer - coco := parseCompletionContext(clicontext) - switch coco.flagName { - case "n", "namespace": - bashCompleteNamespaceNames(clicontext) - return - case "snapshotter", "storage-driver": - bashCompleteSnapshotterNames(clicontext) - return - case "cgroup-manager": - fmt.Fprintln(w, "cgroupfs") - if ncdefaults.IsSystemdAvailable() { - fmt.Fprintln(w, "systemd") - } - if rootlessutil.IsRootless() { - fmt.Fprintln(w, "none") - } - return - } - cli.DefaultAppComplete(clicontext) - for _, subcomm := range clicontext.App.Commands { - fmt.Fprintln(clicontext.App.Writer, subcomm.Name) - } -} - -func bashCompleteNamespaceNames(clicontext *cli.Context) { - if rootlessutil.IsRootlessParent() { - _ = rootlessutil.ParentMain() - return - } - - client, ctx, cancel, err := newClient(clicontext) - if err != nil { - return - } - defer cancel() - nsService := client.NamespaceService() - nsList, err := nsService.List(ctx) - if err != nil { - logrus.Warn(err) - return - } - for _, ns := range nsList { - fmt.Fprintln(clicontext.App.Writer, ns) - } -} - -func bashCompleteSnapshotterNames(clicontext *cli.Context) { - if rootlessutil.IsRootlessParent() { - _ = rootlessutil.ParentMain() - return - } - - client, ctx, cancel, err := newClient(clicontext) - if err != nil { - return - } - defer cancel() - snapshotterPlugins, err := infoutil.GetSnapshotterNames(ctx, client.IntrospectionService()) - if err != nil { - return - } - for _, name := range snapshotterPlugins { - fmt.Fprintln(clicontext.App.Writer, name) - } -} - func globalFlags(clicontext *cli.Context) (string, []string) { args0, err := os.Executable() if err != nil { diff --git a/main_linux.go b/main_linux.go new file mode 100644 index 00000000000..baae0f67b26 --- /dev/null +++ b/main_linux.go @@ -0,0 +1,108 @@ +/* + 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 ( + "fmt" + + ncdefaults "github.com/containerd/nerdctl/pkg/defaults" + "github.com/containerd/nerdctl/pkg/infoutil" + + "github.com/containerd/nerdctl/pkg/rootlessutil" + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" +) + +func appNeedsRootlessParentMain(clicontext *cli.Context) bool { + if !rootlessutil.IsRootlessParent() { + return false + } + // TODO: allow `nerdctl --help` without nsentering into RootlessKit + switch clicontext.Args().First() { + case "", "completion", "login", "logout": + return false + } + return true +} + +func appBashComplete(clicontext *cli.Context) { + w := clicontext.App.Writer + coco := parseCompletionContext(clicontext) + switch coco.flagName { + case "n", "namespace": + bashCompleteNamespaceNames(clicontext) + return + case "snapshotter", "storage-driver": + bashCompleteSnapshotterNames(clicontext) + return + case "cgroup-manager": + fmt.Fprintln(w, "cgroupfs") + if ncdefaults.IsSystemdAvailable() { + fmt.Fprintln(w, "systemd") + } + if rootlessutil.IsRootless() { + fmt.Fprintln(w, "none") + } + return + } + cli.DefaultAppComplete(clicontext) + for _, subcomm := range clicontext.App.Commands { + fmt.Fprintln(clicontext.App.Writer, subcomm.Name) + } +} + +func bashCompleteNamespaceNames(clicontext *cli.Context) { + if rootlessutil.IsRootlessParent() { + _ = rootlessutil.ParentMain() + return + } + + client, ctx, cancel, err := newClient(clicontext) + if err != nil { + return + } + defer cancel() + nsService := client.NamespaceService() + nsList, err := nsService.List(ctx) + if err != nil { + logrus.Warn(err) + return + } + for _, ns := range nsList { + fmt.Fprintln(clicontext.App.Writer, ns) + } +} + +func bashCompleteSnapshotterNames(clicontext *cli.Context) { + if rootlessutil.IsRootlessParent() { + _ = rootlessutil.ParentMain() + return + } + + client, ctx, cancel, err := newClient(clicontext) + if err != nil { + return + } + defer cancel() + snapshotterPlugins, err := infoutil.GetSnapshotterNames(ctx, client.IntrospectionService()) + if err != nil { + return + } + for _, name := range snapshotterPlugins { + fmt.Fprintln(clicontext.App.Writer, name) + } +} diff --git a/main_windows.go b/main_windows.go new file mode 100644 index 00000000000..e53d1796150 --- /dev/null +++ b/main_windows.go @@ -0,0 +1,37 @@ +/* + 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 ( + "github.com/urfave/cli/v2" +) + +func appNeedsRootlessParentMain(clicontext *cli.Context) bool { + return false +} + +func appBashComplete(clicontext *cli.Context) { + return +} + +func bashCompleteNamespaceNames(clicontext *cli.Context) { + return +} + +func bashCompleteSnapshotterNames(clicontext *cli.Context) { + return +} diff --git a/pkg/containerinspector/containerinspector.go b/pkg/containerinspector/containerinspector.go index 2bbac5fbaa5..6abc55d7150 100644 --- a/pkg/containerinspector/containerinspector.go +++ b/pkg/containerinspector/containerinspector.go @@ -18,14 +18,10 @@ package containerinspector import ( "context" - "fmt" - "net" - "strings" "github.com/containerd/containerd" "github.com/containerd/nerdctl/pkg/inspecttypes/native" "github.com/containerd/typeurl" - "github.com/containernetworking/plugins/pkg/ns" "github.com/sirupsen/logrus" ) @@ -58,8 +54,7 @@ func Inspect(ctx context.Context, container containerd.Container) (*native.Conta return n, nil } n.Process.Status = st - netNSPath := fmt.Sprintf("/proc/%d/ns/net", n.Process.Pid) - netNS, err := inspectNetNS(ctx, netNSPath) + netNS, err := inspectNetNS(ctx, n.Process.Pid) if err != nil { logrus.WithError(err).WithField("id", id).Warnf("failed to inspect NetNS") return n, nil @@ -67,49 +62,3 @@ func Inspect(ctx context.Context, container containerd.Container) (*native.Conta n.Process.NetNS = netNS return n, nil } - -func inspectNetNS(ctx context.Context, nsPath string) (*native.NetNS, error) { - res := &native.NetNS{} - fn := func(_ ns.NetNS) error { - intf, err := net.Interfaces() - if err != nil { - return err - } - res.Interfaces = make([]native.NetInterface, len(intf)) - for i, f := range intf { - x := native.NetInterface{ - Interface: f, - } - if f.HardwareAddr != nil { - x.HardwareAddr = f.HardwareAddr.String() - } - if x.Interface.Flags.String() != "0" { - x.Flags = strings.Split(x.Interface.Flags.String(), "|") - } - if addrs, err := x.Interface.Addrs(); err == nil { - x.Addrs = make([]string, len(addrs)) - for j, a := range addrs { - x.Addrs[j] = a.String() - } - } - res.Interfaces[i] = x - } - res.PrimaryInterface = determinePrimaryInterface(res.Interfaces) - return nil - } - if err := ns.WithNetNSPath(nsPath, fn); err != nil { - return nil, err - } - return res, nil -} - -// determinePrimaryInterface returns a net.Interface.Index value, not a slice index. -// Zero means no priary interface was detected. -func determinePrimaryInterface(interfaces []native.NetInterface) int { - for _, f := range interfaces { - if f.Interface.Flags&net.FlagLoopback == 0 && f.Interface.Flags&net.FlagUp != 0 && !strings.HasPrefix(f.Name, "lo") { - return f.Index - } - } - return 0 -} diff --git a/pkg/containerinspector/containerinspector_linux.go b/pkg/containerinspector/containerinspector_linux.go new file mode 100644 index 00000000000..fd4fe13b7da --- /dev/null +++ b/pkg/containerinspector/containerinspector_linux.go @@ -0,0 +1,77 @@ +/* + 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 containerinspector + +import ( + "context" + "fmt" + "net" + "strings" + + + "github.com/containerd/nerdctl/pkg/inspecttypes/native" + + "github.com/containernetworking/plugins/pkg/ns" + +) + +func inspectNetNS(ctx context.Context, pid int) (*native.NetNS, error) { + nsPath := fmt.Sprintf("/proc/%d/ns/net", pid) + res := &native.NetNS{} + fn := func(_ ns.NetNS) error { + intf, err := net.Interfaces() + if err != nil { + return err + } + res.Interfaces = make([]native.NetInterface, len(intf)) + for i, f := range intf { + x := native.NetInterface{ + Interface: f, + } + if f.HardwareAddr != nil { + x.HardwareAddr = f.HardwareAddr.String() + } + if x.Interface.Flags.String() != "0" { + x.Flags = strings.Split(x.Interface.Flags.String(), "|") + } + if addrs, err := x.Interface.Addrs(); err == nil { + x.Addrs = make([]string, len(addrs)) + for j, a := range addrs { + x.Addrs[j] = a.String() + } + } + res.Interfaces[i] = x + } + res.PrimaryInterface = determinePrimaryInterface(res.Interfaces) + return nil + } + if err := ns.WithNetNSPath(nsPath, fn); err != nil { + return nil, err + } + return res, nil +} + +// determinePrimaryInterface returns a net.Interface.Index value, not a slice index. +// Zero means no priary interface was detected. +func determinePrimaryInterface(interfaces []native.NetInterface) int { + for _, f := range interfaces { + if f.Interface.Flags&net.FlagLoopback == 0 && f.Interface.Flags&net.FlagUp != 0 && !strings.HasPrefix(f.Name, "lo") { + return f.Index + } + } + return 0 +} diff --git a/pkg/containerinspector/containerinspector_windows.go b/pkg/containerinspector/containerinspector_windows.go new file mode 100644 index 00000000000..752b807dc5b --- /dev/null +++ b/pkg/containerinspector/containerinspector_windows.go @@ -0,0 +1,29 @@ +/* + 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 containerinspector + +import ( + "context" + + "github.com/containerd/nerdctl/pkg/inspecttypes/native" +) + +func inspectNetNS(ctx context.Context, pid int) (*native.NetNS, error) { + r := &native.NetNS{} + + return r, nil +} diff --git a/pkg/defaults/cgroup.go b/pkg/defaults/cgroup_linux.go similarity index 92% rename from pkg/defaults/cgroup.go rename to pkg/defaults/cgroup_linux.go index 81e0eb4e07f..03479e45d6c 100644 --- a/pkg/defaults/cgroup.go +++ b/pkg/defaults/cgroup_linux.go @@ -51,3 +51,11 @@ func CgroupnsMode() string { } return "host" } + +func CgroupsVersion() string { + if cgroups.Mode() == cgroups.Unified { + return "2" + } + + return "1" +} diff --git a/pkg/defaults/defaults.go b/pkg/defaults/defaults_linux.go similarity index 100% rename from pkg/defaults/defaults.go rename to pkg/defaults/defaults_linux.go diff --git a/pkg/defaults/defaults_windows.go b/pkg/defaults/defaults_windows.go new file mode 100644 index 00000000000..88db067c61f --- /dev/null +++ b/pkg/defaults/defaults_windows.go @@ -0,0 +1,57 @@ +/* + 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 defaults + +import ( + "fmt" + "os" + "path/filepath" +) + +const AppArmorProfileName = "" + +func DataRoot() string { + return filepath.Join(os.Getenv("ProgramData"), "nerdctl") +} + +func CNIPath() string { + return filepath.Join(os.Getenv("ProgramFiles"), "containerd", "cni", "bin") +} + +func CNINetConfPath() string { + return filepath.Join(os.Getenv("ProgramFiles"), "containerd", "cni", "conf") +} + +func BuildKitHost() string { + return fmt.Sprint("\\\\.\\pipe\\buildkit") +} + +func IsSystemdAvailable() bool { + return false +} + +func CgroupManager() string { + return "" +} + +func CgroupsVersion() string { + return "" +} + +func CgroupnsMode() string { + return "" +} diff --git a/pkg/infoutil/infoutil.go b/pkg/infoutil/infoutil.go index b03d1578c49..488dc98e95f 100644 --- a/pkg/infoutil/infoutil.go +++ b/pkg/infoutil/infoutil.go @@ -17,15 +17,11 @@ package infoutil import ( - "bufio" "context" - "io" "os" - "regexp" "runtime" "strings" - "github.com/containerd/cgroups" "github.com/containerd/containerd" "github.com/containerd/containerd/pkg/apparmor" "github.com/containerd/containerd/services/introspection" @@ -33,90 +29,8 @@ import ( "github.com/containerd/nerdctl/pkg/inspecttypes/dockercompat" "github.com/containerd/nerdctl/pkg/rootlessutil" ptypes "github.com/gogo/protobuf/types" - "golang.org/x/sys/unix" ) -// UnameR returns `uname -r` -func UnameR() string { - var utsname unix.Utsname - if err := unix.Uname(&utsname); err != nil { - // error is unlikely to happen - return "" - } - var s string - for _, f := range utsname.Release { - if f == 0 { - break - } - s += string(f) - } - return s -} - -// UnameM returns `uname -m` -func UnameM() string { - var utsname unix.Utsname - if err := unix.Uname(&utsname); err != nil { - // error is unlikely to happen - return "" - } - var s string - for _, f := range utsname.Machine { - if f == 0 { - break - } - s += string(f) - } - return s -} - -const UnameO = "GNU/Linux" - -func DistroName() string { - f, err := os.Open("/etc/os-release") - if err != nil { - return UnameO - } - defer f.Close() - return distroName(f) -} - -func distroName(r io.Reader) string { - scanner := bufio.NewScanner(r) - var name, version string - for scanner.Scan() { - line := scanner.Text() - k, v := getOSReleaseAttrib(line) - switch k { - case "PRETTY_NAME": - return v - case "NAME": - name = v - case "VERSION": - version = v - } - } - if name != "" { - if version != "" { - return name + " " + version - } - return name - } - return UnameO -} - -var osReleaseAttribRegex = regexp.MustCompile(`([^\s=]+)\s*=\s*("{0,1})([^"]*)("{0,1})`) - -func getOSReleaseAttrib(line string) (string, string) { - splitBySlash := strings.SplitN(line, "#", 2) - l := strings.TrimSpace(splitBySlash[0]) - x := osReleaseAttribRegex.FindAllStringSubmatch(l, -1) - if len(x) >= 1 && len(x[0]) > 3 { - return x[0][1], x[0][3] - } - return "", "" -} - func Info(ctx context.Context, client *containerd.Client, defaultSnapshotter string) (*dockercompat.Info, error) { daemonVersion, err := client.Version(ctx) if err != nil { @@ -140,10 +54,7 @@ func Info(ctx context.Context, client *containerd.Client, defaultSnapshotter str info.Plugins.Storage = snapshotterPlugins info.LoggingDriver = "json-file" // hard-coded info.CgroupDriver = defaults.CgroupManager() - info.CgroupVersion = "1" - if cgroups.Mode() == cgroups.Unified { - info.CgroupVersion = "2" - } + info.CgroupVersion = defaults.CgroupsVersion() info.KernelVersion = UnameR() info.OperatingSystem = DistroName() info.OSType = runtime.GOOS diff --git a/pkg/infoutil/infoutil_linux.go b/pkg/infoutil/infoutil_linux.go new file mode 100644 index 00000000000..584910a74e3 --- /dev/null +++ b/pkg/infoutil/infoutil_linux.go @@ -0,0 +1,109 @@ +/* + 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 infoutil + +import ( + "bufio" + "io" + "os" + "regexp" + + "strings" + + "golang.org/x/sys/unix" +) + +// UnameR returns `uname -r` +func UnameR() string { + var utsname unix.Utsname + if err := unix.Uname(&utsname); err != nil { + // error is unlikely to happen + return "" + } + var s string + for _, f := range utsname.Release { + if f == 0 { + break + } + s += string(f) + } + return s +} + +// UnameM returns `uname -m` +func UnameM() string { + var utsname unix.Utsname + if err := unix.Uname(&utsname); err != nil { + // error is unlikely to happen + return "" + } + var s string + for _, f := range utsname.Machine { + if f == 0 { + break + } + s += string(f) + } + return s +} + +const UnameO = "GNU/Linux" + +func DistroName() string { + f, err := os.Open("/etc/os-release") + if err != nil { + return UnameO + } + defer f.Close() + return distroName(f) +} + +func distroName(r io.Reader) string { + scanner := bufio.NewScanner(r) + var name, version string + for scanner.Scan() { + line := scanner.Text() + k, v := getOSReleaseAttrib(line) + switch k { + case "PRETTY_NAME": + return v + case "NAME": + name = v + case "VERSION": + version = v + } + } + if name != "" { + if version != "" { + return name + " " + version + } + return name + } + return UnameO +} + +var osReleaseAttribRegex = regexp.MustCompile(`([^\s=]+)\s*=\s*("{0,1})([^"]*)("{0,1})`) + +func getOSReleaseAttrib(line string) (string, string) { + splitBySlash := strings.SplitN(line, "#", 2) + l := strings.TrimSpace(splitBySlash[0]) + x := osReleaseAttribRegex.FindAllStringSubmatch(l, -1) + if len(x) >= 1 && len(x[0]) > 3 { + return x[0][1], x[0][3] + } + return "", "" +} diff --git a/pkg/infoutil/infoutil_test.go b/pkg/infoutil/infoutil_linux_test.go similarity index 100% rename from pkg/infoutil/infoutil_test.go rename to pkg/infoutil/infoutil_linux_test.go diff --git a/pkg/infoutil/infoutil_windows.go b/pkg/infoutil/infoutil_windows.go new file mode 100644 index 00000000000..89d25474efe --- /dev/null +++ b/pkg/infoutil/infoutil_windows.go @@ -0,0 +1,31 @@ +/* + 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 infoutil + +// UnameR returns `uname -r` +func UnameR() string { + return "" +} + +// UnameM returns `uname -m` +func UnameM() string { + return "" +} + +func DistroName() string { + return "" +} diff --git a/pkg/lockutil/lockutil.go b/pkg/lockutil/lockutil_linux.go similarity index 100% rename from pkg/lockutil/lockutil.go rename to pkg/lockutil/lockutil_linux.go diff --git a/pkg/lockutil/lockutil_windows.go b/pkg/lockutil/lockutil_windows.go new file mode 100644 index 00000000000..ad0ae4141dc --- /dev/null +++ b/pkg/lockutil/lockutil_windows.go @@ -0,0 +1,69 @@ +/* + 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 lockutil + +import ( + "os" + "syscall" + "unsafe" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// LockFile modified from https://github.com/boltdb/bolt/blob/v1.3.1/bolt_windows.go using MIT +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + procLockFileEx = modkernel32.NewProc("LockFileEx") + procUnlockFileEx = modkernel32.NewProc("UnlockFileEx") +) + +func WithDirLock(dir string, fn func() error) error { + dirFile, err := os.OpenFile(dir+".lock", os.O_CREATE, 0644) + if err != nil { + return err + } + defer dirFile.Close() + // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx + // 1 lock immediately + if err := lockFileEx(syscall.Handle(dirFile.Fd()), 1, 0, 1, 0, &syscall.Overlapped{}); err != nil { + return errors.Wrapf(err, "failed to lock %q", dir) + } + + defer func() { + if err := unlockFileEx(syscall.Handle(dirFile.Fd()), 0, 1, 0, &syscall.Overlapped{}); err != nil { + logrus.WithError(err).Errorf("failed to unlock %q", dir) + } + }() + return fn() +} + +func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { + r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol))) + if r == 0 { + return err + } + return nil +} + +func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { + r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0) + if r == 0 { + return err + } + return nil +} diff --git a/pkg/mountutil/mountutil.go b/pkg/mountutil/mountutil.go index 2bf93a3de39..6b443979076 100644 --- a/pkg/mountutil/mountutil.go +++ b/pkg/mountutil/mountutil.go @@ -27,7 +27,6 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) type Processed struct { @@ -108,37 +107,3 @@ func ProcessFlagV(s string, volStore volumestore.VolumeStore) (*Processed, error } return &res, nil } - -// getUnprivilegedMountFlags is from https://github.com/moby/moby/blob/v20.10.5/daemon/oci_linux.go#L420-L450 -// -// Get the set of mount flags that are set on the mount that contains the given -// path and are locked by CL_UNPRIVILEGED. This is necessary to ensure that -// bind-mounting "with options" will not fail with user namespaces, due to -// kernel restrictions that require user namespace mounts to preserve -// CL_UNPRIVILEGED locked flags. -func getUnprivilegedMountFlags(path string) ([]string, error) { - var statfs unix.Statfs_t - if err := unix.Statfs(path, &statfs); err != nil { - return nil, err - } - - // The set of keys come from https://github.com/torvalds/linux/blob/v4.13/fs/namespace.c#L1034-L1048. - unprivilegedFlags := map[uint64]string{ - unix.MS_RDONLY: "ro", - unix.MS_NODEV: "nodev", - unix.MS_NOEXEC: "noexec", - unix.MS_NOSUID: "nosuid", - unix.MS_NOATIME: "noatime", - unix.MS_RELATIME: "relatime", - unix.MS_NODIRATIME: "nodiratime", - } - - var flags []string - for mask, flag := range unprivilegedFlags { - if uint64(statfs.Flags)&mask == mask { - flags = append(flags, flag) - } - } - - return flags, nil -} diff --git a/pkg/mountutil/mountutil_linux.go b/pkg/mountutil/mountutil_linux.go new file mode 100644 index 00000000000..4f88644ae6c --- /dev/null +++ b/pkg/mountutil/mountutil_linux.go @@ -0,0 +1,55 @@ +/* + 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 mountutil + +import ( + "golang.org/x/sys/unix" +) + +// getUnprivilegedMountFlags is from https://github.com/moby/moby/blob/v20.10.5/daemon/oci_linux.go#L420-L450 +// +// Get the set of mount flags that are set on the mount that contains the given +// path and are locked by CL_UNPRIVILEGED. This is necessary to ensure that +// bind-mounting "with options" will not fail with user namespaces, due to +// kernel restrictions that require user namespace mounts to preserve +// CL_UNPRIVILEGED locked flags. +func getUnprivilegedMountFlags(path string) ([]string, error) { + var statfs unix.Statfs_t + if err := unix.Statfs(path, &statfs); err != nil { + return nil, err + } + + // The set of keys come from https://github.com/torvalds/linux/blob/v4.13/fs/namespace.c#L1034-L1048. + unprivilegedFlags := map[uint64]string{ + unix.MS_RDONLY: "ro", + unix.MS_NODEV: "nodev", + unix.MS_NOEXEC: "noexec", + unix.MS_NOSUID: "nosuid", + unix.MS_NOATIME: "noatime", + unix.MS_RELATIME: "relatime", + unix.MS_NODIRATIME: "nodiratime", + } + + var flags []string + for mask, flag := range unprivilegedFlags { + if uint64(statfs.Flags)&mask == mask { + flags = append(flags, flag) + } + } + + return flags, nil +} diff --git a/pkg/mountutil/mountutil_windows.go b/pkg/mountutil/mountutil_windows.go new file mode 100644 index 00000000000..77d1fe7df09 --- /dev/null +++ b/pkg/mountutil/mountutil_windows.go @@ -0,0 +1,22 @@ +/* + 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 mountutil + +func getUnprivilegedMountFlags(path string) ([]string, error) { + m := []string{} + return m, nil +} diff --git a/pkg/netutil/netutil.go b/pkg/netutil/netutil.go index c092b955801..15b4e034a6c 100644 --- a/pkg/netutil/netutil.go +++ b/pkg/netutil/netutil.go @@ -39,12 +39,6 @@ type NetworkConfigList struct { File string } -const ( - DefaultNetworkName = "bridge" - DefaultID = 0 - DefaultCIDR = "10.4.0.0/24" -) - type CNIEnv struct { Path string NetconfPath string @@ -62,49 +56,6 @@ type ConfigListTemplateOpts struct { ExtraPlugins string // e.g. `,{"type":"isolation"}` } -// basicPlugins is used by ConfigListTemplate -var basicPlugins = []string{"bridge", "portmap", "firewall", "tuning"} - -// ConfigListTemplate was copied from https://github.com/containers/podman/blob/v2.2.0/cni/87-podman-bridge.conflist -const ConfigListTemplate = `{ - "cniVersion": "0.4.0", - "name": "{{.Name}}", - "nerdctlID": {{.ID}}, - "plugins": [ - { - "type": "bridge", - "bridge": "nerdctl{{.ID}}", - "isGateway": true, - "ipMasq": true, - "hairpinMode": true, - "ipam": { - "type": "host-local", - "routes": [{ "dst": "0.0.0.0/0" }], - "ranges": [ - [ - { - "subnet": "{{.Subnet}}", - "gateway": "{{.Gateway}}" - } - ] - ] - } - }, - { - "type": "portmap", - "capabilities": { - "portMappings": true - } - }, - { - "type": "firewall" - }, - { - "type": "tuning" - }{{.ExtraPlugins}} - ] -}` - // GenerateConfigList creates NetworkConfigList. // GenerateConfigList does not fill "File" field. // diff --git a/pkg/netutil/netutil_linux.go b/pkg/netutil/netutil_linux.go new file mode 100644 index 00000000000..220ea3171c1 --- /dev/null +++ b/pkg/netutil/netutil_linux.go @@ -0,0 +1,66 @@ +/* + 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 netutil + +const ( + DefaultNetworkName = "bridge" + DefaultID = 0 + DefaultCIDR = "10.4.0.0/24" +) + +// basicPlugins is used by ConfigListTemplate +var basicPlugins = []string{"bridge", "portmap", "firewall", "tuning"} + +// ConfigListTemplate was copied from https://github.com/containers/podman/blob/v2.2.0/cni/87-podman-bridge.conflist +const ConfigListTemplate = `{ + "cniVersion": "0.4.0", + "name": "{{.Name}}", + "nerdctlID": {{.ID}}, + "plugins": [ + { + "type": "bridge", + "bridge": "nerdctl{{.ID}}", + "isGateway": true, + "ipMasq": true, + "hairpinMode": true, + "ipam": { + "type": "host-local", + "routes": [{ "dst": "0.0.0.0/0" }], + "ranges": [ + [ + { + "subnet": "{{.Subnet}}", + "gateway": "{{.Gateway}}" + } + ] + ] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + }, + { + "type": "firewall" + }, + { + "type": "tuning" + }{{.ExtraPlugins}} + ] +}` diff --git a/pkg/netutil/netutil_windows.go b/pkg/netutil/netutil_windows.go new file mode 100644 index 00000000000..1827d00f959 --- /dev/null +++ b/pkg/netutil/netutil_windows.go @@ -0,0 +1,58 @@ +/* + 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 netutil + +const ( + DefaultNetworkName = "nat" + DefaultID = 0 + DefaultCIDR = "10.4.0.0/24" +) + +// basicPlugins is used by ConfigListTemplate +var basicPlugins = []string{"nat"} + +// ConfigListTemplate was copied from https://github.com/containers/podman/blob/v2.2.0/cni/87-podman-bridge.conflist + +const ConfigListTemplate = `{ + "cniVersion": "0.4.0", + "name": "{{.Name}}", + "nerdctlID": {{.ID}}, + "plugins": [ + { + "type": "nat", + "master": "Ethernet", + "ipam": { + "subnet": "{{.Subnet}}", + "routes": [ + { + "gateway": "{{.Gateway}}" + } + ] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + }, + { + "type": "tuning" + }{{.ExtraPlugins}} + ] +}` + diff --git a/pkg/ocihook/ocihook.go b/pkg/ocihook/ocihook.go index 05e09870eba..73104a9e9e8 100644 --- a/pkg/ocihook/ocihook.go +++ b/pkg/ocihook/ocihook.go @@ -25,11 +25,9 @@ import ( "os" "path/filepath" - "github.com/containerd/containerd/contrib/apparmor" pkgapparmor "github.com/containerd/containerd/pkg/apparmor" "github.com/containerd/go-cni" gocni "github.com/containerd/go-cni" - "github.com/containerd/nerdctl/pkg/defaults" "github.com/containerd/nerdctl/pkg/dnsutil/hostsstore" "github.com/containerd/nerdctl/pkg/labels" "github.com/containerd/nerdctl/pkg/netutil" @@ -245,10 +243,7 @@ func getCNINamespaceOpts(opts *handlerOpts) ([]cni.NamespaceOpts, error) { func onCreateRuntime(opts *handlerOpts) error { if pkgapparmor.HostSupports() { - // ensure that the default profile is loaded to the host - if err := apparmor.LoadDefaultProfile(defaults.AppArmorProfileName); err != nil { - logrus.WithError(err).Errorf("failed to load AppArmor profile %q", defaults.AppArmorProfileName) - } + loadAppArmor() } if opts.cni != nil { cniNSOpts, err := getCNINamespaceOpts(opts) diff --git a/pkg/ocihook/ocihook_linux.go b/pkg/ocihook/ocihook_linux.go new file mode 100644 index 00000000000..2c6b71ee9b5 --- /dev/null +++ b/pkg/ocihook/ocihook_linux.go @@ -0,0 +1,32 @@ +/* + 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 ocihook + +import ( + "github.com/containerd/containerd/contrib/apparmor" + + "github.com/containerd/nerdctl/pkg/defaults" + + "github.com/sirupsen/logrus" +) + +func loadAppArmor() { + // ensure that the default profile is loaded to the host + if err := apparmor.LoadDefaultProfile(defaults.AppArmorProfileName); err != nil { + logrus.WithError(err).Errorf("failed to load AppArmor profile %q", defaults.AppArmorProfileName) + } +} diff --git a/pkg/ocihook/ocihook_windows.go b/pkg/ocihook/ocihook_windows.go new file mode 100644 index 00000000000..ef9df017c98 --- /dev/null +++ b/pkg/ocihook/ocihook_windows.go @@ -0,0 +1,22 @@ +/* + 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 ocihook + +func loadAppArmor() { + //noop + return +} diff --git a/run.go b/run.go index 84de32eac2d..8092892edda 100644 --- a/run.go +++ b/run.go @@ -32,7 +32,6 @@ import ( "github.com/containerd/containerd/cmd/ctr/commands/tasks" "github.com/containerd/containerd/containers" "github.com/containerd/containerd/oci" - "github.com/containerd/containerd/pkg/cap" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/runtime/restart" gocni "github.com/containerd/go-cni" @@ -273,7 +272,7 @@ func runAction(clicontext *cli.Context) error { oci.WithMounts([]specs.Mount{ {Type: "cgroup", Source: "cgroup", Destination: "/sys/fs/cgroup", Options: []string{"ro", "nosuid", "noexec", "nodev"}}, }), - oci.WithoutRunMount, // unmount default tmpfs on "/run": https://github.com/containerd/nerdctl/issues/157 + WithoutRunMount(), // unmount default tmpfs on "/run": https://github.com/containerd/nerdctl/issues/157 ) rootfsOpts, rootfsCOpts, ensuredImage, err := generateRootfsOpts(ctx, client, clicontext, id) @@ -735,52 +734,3 @@ func propagateContainerdLabelsToOCIAnnotations() oci.SpecOpts { return oci.WithAnnotations(c.Labels)(ctx, oc, c, s) } } - -func runBashComplete(clicontext *cli.Context) { - coco := parseCompletionContext(clicontext) - if coco.boring { - defaultBashComplete(clicontext) - return - } - if coco.flagTakesValue { - w := clicontext.App.Writer - switch coco.flagName { - case "restart": - fmt.Fprintln(w, "always") - fmt.Fprintln(w, "no") - return - case "pull": - fmt.Fprintln(w, "always") - fmt.Fprintln(w, "missing") - fmt.Fprintln(w, "never") - return - case "cgroupns": - fmt.Fprintln(w, "host") - fmt.Fprintln(w, "private") - return - case "security-opt": - fmt.Fprintln(w, "seccomp=") - fmt.Fprintln(w, "apparmor="+defaults.AppArmorProfileName) - fmt.Fprintln(w, "no-new-privileges") - return - case "cap-add", "cap-drop": - for _, c := range cap.Known() { - // "CAP_SYS_ADMIN" -> "sys_admin" - s := strings.ToLower(strings.TrimPrefix(c, "CAP_")) - fmt.Fprintln(w, s) - } - return - case "net", "network": - bashCompleteNetworkNames(clicontext, nil) - return - } - defaultBashComplete(clicontext) - return - } - // show image names, unless we have "--rootfs" flag - if clicontext.Bool("rootfs") { - defaultBashComplete(clicontext) - return - } - bashCompleteImageNames(clicontext) -} diff --git a/run_cgroup.go b/run_cgroup_linux.go similarity index 100% rename from run_cgroup.go rename to run_cgroup_linux.go diff --git a/run_cgroup_test.go b/run_cgroup_linux_test.go similarity index 100% rename from run_cgroup_test.go rename to run_cgroup_linux_test.go diff --git a/run_cgroup_windows.go b/run_cgroup_windows.go new file mode 100644 index 00000000000..bf571d6b3d3 --- /dev/null +++ b/run_cgroup_windows.go @@ -0,0 +1,26 @@ +/* + 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 ( + "github.com/containerd/containerd/oci" + "github.com/urfave/cli/v2" +) + +func generateCgroupOpts(clicontext *cli.Context, id string) ([]oci.SpecOpts, error) { + return []oci.SpecOpts{}, nil +} diff --git a/run_linux.go b/run_linux.go new file mode 100644 index 00000000000..abdc4f69f07 --- /dev/null +++ b/run_linux.go @@ -0,0 +1,82 @@ +/* + 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 ( + "context" + "fmt" + "strings" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/pkg/cap" + "github.com/containerd/nerdctl/pkg/defaults" + "github.com/urfave/cli/v2" +) + +func WithoutRunMount() func(ctx context.Context, client oci.Client, c *containers.Container, s *oci.Spec) error { + return oci.WithoutRunMount +} + +func runBashComplete(clicontext *cli.Context) { + coco := parseCompletionContext(clicontext) + if coco.boring { + defaultBashComplete(clicontext) + return + } + if coco.flagTakesValue { + w := clicontext.App.Writer + switch coco.flagName { + case "restart": + fmt.Fprintln(w, "always") + fmt.Fprintln(w, "no") + return + case "pull": + fmt.Fprintln(w, "always") + fmt.Fprintln(w, "missing") + fmt.Fprintln(w, "never") + return + case "cgroupns": + fmt.Fprintln(w, "host") + fmt.Fprintln(w, "private") + return + case "security-opt": + fmt.Fprintln(w, "seccomp=") + fmt.Fprintln(w, "apparmor="+defaults.AppArmorProfileName) + fmt.Fprintln(w, "no-new-privileges") + return + case "cap-add", "cap-drop": + for _, c := range cap.Known() { + // "CAP_SYS_ADMIN" -> "sys_admin" + s := strings.ToLower(strings.TrimPrefix(c, "CAP_")) + fmt.Fprintln(w, s) + } + return + case "net", "network": + bashCompleteNetworkNames(clicontext, nil) + return + } + defaultBashComplete(clicontext) + return + } + // show image names, unless we have "--rootfs" flag + if clicontext.Bool("rootfs") { + defaultBashComplete(clicontext) + return + } + bashCompleteImageNames(clicontext) +} diff --git a/run_windows.go b/run_windows.go new file mode 100644 index 00000000000..7ca6310162f --- /dev/null +++ b/run_windows.go @@ -0,0 +1,33 @@ +/* + 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 ( + "context" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" + "github.com/urfave/cli/v2" +) + +func runBashComplete(clicontext *cli.Context) { + // noop +} + +func WithoutRunMount() func(ctx context.Context, client oci.Client, c *containers.Container, s *oci.Spec) error { + // not valid on windows + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error { return nil} +} \ No newline at end of file