From 1ca61e27e4ebfeecaf521826ba56c8a184295376 Mon Sep 17 00:00:00 2001 From: Artem Khramov Date: Wed, 15 Sep 2021 13:08:15 +0300 Subject: [PATCH] [#137] FreeBSD support Now that containerd supports FreeBSD, we can port nerdctl, too! :rocket:. For full-fledged functionality, we will need to port * buildkit. Status: POC is ready, need to upstream fixes to dependencies. * runtime + containerd shim. runj/knast should work just fine. * CNI bridge plugin for networking. This change fixes FreeBSD compilation errors by renaming linux files to unix where necessary, or otherwise introducing FreeBSD versions for the necessary files. Signed-off-by: Artem Khramov --- .../{client_linux.go => client_unix.go} | 3 + cmd/nerdctl/exec_freebsd.go | 29 +++++ cmd/nerdctl/{login_linux.go => login_unix.go} | 3 + cmd/nerdctl/main_freebsd.go | 40 +++++++ cmd/nerdctl/run.go | 11 +- cmd/nerdctl/run_cgroup_freebsd.go | 29 +++++ cmd/nerdctl/run_freebsd.go | 37 ++++++ .../containerinspector_freebsd.go | 32 +++++ pkg/defaults/defaults_freebsd.go | 51 ++++++++ pkg/infoutil/infoutil_freebsd.go | 26 +++++ pkg/infoutil/infoutil_linux.go | 87 -------------- pkg/infoutil/infoutil_unix.go | 110 ++++++++++++++++++ ...il_linux_test.go => infoutil_unix_test.go} | 3 + .../{lockutil_linux.go => lockutil_unix.go} | 4 + pkg/mountutil/mountutil_freebsd.go | 63 ++++++++++ .../{netutil_linux.go => netutil_unix.go} | 3 + pkg/ocihook/ocihook_freebsd.go | 25 ++++ 17 files changed, 466 insertions(+), 90 deletions(-) rename cmd/nerdctl/{client_linux.go => client_unix.go} (94%) create mode 100644 cmd/nerdctl/exec_freebsd.go rename cmd/nerdctl/{login_linux.go => login_unix.go} (95%) create mode 100644 cmd/nerdctl/main_freebsd.go create mode 100644 cmd/nerdctl/run_cgroup_freebsd.go create mode 100644 cmd/nerdctl/run_freebsd.go create mode 100644 pkg/containerinspector/containerinspector_freebsd.go create mode 100644 pkg/defaults/defaults_freebsd.go create mode 100644 pkg/infoutil/infoutil_freebsd.go create mode 100644 pkg/infoutil/infoutil_unix.go rename pkg/infoutil/{infoutil_linux_test.go => infoutil_unix_test.go} (98%) rename pkg/lockutil/{lockutil_linux.go => lockutil_unix.go} (95%) create mode 100644 pkg/mountutil/mountutil_freebsd.go rename pkg/netutil/{netutil_linux.go => netutil_unix.go} (96%) create mode 100644 pkg/ocihook/ocihook_freebsd.go diff --git a/cmd/nerdctl/client_linux.go b/cmd/nerdctl/client_unix.go similarity index 94% rename from cmd/nerdctl/client_linux.go rename to cmd/nerdctl/client_unix.go index ed5988f91b8..401a90bc373 100644 --- a/cmd/nerdctl/client_linux.go +++ b/cmd/nerdctl/client_unix.go @@ -1,3 +1,6 @@ +//go:build freebsd || linux +// +build freebsd linux + /* Copyright The containerd Authors. diff --git a/cmd/nerdctl/exec_freebsd.go b/cmd/nerdctl/exec_freebsd.go new file mode 100644 index 00000000000..5bbb2dbdd4d --- /dev/null +++ b/cmd/nerdctl/exec_freebsd.go @@ -0,0 +1,29 @@ +//go:build freebsd +// +build freebsd + +/* + 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 freebsd + return nil +} diff --git a/cmd/nerdctl/login_linux.go b/cmd/nerdctl/login_unix.go similarity index 95% rename from cmd/nerdctl/login_linux.go rename to cmd/nerdctl/login_unix.go index ae689e5e78a..b349d356bea 100644 --- a/cmd/nerdctl/login_linux.go +++ b/cmd/nerdctl/login_unix.go @@ -1,3 +1,6 @@ +//go:build freebsd || linux +// +build freebsd linux + /* Copyright The containerd Authors. diff --git a/cmd/nerdctl/main_freebsd.go b/cmd/nerdctl/main_freebsd.go new file mode 100644 index 00000000000..259454eda5a --- /dev/null +++ b/cmd/nerdctl/main_freebsd.go @@ -0,0 +1,40 @@ +//go:build freebsd +// +build freebsd + +/* + 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/cmd/nerdctl/run.go b/cmd/nerdctl/run.go index 43dde709bcf..2191c8a0538 100644 --- a/cmd/nerdctl/run.go +++ b/cmd/nerdctl/run.go @@ -25,6 +25,7 @@ import ( "os" "path" "path/filepath" + "runtime" "strings" "github.com/containerd/console" @@ -315,12 +316,16 @@ func runAction(clicontext *cli.Context) error { opts = append(opts, oci.WithDefaultSpec(), oci.WithDefaultUnixDevices, - oci.WithMounts([]specs.Mount{ - {Type: "cgroup", Source: "cgroup", Destination: "/sys/fs/cgroup", Options: []string{"ro", "nosuid", "noexec", "nodev"}}, - }), WithoutRunMount(), // unmount default tmpfs on "/run": https://github.com/containerd/nerdctl/issues/157 ) + if runtime.GOOS != "freebsd" { + opts = append(opts, + oci.WithMounts([]specs.Mount{ + {Type: "cgroup", Source: "cgroup", Destination: "/sys/fs/cgroup", Options: []string{"ro", "nosuid", "noexec", "nodev"}}, + })) + } + rootfsOpts, rootfsCOpts, ensuredImage, err := generateRootfsOpts(ctx, client, clicontext, id) if err != nil { return err diff --git a/cmd/nerdctl/run_cgroup_freebsd.go b/cmd/nerdctl/run_cgroup_freebsd.go new file mode 100644 index 00000000000..25fed14038b --- /dev/null +++ b/cmd/nerdctl/run_cgroup_freebsd.go @@ -0,0 +1,29 @@ +//go:build freebsd +// +build freebsd + +/* + 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/cmd/nerdctl/run_freebsd.go b/cmd/nerdctl/run_freebsd.go new file mode 100644 index 00000000000..18aebdee3fe --- /dev/null +++ b/cmd/nerdctl/run_freebsd.go @@ -0,0 +1,37 @@ +//go:build freebsd +// +build freebsd + +/* + 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 } +} diff --git a/pkg/containerinspector/containerinspector_freebsd.go b/pkg/containerinspector/containerinspector_freebsd.go new file mode 100644 index 00000000000..604d2f32fee --- /dev/null +++ b/pkg/containerinspector/containerinspector_freebsd.go @@ -0,0 +1,32 @@ +//go:build freebsd +// +build freebsd + +/* + 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/defaults_freebsd.go b/pkg/defaults/defaults_freebsd.go new file mode 100644 index 00000000000..c507e39207b --- /dev/null +++ b/pkg/defaults/defaults_freebsd.go @@ -0,0 +1,51 @@ +//go:build freebsd +// +build freebsd + +/* + 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 ( + gocni "github.com/containerd/go-cni" +) + +const AppArmorProfileName = "nerdctl-default" + +func DataRoot() string { + return "/var/lib/nerdctl" +} + +func CNIPath() string { + // default: /opt/cni/bin + return gocni.DefaultCNIDir +} + +func CNINetConfPath() string { + return gocni.DefaultNetDir +} + +func BuildKitHost() string { + return "unix:///run/buildkit/buildkitd.sock" +} + +func CgroupManager() string { + return "" +} + +func CgroupnsMode() string { + return "" +} diff --git a/pkg/infoutil/infoutil_freebsd.go b/pkg/infoutil/infoutil_freebsd.go new file mode 100644 index 00000000000..ad5c050f80a --- /dev/null +++ b/pkg/infoutil/infoutil_freebsd.go @@ -0,0 +1,26 @@ +//go:build freebsd +// +build freebsd + +/* + 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 + +const UnameO = "FreeBSD" + +func CgroupsVersion() string { + return "" +} diff --git a/pkg/infoutil/infoutil_linux.go b/pkg/infoutil/infoutil_linux.go index 1d2c6285b4d..cf6aab29ab1 100644 --- a/pkg/infoutil/infoutil_linux.go +++ b/pkg/infoutil/infoutil_linux.go @@ -17,98 +17,11 @@ package infoutil import ( - "bufio" - "io" - "os" - "regexp" - - "strings" - "github.com/containerd/cgroups" - "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 CgroupsVersion() string { if cgroups.Mode() == cgroups.Unified { return "2" diff --git a/pkg/infoutil/infoutil_unix.go b/pkg/infoutil/infoutil_unix.go new file mode 100644 index 00000000000..46f27a337a8 --- /dev/null +++ b/pkg/infoutil/infoutil_unix.go @@ -0,0 +1,110 @@ +//go:build freebsd || linux +// +build freebsd linux + +/* + 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 +} + +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_linux_test.go b/pkg/infoutil/infoutil_unix_test.go similarity index 98% rename from pkg/infoutil/infoutil_linux_test.go rename to pkg/infoutil/infoutil_unix_test.go index 90628f0b0af..f98d30c51ec 100644 --- a/pkg/infoutil/infoutil_linux_test.go +++ b/pkg/infoutil/infoutil_unix_test.go @@ -1,3 +1,6 @@ +//go:build freebsd || linux +// +build freebsd linux + /* Copyright The containerd Authors. diff --git a/pkg/lockutil/lockutil_linux.go b/pkg/lockutil/lockutil_unix.go similarity index 95% rename from pkg/lockutil/lockutil_linux.go rename to pkg/lockutil/lockutil_unix.go index f779a89e054..2a2e4a8ee4a 100644 --- a/pkg/lockutil/lockutil_linux.go +++ b/pkg/lockutil/lockutil_unix.go @@ -1,3 +1,7 @@ +//go:build freebsd || linux +// +build freebsd linux + + /* Copyright The containerd Authors. diff --git a/pkg/mountutil/mountutil_freebsd.go b/pkg/mountutil/mountutil_freebsd.go new file mode 100644 index 00000000000..e73d9c2b621 --- /dev/null +++ b/pkg/mountutil/mountutil_freebsd.go @@ -0,0 +1,63 @@ +//go:build freebsd +// +build freebsd + +/* + 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 ( + "fmt" + "strings" + + "github.com/containerd/containerd/oci" + "github.com/sirupsen/logrus" +) + +func getUnprivilegedMountFlags(path string) ([]string, error) { + m := []string{} + return m, nil +} + +// DefaultPropagationMode is the default propagation of mounts +// where user doesn't specify mount propagation explicitly. +// See also: https://github.com/moby/moby/blob/v20.10.7/volume/mounts/windows_parser.go#L440-L442 +const DefaultPropagationMode = "" + +// parseVolumeOptions parses specified optsRaw with using information of +// the volume type and the src directory when necessary. +func parseVolumeOptions(vType, src, optsRaw string) ([]string, []oci.SpecOpts, error) { + var writeModeRawOpts []string + for _, opt := range strings.Split(optsRaw, ",") { + switch opt { + case "rw": + writeModeRawOpts = append(writeModeRawOpts, opt) + case "ro": + writeModeRawOpts = append(writeModeRawOpts, opt) + case "": + // NOP + default: + logrus.Warnf("unsupported volume option %q", opt) + } + } + var opts []string + if len(writeModeRawOpts) > 1 { + return nil, nil, fmt.Errorf("duplicated read/write volume option: %+v", writeModeRawOpts) + } else if len(writeModeRawOpts) > 0 && writeModeRawOpts[0] == "ro" { + opts = append(opts, "ro") + } // No need to return option when "rw" + return opts, nil, nil +} diff --git a/pkg/netutil/netutil_linux.go b/pkg/netutil/netutil_unix.go similarity index 96% rename from pkg/netutil/netutil_linux.go rename to pkg/netutil/netutil_unix.go index 3b17a4aa057..7bc04612fa8 100644 --- a/pkg/netutil/netutil_linux.go +++ b/pkg/netutil/netutil_unix.go @@ -1,3 +1,6 @@ +//go:build freebsd || linux +// +build freebsd linux + /* Copyright The containerd Authors. diff --git a/pkg/ocihook/ocihook_freebsd.go b/pkg/ocihook/ocihook_freebsd.go new file mode 100644 index 00000000000..f6ab7d9d3cf --- /dev/null +++ b/pkg/ocihook/ocihook_freebsd.go @@ -0,0 +1,25 @@ +//go:build freebsd +// +build freebsd + +/* + 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 +}