diff --git a/.travis.yml b/.travis.yml index 7df354b88..f5e39a336 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ env: - TRAVIS_GOOS=windows TRAVIS_CGO_ENABLED=1 - TRAVIS_GOOS=linux TRAVIS_CGO_ENABLED=1 - TRAVIS_GOOS=darwin TRAVIS_CGO_ENABLED=0 + - TRAVIS_GOOS=solaris TRAVIS_CGO_ENABLED=0 before_install: - uname -r diff --git a/Makefile b/Makefile index c4ef47037..c42771f48 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,10 @@ REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet ifneq "$(strip $(shell command -v go 2>/dev/null))" "" GOOS ?= $(shell go env GOOS) + GOARCH ?= $(shell go env GOARCH) else GOOS ?= $$GOOS + GOARCH ?= $$GOARCH endif WHALE = "🇩" @@ -22,16 +24,28 @@ ifeq ("$(OS)", "Windows_NT") ONI="-" FIX_PATH = $(subst /,\,$1) endif -GOARCH ?= $(shell go env GOARCH) RELEASE=containerd-$(VERSION:v%=%).${GOOS}-${GOARCH} PKG=github.com/containerd/containerd +# on SunOS default to gnu utilities for things like grep, sed, etc. +ifeq ($(shell uname -s),SunOS) + export PATH := /usr/gnu/bin:$(PATH) +endif + # Project packages. PACKAGES=$(shell go list ./... | grep -v /vendor/) INTEGRATION_PACKAGE=${PKG} -TEST_REQUIRES_ROOT_PACKAGES=$(shell for f in $$(git grep -l testutil.RequiresRoot | grep -v Makefile);do echo "${PKG}/$$(dirname $$f)"; done) +TEST_REQUIRES_ROOT_PACKAGES=$(filter \ + ${PACKAGES}, \ + $(shell \ + for f in $$(git grep -l testutil.RequiresRoot | grep -v Makefile); do \ + d="$$(dirname $$f)"; \ + [ "$$d" = "." ] && echo "${PKG}" && continue; \ + echo "${PKG}/$$d"; \ + done | sort -u) \ + ) # Project binaries. COMMANDS=ctr containerd @@ -46,8 +60,16 @@ endif GO_TAGS=$(if $(BUILDTAGS),-tags "$(BUILDTAGS)",) GO_LDFLAGS=-ldflags "-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PKG) $(EXTRA_LDFLAGS)" +# go test -race is only supported on the patforms listed below. +TESTFLAGS_RACE= +ifeq ($(filter \ + linux/amd64 freebsd/amd64 darwin/amd64 windows/amd64, \ + $(GOOS)/$(GOARCH)),$(GOOS)/$(GOARCH)) + TESTFLAGS_RACE= -race +endif + # Flags passed to `go test` -TESTFLAGS ?=-parallel 8 -race -v +TESTFLAGS ?=-parallel 8 -v $(TESTFLAGS_RACE) .PHONY: clean all AUTHORS fmt vet lint dco build binaries test integration setup generate protos checkprotos coverage ci check help install uninstall vendor release .DEFAULT: default diff --git a/archive/time_unix.go b/archive/time_unix.go index 5f17084f2..054f06eba 100644 --- a/archive/time_unix.go +++ b/archive/time_unix.go @@ -1,4 +1,4 @@ -// +build linux freebsd +// +build linux freebsd solaris package archive diff --git a/cmd/containerd/builtins_unix.go b/cmd/containerd/builtins_unix.go index 15133150e..3983aa7ef 100644 --- a/cmd/containerd/builtins_unix.go +++ b/cmd/containerd/builtins_unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build darwin freebsd solaris package main diff --git a/cmd/containerd/config_solaris.go b/cmd/containerd/config_solaris.go new file mode 100644 index 000000000..15ab7e471 --- /dev/null +++ b/cmd/containerd/config_solaris.go @@ -0,0 +1,18 @@ +// +build solaris + +package main + +import "github.com/containerd/containerd/server" + +func defaultConfig() *server.Config { + return &server.Config{ + Root: "/var/lib/containerd", + GRPC: server.GRPCConfig{ + Address: server.DefaultAddress, + }, + Debug: server.Debug{ + Level: "info", + Address: server.DefaultDebugAddress, + }, + } +} diff --git a/cmd/containerd/config_unsupported.go b/cmd/containerd/config_unsupported.go index 6a7478f44..230327901 100644 --- a/cmd/containerd/config_unsupported.go +++ b/cmd/containerd/config_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows +// +build !linux,!windows,!solaris package main diff --git a/cmd/containerd/main_unix.go b/cmd/containerd/main_unix.go index 6fcf8de63..385467fd5 100644 --- a/cmd/containerd/main_unix.go +++ b/cmd/containerd/main_unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build darwin freebsd solaris package main diff --git a/cmd/ctr/signals_unix.go b/cmd/ctr/signals_unix.go index f7b962f17..871a8f6bf 100644 --- a/cmd/ctr/signals_unix.go +++ b/cmd/ctr/signals_unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build darwin freebsd solaris package main diff --git a/content/local/store_linux.go b/content/local/store_linux.go deleted file mode 100644 index e1f89f31d..000000000 --- a/content/local/store_linux.go +++ /dev/null @@ -1,15 +0,0 @@ -package local - -import ( - "os" - "syscall" - "time" -) - -func getStartTime(fi os.FileInfo) time.Time { - if st, ok := fi.Sys().(*syscall.Stat_t); ok { - return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec)) - } - - return fi.ModTime() -} diff --git a/content/local/store_unix.go b/content/local/store_unix.go index 75b269972..46eab02c5 100644 --- a/content/local/store_unix.go +++ b/content/local/store_unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build linux solaris darwin freebsd package local @@ -6,11 +6,14 @@ import ( "os" "syscall" "time" + + "github.com/containerd/containerd/sys" ) func getStartTime(fi os.FileInfo) time.Time { if st, ok := fi.Sys().(*syscall.Stat_t); ok { - return time.Unix(int64(st.Ctimespec.Sec), int64(st.Ctimespec.Nsec)) + return time.Unix(int64(sys.StatCtime(st).Sec), + int64(sys.StatCtime(st).Nsec)) } return fi.ModTime() diff --git a/fs/copy_linux.go b/fs/copy_linux.go index efa924861..acc56f67d 100644 --- a/fs/copy_linux.go +++ b/fs/copy_linux.go @@ -5,6 +5,7 @@ import ( "os" "syscall" + "github.com/containerd/containerd/sys" "github.com/containerd/continuity/sysx" "github.com/pkg/errors" "golang.org/x/sys/unix" @@ -22,7 +23,7 @@ func copyFileInfo(fi os.FileInfo, name string) error { } } - timespec := []unix.Timespec{unix.Timespec(st.Atim), unix.Timespec(st.Mtim)} + timespec := []unix.Timespec{unix.Timespec(sys.StatAtime(st)), unix.Timespec(sys.StatMtime(st))} if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil { return errors.Wrapf(err, "failed to utime %s", name) } diff --git a/fs/copy_unix.go b/fs/copy_unix.go index 4a6cce49d..3ddbc5f93 100644 --- a/fs/copy_unix.go +++ b/fs/copy_unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build solaris darwin freebsd package fs @@ -7,6 +7,7 @@ import ( "os" "syscall" + "github.com/containerd/containerd/sys" "github.com/containerd/continuity/sysx" "github.com/pkg/errors" ) @@ -23,7 +24,8 @@ func copyFileInfo(fi os.FileInfo, name string) error { } } - if err := syscall.UtimesNano(name, []syscall.Timespec{st.Atimespec, st.Mtimespec}); err != nil { + timespec := []syscall.Timespec{sys.StatAtime(st), sys.StatMtime(st)} + if err := syscall.UtimesNano(name, timespec); err != nil { return errors.Wrapf(err, "failed to utime %s", name) } diff --git a/fs/dtype_test.go b/fs/dtype_test.go new file mode 100644 index 000000000..7b551f051 --- /dev/null +++ b/fs/dtype_test.go @@ -0,0 +1,26 @@ +package fs + +import ( + "testing" + + "github.com/containerd/containerd/testutil" +) + +func TestRequiresRootNOP(t *testing.T) { + + // This is a dummy test case that exist to call + // testutil.RequiresRoot() on non-linux platforms. This is + // needed because the Makfile root-coverage tests target + // determines which packages contain root test by grepping for + // testutil.RequiresRoot. Within the fs package, the only test + // that references this symbol is in dtype_linux_test.go, but + // that file is only built on linux. Since the Makefile is not + // go build tag aware it sees this file and then tries to run + // the following command on all platforms: "go test ... + // github.com/containerd/containerd/fs -test.root". On + // non-linux platforms this fails because there are no tests in + // the "fs" package that reference testutil.RequiresRoot. To + // fix this problem we'll add a reference to this symbol below. + + testutil.RequiresRoot(t) +} diff --git a/mount/mount_solaris.go b/mount/mount_solaris.go new file mode 100644 index 000000000..3b6c35d74 --- /dev/null +++ b/mount/mount_solaris.go @@ -0,0 +1,83 @@ +package mount + +// On Solaris we can't invoke the mount system call directly. First, +// the mount system call takes more than 6 arguments, and go doesn't +// support invoking system calls that take more than 6 arguments. Past +// that, the mount system call is a private interfaces. For example, +// the arguments and data structures passed to the kernel to create an +// nfs mount are private and can change at any time. The only public +// and stable interface for creating mounts on Solaris is the mount.8 +// command, so we'll invoke that here. + +import ( + "bytes" + "errors" + "fmt" + "os/exec" + "strings" + + "golang.org/x/sys/unix" +) + +const ( + mountCmd = "/usr/sbin/mount" +) + +func doMount(arg ...string) error { + cmd := exec.Command(mountCmd, arg...) + + /* Setup Stdin, Stdout, and Stderr */ + stderr := new(bytes.Buffer) + cmd.Stdin = nil + cmd.Stdout = nil + cmd.Stderr = stderr + + /* + * Run the command. If the command fails create a new error + * object to return that includes stderr output. + */ + err := cmd.Start() + if err != nil { + return err + } + err = cmd.Wait() + if err != nil { + return errors.New(fmt.Sprintf("%v: %s", err, stderr.String())) + } + return nil +} + +func (m *Mount) Mount(target string) error { + var err error + + if len(m.Options) == 0 { + err = doMount("-F", m.Type, m.Source, target) + } else { + err = doMount("-F", m.Type, "-o", strings.Join(m.Options, ","), + m.Source, target) + } + return err +} + +func Unmount(mount string, flags int) error { + return unix.Unmount(mount, flags) +} + +// UnmountAll repeatedly unmounts the given mount point until there +// are no mounts remaining (EINVAL is returned by mount), which is +// useful for undoing a stack of mounts on the same mount point. +func UnmountAll(mount string, flags int) error { + for { + if err := Unmount(mount, flags); err != nil { + // EINVAL is returned if the target is not a + // mount point, indicating that we are + // done. It can also indicate a few other + // things (such as invalid flags) which we + // unfortunately end up squelching here too. + if err == unix.EINVAL { + return nil + } + return err + } + } +} diff --git a/server/server_solaris.go b/server/server_solaris.go new file mode 100644 index 000000000..35b7434e3 --- /dev/null +++ b/server/server_solaris.go @@ -0,0 +1,14 @@ +package server + +import "context" + +const ( + // DefaultAddress is the default unix socket address + DefaultAddress = "/var/run/containerd/containerd.sock" + // DefaultDebuggAddress is the default unix socket address for pprof data + DefaultDebugAddress = "/var/run/containerd/debug.sock" +) + +func apply(_ context.Context, _ *Config) error { + return nil +} diff --git a/server/server_unsupported.go b/server/server_unsupported.go index 197bfa029..e625cc892 100644 --- a/server/server_unsupported.go +++ b/server/server_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows +// +build !linux,!windows,!solaris package server diff --git a/services/snapshot/default_unix.go b/services/snapshot/default_unix.go index 1adf5ca7d..3489cf8cf 100644 --- a/services/snapshot/default_unix.go +++ b/services/snapshot/default_unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build darwin freebsd solaris package snapshot diff --git a/snapshot/btrfs/btrfs.go b/snapshot/btrfs/btrfs.go index e9f963b07..44ae8bd46 100644 --- a/snapshot/btrfs/btrfs.go +++ b/snapshot/btrfs/btrfs.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,!no_btrfs package btrfs diff --git a/snapshot/btrfs/btrfs_test.go b/snapshot/btrfs/btrfs_test.go index afc251570..4175f9662 100644 --- a/snapshot/btrfs/btrfs_test.go +++ b/snapshot/btrfs/btrfs_test.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,!no_btrfs package btrfs diff --git a/sys/stat_bsd.go b/sys/stat_bsd.go new file mode 100644 index 000000000..13db2b32e --- /dev/null +++ b/sys/stat_bsd.go @@ -0,0 +1,19 @@ +// +build darwin freebsd + +package sys + +import ( + "syscall" +) + +func StatAtime(st *syscall.Stat_t) syscall.Timespec { + return st.Atimespec +} + +func StatCtime(st *syscall.Stat_t) syscall.Timespec { + return st.Ctimespec +} + +func StatMtime(st *syscall.Stat_t) syscall.Timespec { + return st.Mtimespec +} diff --git a/sys/stat_unix.go b/sys/stat_unix.go new file mode 100644 index 000000000..da13ed26e --- /dev/null +++ b/sys/stat_unix.go @@ -0,0 +1,19 @@ +// +build linux solaris + +package sys + +import ( + "syscall" +) + +func StatAtime(st *syscall.Stat_t) syscall.Timespec { + return st.Atim +} + +func StatCtime(st *syscall.Stat_t) syscall.Timespec { + return st.Ctim +} + +func StatMtime(st *syscall.Stat_t) syscall.Timespec { + return st.Mtim +}