From a531a67461af87e322c6e00356590d05617f4264 Mon Sep 17 00:00:00 2001 From: Amit Krishnan Date: Fri, 25 Mar 2016 16:38:00 -0700 Subject: [PATCH] Get the Docker Engine to build clean on Solaris Signed-off-by: Amit Krishnan --- directory/directory_unix.go | 2 +- fileutils/fileutils_solaris.go | 7 + listeners/listeners_solaris.go | 31 +++++ listeners/listeners_unix.go | 2 +- mount/flags_unsupported.go | 2 +- mount/mount.go | 4 +- mount/mounter_solaris.go | 33 +++++ mount/mounter_unsupported.go | 2 +- mount/mountinfo_solaris.go | 37 +++++ mount/mountinfo_unsupported.go | 2 +- parsers/kernel/uname_solaris.go | 14 ++ parsers/kernel/uname_unsupported.go | 2 +- .../operatingsystem_solaris.go | 37 +++++ platform/architecture_freebsd.go | 15 -- platform/architecture_unix.go | 18 +++ .../{command_freebsd.go => command_unix.go} | 2 +- reexec/command_unsupported.go | 2 +- signal/signal_solaris.go | 42 ++++++ signal/signal_unsupported.go | 2 +- sysinfo/sysinfo_solaris.go | 119 ++++++++++++++++ system/meminfo_solaris.go | 128 ++++++++++++++++++ system/meminfo_unsupported.go | 2 +- system/stat_solaris.go | 17 +++ 23 files changed, 495 insertions(+), 27 deletions(-) create mode 100644 fileutils/fileutils_solaris.go create mode 100644 listeners/listeners_solaris.go create mode 100644 mount/mounter_solaris.go create mode 100644 mount/mountinfo_solaris.go create mode 100644 parsers/kernel/uname_solaris.go create mode 100644 parsers/operatingsystem/operatingsystem_solaris.go delete mode 100644 platform/architecture_freebsd.go create mode 100644 platform/architecture_unix.go rename reexec/{command_freebsd.go => command_unix.go} (94%) create mode 100644 signal/signal_solaris.go create mode 100644 sysinfo/sysinfo_solaris.go create mode 100644 system/meminfo_solaris.go diff --git a/directory/directory_unix.go b/directory/directory_unix.go index dbebdd3..b43c79f 100644 --- a/directory/directory_unix.go +++ b/directory/directory_unix.go @@ -1,4 +1,4 @@ -// +build linux freebsd +// +build linux freebsd solaris package directory diff --git a/fileutils/fileutils_solaris.go b/fileutils/fileutils_solaris.go new file mode 100644 index 0000000..0f2cb7a --- /dev/null +++ b/fileutils/fileutils_solaris.go @@ -0,0 +1,7 @@ +package fileutils + +// GetTotalUsedFds Returns the number of used File Descriptors. +// On Solaris these limits are per process and not systemwide +func GetTotalUsedFds() int { + return -1 +} diff --git a/listeners/listeners_solaris.go b/listeners/listeners_solaris.go new file mode 100644 index 0000000..ff833e3 --- /dev/null +++ b/listeners/listeners_solaris.go @@ -0,0 +1,31 @@ +package listeners + +import ( + "crypto/tls" + "fmt" + "net" + + "github.com/docker/go-connections/sockets" +) + +// Init creates new listeners for the server. +func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) (ls []net.Listener, err error) { + switch proto { + case "tcp": + l, err := sockets.NewTCPSocket(addr, tlsConfig) + if err != nil { + return nil, err + } + ls = append(ls, l) + case "unix": + l, err := sockets.NewUnixSocket(addr, socketGroup) + if err != nil { + return nil, fmt.Errorf("can't create unix socket %s: %v", addr, err) + } + ls = append(ls, l) + default: + return nil, fmt.Errorf("Invalid protocol format: %q", proto) + } + + return +} diff --git a/listeners/listeners_unix.go b/listeners/listeners_unix.go index fddd3a8..1bcae7a 100644 --- a/listeners/listeners_unix.go +++ b/listeners/listeners_unix.go @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows,!solaris package listeners diff --git a/mount/flags_unsupported.go b/mount/flags_unsupported.go index a90d3d1..5564f7b 100644 --- a/mount/flags_unsupported.go +++ b/mount/flags_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd freebsd,!cgo +// +build !linux,!freebsd freebsd,!cgo solaris,!cgo package mount diff --git a/mount/mount.go b/mount/mount.go index ed7216e..66ac4bf 100644 --- a/mount/mount.go +++ b/mount/mount.go @@ -9,8 +9,8 @@ func GetMounts() ([]*Info, error) { return parseMountTable() } -// Mounted looks at /proc/self/mountinfo to determine of the specified -// mountpoint has been mounted +// Mounted determines if a specified mountpoint has been mounted. +// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab. func Mounted(mountpoint string) (bool, error) { entries, err := parseMountTable() if err != nil { diff --git a/mount/mounter_solaris.go b/mount/mounter_solaris.go new file mode 100644 index 0000000..c684aa8 --- /dev/null +++ b/mount/mounter_solaris.go @@ -0,0 +1,33 @@ +// +build solaris,cgo + +package mount + +import ( + "golang.org/x/sys/unix" + "unsafe" +) + +// #include +// #include +// #include +// int Mount(const char *spec, const char *dir, int mflag, +// char *fstype, char *dataptr, int datalen, char *optptr, int optlen) { +// return mount(spec, dir, mflag, fstype, dataptr, datalen, optptr, optlen); +// } +import "C" + +func mount(device, target, mType string, flag uintptr, data string) error { + spec := C.CString(device) + dir := C.CString(target) + fstype := C.CString(mType) + _, err := C.Mount(spec, dir, C.int(flag), fstype, nil, 0, nil, 0) + C.free(unsafe.Pointer(spec)) + C.free(unsafe.Pointer(dir)) + C.free(unsafe.Pointer(fstype)) + return err +} + +func unmount(target string, flag int) error { + err := unix.Unmount(target, flag) + return err +} diff --git a/mount/mounter_unsupported.go b/mount/mounter_unsupported.go index eb93365..a2a3bb4 100644 --- a/mount/mounter_unsupported.go +++ b/mount/mounter_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd freebsd,!cgo +// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo package mount diff --git a/mount/mountinfo_solaris.go b/mount/mountinfo_solaris.go new file mode 100644 index 0000000..ad9ab57 --- /dev/null +++ b/mount/mountinfo_solaris.go @@ -0,0 +1,37 @@ +// +build solaris,cgo + +package mount + +/* +#include +#include +*/ +import "C" + +import ( + "fmt" +) + +func parseMountTable() ([]*Info, error) { + mnttab := C.fopen(C.CString(C.MNTTAB), C.CString("r")) + if mnttab == nil { + return nil, fmt.Errorf("Failed to open %s", C.MNTTAB) + } + + var out []*Info + var mp C.struct_mnttab + + ret := C.getmntent(mnttab, &mp) + for ret == 0 { + var mountinfo Info + mountinfo.Mountpoint = C.GoString(mp.mnt_mountp) + mountinfo.Source = C.GoString(mp.mnt_special) + mountinfo.Fstype = C.GoString(mp.mnt_fstype) + mountinfo.Opts = C.GoString(mp.mnt_mntopts) + out = append(out, &mountinfo) + ret = C.getmntent(mnttab, &mp) + } + + C.fclose(mnttab) + return out, nil +} diff --git a/mount/mountinfo_unsupported.go b/mount/mountinfo_unsupported.go index b8d9aa5..7fbcf19 100644 --- a/mount/mountinfo_unsupported.go +++ b/mount/mountinfo_unsupported.go @@ -1,4 +1,4 @@ -// +build !windows,!linux,!freebsd freebsd,!cgo +// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo package mount diff --git a/parsers/kernel/uname_solaris.go b/parsers/kernel/uname_solaris.go new file mode 100644 index 0000000..49370bd --- /dev/null +++ b/parsers/kernel/uname_solaris.go @@ -0,0 +1,14 @@ +package kernel + +import ( + "golang.org/x/sys/unix" +) + +func uname() (*unix.Utsname, error) { + uts := &unix.Utsname{} + + if err := unix.Uname(uts); err != nil { + return nil, err + } + return uts, nil +} diff --git a/parsers/kernel/uname_unsupported.go b/parsers/kernel/uname_unsupported.go index 79c66b3..1da3f23 100644 --- a/parsers/kernel/uname_unsupported.go +++ b/parsers/kernel/uname_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!solaris package kernel diff --git a/parsers/operatingsystem/operatingsystem_solaris.go b/parsers/operatingsystem/operatingsystem_solaris.go new file mode 100644 index 0000000..d08ad14 --- /dev/null +++ b/parsers/operatingsystem/operatingsystem_solaris.go @@ -0,0 +1,37 @@ +// +build solaris,cgo + +package operatingsystem + +/* +#include +*/ +import "C" + +import ( + "bytes" + "errors" + "io/ioutil" +) + +var etcOsRelease = "/etc/release" + +// GetOperatingSystem gets the name of the current operating system. +func GetOperatingSystem() (string, error) { + b, err := ioutil.ReadFile(etcOsRelease) + if err != nil { + return "", err + } + if i := bytes.Index(b, []byte("\n")); i >= 0 { + b = bytes.Trim(b[:i], " ") + return string(b), nil + } + return "", errors.New("release not found") +} + +// IsContainerized returns true if we are running inside a container. +func IsContainerized() (bool, error) { + if C.getzoneid() != 0 { + return true, nil + } + return false, nil +} diff --git a/platform/architecture_freebsd.go b/platform/architecture_freebsd.go deleted file mode 100644 index 5849ecc..0000000 --- a/platform/architecture_freebsd.go +++ /dev/null @@ -1,15 +0,0 @@ -package platform - -import ( - "os/exec" -) - -// runtimeArchitecture gets the name of the current architecture (x86, x86_64, …) -func runtimeArchitecture() (string, error) { - cmd := exec.Command("uname", "-m") - machine, err := cmd.Output() - if err != nil { - return "", err - } - return string(machine), nil -} diff --git a/platform/architecture_unix.go b/platform/architecture_unix.go new file mode 100644 index 0000000..21e6a26 --- /dev/null +++ b/platform/architecture_unix.go @@ -0,0 +1,18 @@ +// +build freebsd solaris + +package platform + +import ( + "os/exec" + "strings" +) + +// runtimeArchitecture get the name of the current architecture (i86pc, sun4v) +func runtimeArchitecture() (string, error) { + cmd := exec.Command("/usr/bin/uname", "-m") + machine, err := cmd.Output() + if err != nil { + return "", err + } + return strings.TrimSpace(string(machine)), nil +} diff --git a/reexec/command_freebsd.go b/reexec/command_unix.go similarity index 94% rename from reexec/command_freebsd.go rename to reexec/command_unix.go index c7f797a..b70edcb 100644 --- a/reexec/command_freebsd.go +++ b/reexec/command_unix.go @@ -1,4 +1,4 @@ -// +build freebsd +// +build freebsd solaris package reexec diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index ad4ea38..9aed004 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd +// +build !linux,!windows,!freebsd,!solaris package reexec diff --git a/signal/signal_solaris.go b/signal/signal_solaris.go new file mode 100644 index 0000000..89576b9 --- /dev/null +++ b/signal/signal_solaris.go @@ -0,0 +1,42 @@ +package signal + +import ( + "syscall" +) + +// SignalMap is a map of Solaris signals. +// SIGINFO and SIGTHR not defined for Solaris +var SignalMap = map[string]syscall.Signal{ + "ABRT": syscall.SIGABRT, + "ALRM": syscall.SIGALRM, + "BUF": syscall.SIGBUS, + "CHLD": syscall.SIGCHLD, + "CONT": syscall.SIGCONT, + "EMT": syscall.SIGEMT, + "FPE": syscall.SIGFPE, + "HUP": syscall.SIGHUP, + "ILL": syscall.SIGILL, + "INT": syscall.SIGINT, + "IO": syscall.SIGIO, + "IOT": syscall.SIGIOT, + "KILL": syscall.SIGKILL, + "LWP": syscall.SIGLWP, + "PIPE": syscall.SIGPIPE, + "PROF": syscall.SIGPROF, + "QUIT": syscall.SIGQUIT, + "SEGV": syscall.SIGSEGV, + "STOP": syscall.SIGSTOP, + "SYS": syscall.SIGSYS, + "TERM": syscall.SIGTERM, + "TRAP": syscall.SIGTRAP, + "TSTP": syscall.SIGTSTP, + "TTIN": syscall.SIGTTIN, + "TTOU": syscall.SIGTTOU, + "URG": syscall.SIGURG, + "USR1": syscall.SIGUSR1, + "USR2": syscall.SIGUSR2, + "VTALRM": syscall.SIGVTALRM, + "WINCH": syscall.SIGWINCH, + "XCPU": syscall.SIGXCPU, + "XFSZ": syscall.SIGXFSZ, +} diff --git a/signal/signal_unsupported.go b/signal/signal_unsupported.go index 161ba27..c592d37 100644 --- a/signal/signal_unsupported.go +++ b/signal/signal_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!darwin,!freebsd,!windows +// +build !linux,!darwin,!freebsd,!windows,!solaris package signal diff --git a/sysinfo/sysinfo_solaris.go b/sysinfo/sysinfo_solaris.go new file mode 100644 index 0000000..75a9c9b --- /dev/null +++ b/sysinfo/sysinfo_solaris.go @@ -0,0 +1,119 @@ +// +build solaris,cgo + +package sysinfo + +import ( + "bytes" + "os/exec" + "strconv" + "strings" +) + +/* +#cgo LDFLAGS: -llgrp +#include +#include +#include +int getLgrpCount() { + lgrp_cookie_t lgrpcookie = LGRP_COOKIE_NONE; + uint_t nlgrps; + + if ((lgrpcookie = lgrp_init(LGRP_VIEW_OS)) == LGRP_COOKIE_NONE) { + return -1; + } + nlgrps = lgrp_nlgrps(lgrpcookie); + return nlgrps; +} +*/ +import "C" + +// IsCPUSharesAvailable returns whether CPUShares setting is supported. +// We need FSS to be set as default scheduling class to support CPU Shares +func IsCPUSharesAvailable() bool { + cmd := exec.Command("/usr/sbin/dispadmin", "-d") + outBuf := new(bytes.Buffer) + errBuf := new(bytes.Buffer) + cmd.Stderr = errBuf + cmd.Stdout = outBuf + + if err := cmd.Run(); err != nil { + return false + } + return (strings.Contains(outBuf.String(), "FSS")) +} + +// New returns a new SysInfo, using the filesystem to detect which features +// the kernel supports. +//NOTE Solaris: If we change the below capabilities be sure +// to update verifyPlatformContainerSettings() in daemon_solaris.go +func New(quiet bool) *SysInfo { + sysInfo := &SysInfo{} + sysInfo.cgroupMemInfo = setCgroupMem(quiet) + sysInfo.cgroupCPUInfo = setCgroupCPU(quiet) + sysInfo.cgroupBlkioInfo = setCgroupBlkioInfo(quiet) + sysInfo.cgroupCpusetInfo = setCgroupCPUsetInfo(quiet) + + sysInfo.IPv4ForwardingDisabled = false + + sysInfo.AppArmor = false + + return sysInfo +} + +// setCgroupMem reads the memory information for Solaris. +func setCgroupMem(quiet bool) cgroupMemInfo { + + return cgroupMemInfo{ + MemoryLimit: true, + SwapLimit: true, + MemoryReservation: false, + OomKillDisable: false, + MemorySwappiness: false, + KernelMemory: false, + } +} + +// setCgroupCPU reads the cpu information for Solaris. +func setCgroupCPU(quiet bool) cgroupCPUInfo { + + return cgroupCPUInfo{ + CPUShares: true, + CPUCfsPeriod: false, + CPUCfsQuota: true, + } +} + +// blkio switches are not supported in Solaris. +func setCgroupBlkioInfo(quiet bool) cgroupBlkioInfo { + + return cgroupBlkioInfo{ + BlkioWeight: false, + BlkioWeightDevice: false, + } +} + +// setCgroupCPUsetInfo reads the cpuset information for Solaris. +func setCgroupCPUsetInfo(quiet bool) cgroupCpusetInfo { + + return cgroupCpusetInfo{ + Cpuset: true, + Cpus: getCPUCount(), + Mems: getLgrpCount(), + } +} + +func getCPUCount() string { + ncpus := C.sysconf(C._SC_NPROCESSORS_ONLN) + if ncpus <= 0 { + return "" + } + return strconv.FormatInt(int64(ncpus), 16) +} + +func getLgrpCount() string { + nlgrps := C.getLgrpCount() + if nlgrps <= 0 { + return "" + } + return strconv.FormatInt(int64(nlgrps), 16) +} diff --git a/system/meminfo_solaris.go b/system/meminfo_solaris.go new file mode 100644 index 0000000..313c601 --- /dev/null +++ b/system/meminfo_solaris.go @@ -0,0 +1,128 @@ +// +build solaris,cgo + +package system + +import ( + "fmt" + "unsafe" +) + +// #cgo LDFLAGS: -lkstat +// #include +// #include +// #include +// #include +// #include +// #include +// struct swaptable *allocSwaptable(int num) { +// struct swaptable *st; +// struct swapent *swapent; +// st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int)); +// swapent = st->swt_ent; +// for (int i = 0; i < num; i++,swapent++) { +// swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char)); +// } +// st->swt_n = num; +// return st; +//} +// void freeSwaptable (struct swaptable *st) { +// struct swapent *swapent = st->swt_ent; +// for (int i = 0; i < st->swt_n; i++,swapent++) { +// free(swapent->ste_path); +// } +// free(st); +// } +// swapent_t getSwapEnt(swapent_t *ent, int i) { +// return ent[i]; +// } +// int64_t getPpKernel() { +// int64_t pp_kernel = 0; +// kstat_ctl_t *ksc; +// kstat_t *ks; +// kstat_named_t *knp; +// kid_t kid; +// +// if ((ksc = kstat_open()) == NULL) { +// return -1; +// } +// if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) { +// return -1; +// } +// if (((kid = kstat_read(ksc, ks, NULL)) == -1) || +// ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) { +// return -1; +// } +// switch (knp->data_type) { +// case KSTAT_DATA_UINT64: +// pp_kernel = knp->value.ui64; +// break; +// case KSTAT_DATA_UINT32: +// pp_kernel = knp->value.ui32; +// break; +// } +// pp_kernel *= sysconf(_SC_PAGESIZE); +// return (pp_kernel > 0 ? pp_kernel : -1); +// } +import "C" + +// Get the system memory info using sysconf same as prtconf +func getTotalMem() int64 { + pagesize := C.sysconf(C._SC_PAGESIZE) + npages := C.sysconf(C._SC_PHYS_PAGES) + return int64(pagesize * npages) +} + +func getFreeMem() int64 { + pagesize := C.sysconf(C._SC_PAGESIZE) + npages := C.sysconf(C._SC_AVPHYS_PAGES) + return int64(pagesize * npages) +} + +// ReadMemInfo retrieves memory statistics of the host system and returns a +// MemInfo type. +func ReadMemInfo() (*MemInfo, error) { + + ppKernel := C.getPpKernel() + MemTotal := getTotalMem() + MemFree := getFreeMem() + SwapTotal, SwapFree, err := getSysSwap() + + if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 || + SwapFree < 0 { + return nil, fmt.Errorf("Error getting system memory info %v\n", err) + } + + meminfo := &MemInfo{} + // Total memory is total physical memory less than memory locked by kernel + meminfo.MemTotal = MemTotal - int64(ppKernel) + meminfo.MemFree = MemFree + meminfo.SwapTotal = SwapTotal + meminfo.SwapFree = SwapFree + + return meminfo, nil +} + +func getSysSwap() (int64, int64, error) { + var tSwap int64 + var fSwap int64 + var diskblksPerPage int64 + num, err := C.swapctl(C.SC_GETNSWP, nil) + if err != nil { + return -1, -1, err + } + st := C.allocSwaptable(num) + _, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st)) + if err != nil { + C.freeSwaptable(st) + return -1, -1, err + } + + diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT) + for i := 0; i < int(num); i++ { + swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i)) + tSwap += int64(swapent.ste_pages) * diskblksPerPage + fSwap += int64(swapent.ste_free) * diskblksPerPage + } + C.freeSwaptable(st) + return tSwap, fSwap, nil +} diff --git a/system/meminfo_unsupported.go b/system/meminfo_unsupported.go index 82ddd30..3ce019d 100644 --- a/system/meminfo_unsupported.go +++ b/system/meminfo_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows +// +build !linux,!windows,!solaris package system diff --git a/system/stat_solaris.go b/system/stat_solaris.go index b01d08a..0216985 100644 --- a/system/stat_solaris.go +++ b/system/stat_solaris.go @@ -15,3 +15,20 @@ func fromStatT(s *syscall.Stat_t) (*StatT, error) { rdev: uint64(s.Rdev), mtim: s.Mtim}, nil } + +// FromStatT loads a system.StatT from a syscal.Stat_t. +func FromStatT(s *syscall.Stat_t) (*StatT, error) { + return fromStatT(s) +} + +// Stat takes a path to a file and returns +// a system.StatT type pertaining to that file. +// +// Throws an error if the file does not exist +func Stat(path string) (*StatT, error) { + s := &syscall.Stat_t{} + if err := syscall.Stat(path, s); err != nil { + return nil, err + } + return fromStatT(s) +}