Remove the unused pkgs

We're not using pkg/jsonmessage, pkg/parsers/operatingsystem,
pkg/pidfile, or pkg/sysinfo, so remove them.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2017-01-12 10:21:42 -05:00
parent 55e5d76085
commit c4bcd1cf17
21 changed files with 0 additions and 1719 deletions

View file

@ -1,221 +0,0 @@
package jsonmessage
import (
"encoding/json"
"fmt"
"io"
"strings"
"time"
"github.com/containers/storage/pkg/jsonlog"
"github.com/containers/storage/pkg/term"
"github.com/docker/go-units"
)
// JSONError wraps a concrete Code and Message, `Code` is
// is an integer error code, `Message` is the error message.
type JSONError struct {
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
func (e *JSONError) Error() string {
return e.Message
}
// JSONProgress describes a Progress. terminalFd is the fd of the current terminal,
// Start is the initial value for the operation. Current is the current status and
// value of the progress made towards Total. Total is the end value describing when
// we made 100% progress for an operation.
type JSONProgress struct {
terminalFd uintptr
Current int64 `json:"current,omitempty"`
Total int64 `json:"total,omitempty"`
Start int64 `json:"start,omitempty"`
}
func (p *JSONProgress) String() string {
var (
width = 200
pbBox string
numbersBox string
timeLeftBox string
)
ws, err := term.GetWinsize(p.terminalFd)
if err == nil {
width = int(ws.Width)
}
if p.Current <= 0 && p.Total <= 0 {
return ""
}
current := units.HumanSize(float64(p.Current))
if p.Total <= 0 {
return fmt.Sprintf("%8v", current)
}
total := units.HumanSize(float64(p.Total))
percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
if percentage > 50 {
percentage = 50
}
if width > 110 {
// this number can't be negative gh#7136
numSpaces := 0
if 50-percentage > 0 {
numSpaces = 50 - percentage
}
pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
}
numbersBox = fmt.Sprintf("%8v/%v", current, total)
if p.Current > p.Total {
// remove total display if the reported current is wonky.
numbersBox = fmt.Sprintf("%8v", current)
}
if p.Current > 0 && p.Start > 0 && percentage < 50 {
fromStart := time.Now().UTC().Sub(time.Unix(p.Start, 0))
perEntry := fromStart / time.Duration(p.Current)
left := time.Duration(p.Total-p.Current) * perEntry
left = (left / time.Second) * time.Second
if width > 50 {
timeLeftBox = " " + left.String()
}
}
return pbBox + numbersBox + timeLeftBox
}
// JSONMessage defines a message struct. It describes
// the created time, where it from, status, ID of the
// message. It's used for docker events.
type JSONMessage struct {
Stream string `json:"stream,omitempty"`
Status string `json:"status,omitempty"`
Progress *JSONProgress `json:"progressDetail,omitempty"`
ProgressMessage string `json:"progress,omitempty"` //deprecated
ID string `json:"id,omitempty"`
From string `json:"from,omitempty"`
Time int64 `json:"time,omitempty"`
TimeNano int64 `json:"timeNano,omitempty"`
Error *JSONError `json:"errorDetail,omitempty"`
ErrorMessage string `json:"error,omitempty"` //deprecated
// Aux contains out-of-band data, such as digests for push signing.
Aux *json.RawMessage `json:"aux,omitempty"`
}
// Display displays the JSONMessage to `out`. `isTerminal` describes if `out`
// is a terminal. If this is the case, it will erase the entire current line
// when displaying the progressbar.
func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
if jm.Error != nil {
if jm.Error.Code == 401 {
return fmt.Errorf("Authentication is required.")
}
return jm.Error
}
var endl string
if isTerminal && jm.Stream == "" && jm.Progress != nil {
// <ESC>[2K = erase entire current line
fmt.Fprintf(out, "%c[2K\r", 27)
endl = "\r"
} else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal
return nil
}
if jm.TimeNano != 0 {
fmt.Fprintf(out, "%s ", time.Unix(0, jm.TimeNano).Format(jsonlog.RFC3339NanoFixed))
} else if jm.Time != 0 {
fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(jsonlog.RFC3339NanoFixed))
}
if jm.ID != "" {
fmt.Fprintf(out, "%s: ", jm.ID)
}
if jm.From != "" {
fmt.Fprintf(out, "(from %s) ", jm.From)
}
if jm.Progress != nil && isTerminal {
fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl)
} else if jm.ProgressMessage != "" { //deprecated
fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl)
} else if jm.Stream != "" {
fmt.Fprintf(out, "%s%s", jm.Stream, endl)
} else {
fmt.Fprintf(out, "%s%s\n", jm.Status, endl)
}
return nil
}
// DisplayJSONMessagesStream displays a json message stream from `in` to `out`, `isTerminal`
// describes if `out` is a terminal. If this is the case, it will print `\n` at the end of
// each line and move the cursor while displaying.
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(*json.RawMessage)) error {
var (
dec = json.NewDecoder(in)
ids = make(map[string]int)
)
for {
diff := 0
var jm JSONMessage
if err := dec.Decode(&jm); err != nil {
if err == io.EOF {
break
}
return err
}
if jm.Aux != nil {
if auxCallback != nil {
auxCallback(jm.Aux)
}
continue
}
if jm.Progress != nil {
jm.Progress.terminalFd = terminalFd
}
if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") {
line, ok := ids[jm.ID]
if !ok {
// NOTE: This approach of using len(id) to
// figure out the number of lines of history
// only works as long as we clear the history
// when we output something that's not
// accounted for in the map, such as a line
// with no ID.
line = len(ids)
ids[jm.ID] = line
if isTerminal {
fmt.Fprintf(out, "\n")
}
} else {
diff = len(ids) - line
}
if isTerminal {
// NOTE: this appears to be necessary even if
// diff == 0.
// <ESC>[{diff}A = move cursor up diff rows
fmt.Fprintf(out, "%c[%dA", 27, diff)
}
} else {
// When outputting something that isn't progress
// output, clear the history of previous lines. We
// don't want progress entries from some previous
// operation to be updated (for example, pull -a
// with multiple tags).
ids = make(map[string]int)
}
err := jm.Display(out, isTerminal)
if jm.ID != "" && isTerminal {
// NOTE: this appears to be necessary even if
// diff == 0.
// <ESC>[{diff}B = move cursor down diff rows
fmt.Fprintf(out, "%c[%dB", 27, diff)
}
if err != nil {
return err
}
}
return nil
}

View file

@ -1,245 +0,0 @@
package jsonmessage
import (
"bytes"
"fmt"
"strings"
"testing"
"time"
"github.com/containers/storage/pkg/jsonlog"
"github.com/containers/storage/pkg/term"
)
func TestError(t *testing.T) {
je := JSONError{404, "Not found"}
if je.Error() != "Not found" {
t.Fatalf("Expected 'Not found' got '%s'", je.Error())
}
}
func TestProgress(t *testing.T) {
termsz, err := term.GetWinsize(0)
if err != nil {
// we can safely ignore the err here
termsz = nil
}
jp := JSONProgress{}
if jp.String() != "" {
t.Fatalf("Expected empty string, got '%s'", jp.String())
}
expected := " 1 B"
jp2 := JSONProgress{Current: 1}
if jp2.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp2.String())
}
expectedStart := "[==========> ] 20 B/100 B"
if termsz != nil && termsz.Width <= 110 {
expectedStart = " 20 B/100 B"
}
jp3 := JSONProgress{Current: 20, Total: 100, Start: time.Now().Unix()}
// Just look at the start of the string
// (the remaining time is really hard to test -_-)
if jp3.String()[:len(expectedStart)] != expectedStart {
t.Fatalf("Expected to start with %q, got %q", expectedStart, jp3.String())
}
expected = "[=========================> ] 50 B/100 B"
if termsz != nil && termsz.Width <= 110 {
expected = " 50 B/100 B"
}
jp4 := JSONProgress{Current: 50, Total: 100}
if jp4.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp4.String())
}
// this number can't be negative gh#7136
expected = "[==================================================>] 50 B"
if termsz != nil && termsz.Width <= 110 {
expected = " 50 B"
}
jp5 := JSONProgress{Current: 50, Total: 40}
if jp5.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp5.String())
}
}
func TestJSONMessageDisplay(t *testing.T) {
now := time.Now()
messages := map[JSONMessage][]string{
// Empty
JSONMessage{}: {"\n", "\n"},
// Status
JSONMessage{
Status: "status",
}: {
"status\n",
"status\n",
},
// General
JSONMessage{
Time: now.Unix(),
ID: "ID",
From: "From",
Status: "status",
}: {
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)),
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)),
},
// General, with nano precision time
JSONMessage{
TimeNano: now.UnixNano(),
ID: "ID",
From: "From",
Status: "status",
}: {
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
},
// General, with both times Nano is preferred
JSONMessage{
Time: now.Unix(),
TimeNano: now.UnixNano(),
ID: "ID",
From: "From",
Status: "status",
}: {
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
},
// Stream over status
JSONMessage{
Status: "status",
Stream: "stream",
}: {
"stream",
"stream",
},
// With progress message
JSONMessage{
Status: "status",
ProgressMessage: "progressMessage",
}: {
"status progressMessage",
"status progressMessage",
},
// With progress, stream empty
JSONMessage{
Status: "status",
Stream: "",
Progress: &JSONProgress{Current: 1},
}: {
"",
fmt.Sprintf("%c[2K\rstatus 1 B\r", 27),
},
}
// The tests :)
for jsonMessage, expectedMessages := range messages {
// Without terminal
data := bytes.NewBuffer([]byte{})
if err := jsonMessage.Display(data, false); err != nil {
t.Fatal(err)
}
if data.String() != expectedMessages[0] {
t.Fatalf("Expected [%v], got [%v]", expectedMessages[0], data.String())
}
// With terminal
data = bytes.NewBuffer([]byte{})
if err := jsonMessage.Display(data, true); err != nil {
t.Fatal(err)
}
if data.String() != expectedMessages[1] {
t.Fatalf("Expected [%v], got [%v]", expectedMessages[1], data.String())
}
}
}
// Test JSONMessage with an Error. It will return an error with the text as error, not the meaning of the HTTP code.
func TestJSONMessageDisplayWithJSONError(t *testing.T) {
data := bytes.NewBuffer([]byte{})
jsonMessage := JSONMessage{Error: &JSONError{404, "Can't find it"}}
err := jsonMessage.Display(data, true)
if err == nil || err.Error() != "Can't find it" {
t.Fatalf("Expected a JSONError 404, got [%v]", err)
}
jsonMessage = JSONMessage{Error: &JSONError{401, "Anything"}}
err = jsonMessage.Display(data, true)
if err == nil || err.Error() != "Authentication is required." {
t.Fatalf("Expected an error [Authentication is required.], got [%v]", err)
}
}
func TestDisplayJSONMessagesStreamInvalidJSON(t *testing.T) {
var (
inFd uintptr
)
data := bytes.NewBuffer([]byte{})
reader := strings.NewReader("This is not a 'valid' JSON []")
inFd, _ = term.GetFdInfo(reader)
if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err == nil && err.Error()[:17] != "invalid character" {
t.Fatalf("Should have thrown an error (invalid character in ..), got [%v]", err)
}
}
func TestDisplayJSONMessagesStream(t *testing.T) {
var (
inFd uintptr
)
messages := map[string][]string{
// empty string
"": {
"",
""},
// Without progress & ID
"{ \"status\": \"status\" }": {
"status\n",
"status\n",
},
// Without progress, with ID
"{ \"id\": \"ID\",\"status\": \"status\" }": {
"ID: status\n",
fmt.Sprintf("ID: status\n%c[%dB", 27, 0),
},
// With progress
"{ \"id\": \"ID\", \"status\": \"status\", \"progress\": \"ProgressMessage\" }": {
"ID: status ProgressMessage",
fmt.Sprintf("\n%c[%dAID: status ProgressMessage%c[%dB", 27, 0, 27, 0),
},
// With progressDetail
"{ \"id\": \"ID\", \"status\": \"status\", \"progressDetail\": { \"Current\": 1} }": {
"", // progressbar is disabled in non-terminal
fmt.Sprintf("\n%c[%dA%c[2K\rID: status 1 B\r%c[%dB", 27, 0, 27, 27, 0),
},
}
for jsonMessage, expectedMessages := range messages {
data := bytes.NewBuffer([]byte{})
reader := strings.NewReader(jsonMessage)
inFd, _ = term.GetFdInfo(reader)
// Without terminal
if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err != nil {
t.Fatal(err)
}
if data.String() != expectedMessages[0] {
t.Fatalf("Expected an [%v], got [%v]", expectedMessages[0], data.String())
}
// With terminal
data = bytes.NewBuffer([]byte{})
reader = strings.NewReader(jsonMessage)
if err := DisplayJSONMessagesStream(reader, data, inFd, true, nil); err != nil {
t.Fatal(err)
}
if data.String() != expectedMessages[1] {
t.Fatalf("Expected an [%v], got [%v]", expectedMessages[1], data.String())
}
}
}

View file

@ -1,77 +0,0 @@
// Package operatingsystem provides helper function to get the operating system
// name for different platforms.
package operatingsystem
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/mattn/go-shellwords"
)
var (
// file to use to detect if the daemon is running in a container
proc1Cgroup = "/proc/1/cgroup"
// file to check to determine Operating System
etcOsRelease = "/etc/os-release"
// used by stateless systems like Clear Linux
altOsRelease = "/usr/lib/os-release"
)
// GetOperatingSystem gets the name of the current operating system.
func GetOperatingSystem() (string, error) {
osReleaseFile, err := os.Open(etcOsRelease)
if err != nil {
if !os.IsNotExist(err) {
return "", fmt.Errorf("Error opening %s: %v", etcOsRelease, err)
}
osReleaseFile, err = os.Open(altOsRelease)
if err != nil {
return "", fmt.Errorf("Error opening %s: %v", altOsRelease, err)
}
}
defer osReleaseFile.Close()
var prettyName string
scanner := bufio.NewScanner(osReleaseFile)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "PRETTY_NAME=") {
data := strings.SplitN(line, "=", 2)
prettyNames, err := shellwords.Parse(data[1])
if err != nil {
return "", fmt.Errorf("PRETTY_NAME is invalid: %s", err.Error())
}
if len(prettyNames) != 1 {
return "", fmt.Errorf("PRETTY_NAME needs to be enclosed by quotes if they have spaces: %s", data[1])
}
prettyName = prettyNames[0]
}
}
if prettyName != "" {
return prettyName, nil
}
// If not set, defaults to PRETTY_NAME="Linux"
// c.f. http://www.freedesktop.org/software/systemd/man/os-release.html
return "Linux", nil
}
// IsContainerized returns true if we are running inside a container.
func IsContainerized() (bool, error) {
b, err := ioutil.ReadFile(proc1Cgroup)
if err != nil {
return false, err
}
for _, line := range bytes.Split(b, []byte{'\n'}) {
if len(line) > 0 && !bytes.HasSuffix(line, []byte{'/'}) && !bytes.HasSuffix(line, []byte("init.scope")) {
return true, nil
}
}
return false, nil
}

View file

@ -1,37 +0,0 @@
// +build solaris,cgo
package operatingsystem
/*
#include <zone.h>
*/
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
}

View file

@ -1,25 +0,0 @@
// +build freebsd darwin
package operatingsystem
import (
"errors"
"os/exec"
)
// GetOperatingSystem gets the name of the current operating system.
func GetOperatingSystem() (string, error) {
cmd := exec.Command("uname", "-s")
osName, err := cmd.Output()
if err != nil {
return "", err
}
return string(osName), nil
}
// IsContainerized returns true if we are running inside a container.
// No-op on FreeBSD and Darwin, always returns false.
func IsContainerized() (bool, error) {
// TODO: Implement jail detection for freeBSD
return false, errors.New("Cannot detect if we are in container")
}

View file

@ -1,247 +0,0 @@
// +build linux freebsd
package operatingsystem
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func TestGetOperatingSystem(t *testing.T) {
var backup = etcOsRelease
invalids := []struct {
content string
errorExpected string
}{
{
`PRETTY_NAME=Source Mage GNU/Linux
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME needs to be enclosed by quotes if they have spaces: Source Mage GNU/Linux",
},
{
`PRETTY_NAME="Ubuntu Linux
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME is invalid: invalid command line string",
},
{
`PRETTY_NAME=Ubuntu'
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME is invalid: invalid command line string",
},
{
`PRETTY_NAME'
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME needs to be enclosed by quotes if they have spaces: Ubuntu 14.04.LTS",
},
}
valids := []struct {
content string
expected string
}{
{
`NAME="Ubuntu"
PRETTY_NAME_AGAIN="Ubuntu 14.04.LTS"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`,
"Linux",
},
{
`NAME="Ubuntu"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`,
"Linux",
},
{
`NAME=Gentoo
ID=gentoo
PRETTY_NAME="Gentoo/Linux"
ANSI_COLOR="1;32"
HOME_URL="http://www.gentoo.org/"
SUPPORT_URL="http://www.gentoo.org/main/en/support.xml"
BUG_REPORT_URL="https://bugs.gentoo.org/"
`,
"Gentoo/Linux",
},
{
`NAME="Ubuntu"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`,
"Ubuntu 14.04 LTS",
},
{
`NAME="Ubuntu"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME='Ubuntu 14.04 LTS'`,
"Ubuntu 14.04 LTS",
},
{
`PRETTY_NAME=Source
NAME="Source Mage"`,
"Source",
},
{
`PRETTY_NAME=Source
PRETTY_NAME="Source Mage"`,
"Source Mage",
},
}
dir := os.TempDir()
etcOsRelease = filepath.Join(dir, "etcOsRelease")
defer func() {
os.Remove(etcOsRelease)
etcOsRelease = backup
}()
for _, elt := range invalids {
if err := ioutil.WriteFile(etcOsRelease, []byte(elt.content), 0600); err != nil {
t.Fatalf("failed to write to %s: %v", etcOsRelease, err)
}
s, err := GetOperatingSystem()
if err == nil || err.Error() != elt.errorExpected {
t.Fatalf("Expected an error %q, got %q (err: %v)", elt.errorExpected, s, err)
}
}
for _, elt := range valids {
if err := ioutil.WriteFile(etcOsRelease, []byte(elt.content), 0600); err != nil {
t.Fatalf("failed to write to %s: %v", etcOsRelease, err)
}
s, err := GetOperatingSystem()
if err != nil || s != elt.expected {
t.Fatalf("Expected %q, got %q (err: %v)", elt.expected, s, err)
}
}
}
func TestIsContainerized(t *testing.T) {
var (
backup = proc1Cgroup
nonContainerizedProc1Cgroupsystemd226 = []byte(`9:memory:/init.scope
8:net_cls,net_prio:/
7:cpuset:/
6:freezer:/
5:devices:/init.scope
4:blkio:/init.scope
3:cpu,cpuacct:/init.scope
2:perf_event:/
1:name=systemd:/init.scope
`)
nonContainerizedProc1Cgroup = []byte(`14:name=systemd:/
13:hugetlb:/
12:net_prio:/
11:perf_event:/
10:bfqio:/
9:blkio:/
8:net_cls:/
7:freezer:/
6:devices:/
5:memory:/
4:cpuacct:/
3:cpu:/
2:cpuset:/
`)
containerizedProc1Cgroup = []byte(`9:perf_event:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
8:blkio:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
7:net_cls:/
6:freezer:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
5:devices:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
4:memory:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
3:cpuacct:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
2:cpu:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
1:cpuset:/`)
)
dir := os.TempDir()
proc1Cgroup = filepath.Join(dir, "proc1Cgroup")
defer func() {
os.Remove(proc1Cgroup)
proc1Cgroup = backup
}()
if err := ioutil.WriteFile(proc1Cgroup, nonContainerizedProc1Cgroup, 0600); err != nil {
t.Fatalf("failed to write to %s: %v", proc1Cgroup, err)
}
inContainer, err := IsContainerized()
if err != nil {
t.Fatal(err)
}
if inContainer {
t.Fatal("Wrongly assuming containerized")
}
if err := ioutil.WriteFile(proc1Cgroup, nonContainerizedProc1Cgroupsystemd226, 0600); err != nil {
t.Fatalf("failed to write to %s: %v", proc1Cgroup, err)
}
inContainer, err = IsContainerized()
if err != nil {
t.Fatal(err)
}
if inContainer {
t.Fatal("Wrongly assuming containerized for systemd /init.scope cgroup layout")
}
if err := ioutil.WriteFile(proc1Cgroup, containerizedProc1Cgroup, 0600); err != nil {
t.Fatalf("failed to write to %s: %v", proc1Cgroup, err)
}
inContainer, err = IsContainerized()
if err != nil {
t.Fatal(err)
}
if !inContainer {
t.Fatal("Wrongly assuming non-containerized")
}
}
func TestOsReleaseFallback(t *testing.T) {
var backup = etcOsRelease
var altBackup = altOsRelease
dir := os.TempDir()
etcOsRelease = filepath.Join(dir, "etcOsRelease")
altOsRelease = filepath.Join(dir, "altOsRelease")
defer func() {
os.Remove(dir)
etcOsRelease = backup
altOsRelease = altBackup
}()
content := `NAME=Gentoo
ID=gentoo
PRETTY_NAME="Gentoo/Linux"
ANSI_COLOR="1;32"
HOME_URL="http://www.gentoo.org/"
SUPPORT_URL="http://www.gentoo.org/main/en/support.xml"
BUG_REPORT_URL="https://bugs.gentoo.org/"
`
if err := ioutil.WriteFile(altOsRelease, []byte(content), 0600); err != nil {
t.Fatalf("failed to write to %s: %v", etcOsRelease, err)
}
s, err := GetOperatingSystem()
if err != nil || s != "Gentoo/Linux" {
t.Fatalf("Expected %q, got %q (err: %v)", "Gentoo/Linux", s, err)
}
}

View file

@ -1,49 +0,0 @@
package operatingsystem
import (
"syscall"
"unsafe"
)
// See https://code.google.com/p/go/source/browse/src/pkg/mime/type_windows.go?r=d14520ac25bf6940785aabb71f5be453a286f58c
// for a similar sample
// GetOperatingSystem gets the name of the current operating system.
func GetOperatingSystem() (string, error) {
var h syscall.Handle
// Default return value
ret := "Unknown Operating System"
if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE,
syscall.StringToUTF16Ptr(`SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\`),
0,
syscall.KEY_READ,
&h); err != nil {
return ret, err
}
defer syscall.RegCloseKey(h)
var buf [1 << 10]uint16
var typ uint32
n := uint32(len(buf) * 2) // api expects array of bytes, not uint16
if err := syscall.RegQueryValueEx(h,
syscall.StringToUTF16Ptr("ProductName"),
nil,
&typ,
(*byte)(unsafe.Pointer(&buf[0])),
&n); err != nil {
return ret, err
}
ret = syscall.UTF16ToString(buf[:])
return ret, nil
}
// IsContainerized returns true if we are running inside a container.
// No-op on Windows, always returns false.
func IsContainerized() (bool, error) {
return false, nil
}

View file

@ -1,49 +0,0 @@
// Package pidfile provides structure and helper functions to create and remove
// PID file. A PID file is usually a file used to store the process ID of a
// running process.
package pidfile
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)
// PIDFile is a file used to store the process ID of a running process.
type PIDFile struct {
path string
}
func checkPIDFileAlreadyExists(path string) error {
if pidByte, err := ioutil.ReadFile(path); err == nil {
pidString := strings.TrimSpace(string(pidByte))
if pid, err := strconv.Atoi(pidString); err == nil {
if processExists(pid) {
return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path)
}
}
}
return nil
}
// New creates a PIDfile using the specified path.
func New(path string) (*PIDFile, error) {
if err := checkPIDFileAlreadyExists(path); err != nil {
return nil, err
}
if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
return nil, err
}
return &PIDFile{path: path}, nil
}
// Remove removes the PIDFile.
func (file PIDFile) Remove() error {
if err := os.Remove(file.path); err != nil {
return err
}
return nil
}

View file

@ -1,38 +0,0 @@
package pidfile
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func TestNewAndRemove(t *testing.T) {
dir, err := ioutil.TempDir(os.TempDir(), "test-pidfile")
if err != nil {
t.Fatal("Could not create test directory")
}
path := filepath.Join(dir, "testfile")
file, err := New(path)
if err != nil {
t.Fatal("Could not create test file", err)
}
_, err = New(path)
if err == nil {
t.Fatal("Test file creation not blocked")
}
if err := file.Remove(); err != nil {
t.Fatal("Could not delete created test file")
}
}
func TestRemoveInvalidPath(t *testing.T) {
file := PIDFile{path: filepath.Join("foo", "bar")}
if err := file.Remove(); err == nil {
t.Fatal("Non-existing file doesn't give an error on delete")
}
}

View file

@ -1,16 +0,0 @@
// +build !windows
package pidfile
import (
"os"
"path/filepath"
"strconv"
)
func processExists(pid int) bool {
if _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))); err == nil {
return true
}
return false
}

View file

@ -1,23 +0,0 @@
package pidfile
import "syscall"
const (
processQueryLimitedInformation = 0x1000
stillActive = 259
)
func processExists(pid int) bool {
h, err := syscall.OpenProcess(processQueryLimitedInformation, false, uint32(pid))
if err != nil {
return false
}
var c uint32
err = syscall.GetExitCodeProcess(h, &c)
syscall.Close(h)
if err != nil {
return c == stillActive
}
return true
}

View file

@ -1,12 +0,0 @@
// +build !linux,!windows
package sysinfo
import (
"runtime"
)
// NumCPU returns the number of CPUs
func NumCPU() int {
return runtime.NumCPU()
}

View file

@ -1,43 +0,0 @@
// +build linux
package sysinfo
import (
"runtime"
"syscall"
"unsafe"
)
// numCPU queries the system for the count of threads available
// for use to this process.
//
// Issues two syscalls.
// Returns 0 on errors. Use |runtime.NumCPU| in that case.
func numCPU() int {
// Gets the affinity mask for a process: The very one invoking this function.
pid, _, _ := syscall.RawSyscall(syscall.SYS_GETPID, 0, 0, 0)
var mask [1024 / 64]uintptr
_, _, err := syscall.RawSyscall(syscall.SYS_SCHED_GETAFFINITY, pid, uintptr(len(mask)*8), uintptr(unsafe.Pointer(&mask[0])))
if err != 0 {
return 0
}
// For every available thread a bit is set in the mask.
ncpu := 0
for _, e := range mask {
if e == 0 {
continue
}
ncpu += int(popcnt(uint64(e)))
}
return ncpu
}
// NumCPU returns the number of CPUs which are currently online
func NumCPU() int {
if ncpu := numCPU(); ncpu > 0 {
return ncpu
}
return runtime.NumCPU()
}

View file

@ -1,36 +0,0 @@
// +build windows
package sysinfo
import (
"runtime"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
getCurrentProcess = kernel32.NewProc("GetCurrentProcess")
getProcessAffinityMask = kernel32.NewProc("GetProcessAffinityMask")
)
func numCPU() int {
// Gets the affinity mask for a process
var mask, sysmask uintptr
currentProcess, _, _ := getCurrentProcess.Call()
ret, _, _ := getProcessAffinityMask.Call(currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
if ret == 0 {
return 0
}
// For every available thread a bit is set in the mask.
ncpu := int(popcnt(uint64(mask)))
return ncpu
}
// NumCPU returns the number of CPUs which are currently online
func NumCPU() int {
if ncpu := numCPU(); ncpu > 0 {
return ncpu
}
return runtime.NumCPU()
}

View file

@ -1,138 +0,0 @@
package sysinfo
import "github.com/containers/storage/pkg/parsers"
// SysInfo stores information about which features a kernel supports.
// TODO Windows: Factor out platform specific capabilities.
type SysInfo struct {
// Whether the kernel supports AppArmor or not
AppArmor bool
// Whether the kernel supports Seccomp or not
Seccomp bool
cgroupMemInfo
cgroupCPUInfo
cgroupBlkioInfo
cgroupCpusetInfo
cgroupPids
// Whether IPv4 forwarding is supported or not, if this was disabled, networking will not work
IPv4ForwardingDisabled bool
// Whether bridge-nf-call-iptables is supported or not
BridgeNFCallIPTablesDisabled bool
// Whether bridge-nf-call-ip6tables is supported or not
BridgeNFCallIP6TablesDisabled bool
// Whether the cgroup has the mountpoint of "devices" or not
CgroupDevicesEnabled bool
}
type cgroupMemInfo struct {
// Whether memory limit is supported or not
MemoryLimit bool
// Whether swap limit is supported or not
SwapLimit bool
// Whether soft limit is supported or not
MemoryReservation bool
// Whether OOM killer disable is supported or not
OomKillDisable bool
// Whether memory swappiness is supported or not
MemorySwappiness bool
// Whether kernel memory limit is supported or not
KernelMemory bool
}
type cgroupCPUInfo struct {
// Whether CPU shares is supported or not
CPUShares bool
// Whether CPU CFS(Completely Fair Scheduler) period is supported or not
CPUCfsPeriod bool
// Whether CPU CFS(Completely Fair Scheduler) quota is supported or not
CPUCfsQuota bool
}
type cgroupBlkioInfo struct {
// Whether Block IO weight is supported or not
BlkioWeight bool
// Whether Block IO weight_device is supported or not
BlkioWeightDevice bool
// Whether Block IO read limit in bytes per second is supported or not
BlkioReadBpsDevice bool
// Whether Block IO write limit in bytes per second is supported or not
BlkioWriteBpsDevice bool
// Whether Block IO read limit in IO per second is supported or not
BlkioReadIOpsDevice bool
// Whether Block IO write limit in IO per second is supported or not
BlkioWriteIOpsDevice bool
}
type cgroupCpusetInfo struct {
// Whether Cpuset is supported or not
Cpuset bool
// Available Cpuset's cpus
Cpus string
// Available Cpuset's memory nodes
Mems string
}
type cgroupPids struct {
// Whether Pids Limit is supported or not
PidsLimit bool
}
// IsCpusetCpusAvailable returns `true` if the provided string set is contained
// in cgroup's cpuset.cpus set, `false` otherwise.
// If error is not nil a parsing error occurred.
func (c cgroupCpusetInfo) IsCpusetCpusAvailable(provided string) (bool, error) {
return isCpusetListAvailable(provided, c.Cpus)
}
// IsCpusetMemsAvailable returns `true` if the provided string set is contained
// in cgroup's cpuset.mems set, `false` otherwise.
// If error is not nil a parsing error occurred.
func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) {
return isCpusetListAvailable(provided, c.Mems)
}
func isCpusetListAvailable(provided, available string) (bool, error) {
parsedProvided, err := parsers.ParseUintList(provided)
if err != nil {
return false, err
}
parsedAvailable, err := parsers.ParseUintList(available)
if err != nil {
return false, err
}
for k := range parsedProvided {
if !parsedAvailable[k] {
return false, nil
}
}
return true, nil
}
// Returns bit count of 1, used by NumCPU
func popcnt(x uint64) (n byte) {
x -= (x >> 1) & 0x5555555555555555
x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
x += x >> 4
x &= 0x0f0f0f0f0f0f0f0f
x *= 0x0101010101010101
return byte(x >> 56)
}

View file

@ -1,7 +0,0 @@
package sysinfo
// New returns an empty SysInfo for freebsd for now.
func New(quiet bool) *SysInfo {
sysInfo := &SysInfo{}
return sysInfo
}

View file

@ -1,246 +0,0 @@
package sysinfo
import (
"fmt"
"io/ioutil"
"os"
"path"
"strings"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer/cgroups"
)
const (
// SeccompModeFilter refers to the syscall argument SECCOMP_MODE_FILTER.
SeccompModeFilter = uintptr(2)
)
func findCgroupMountpoints() (map[string]string, error) {
cgMounts, err := cgroups.GetCgroupMounts()
if err != nil {
return nil, fmt.Errorf("Failed to parse cgroup information: %v", err)
}
mps := make(map[string]string)
for _, m := range cgMounts {
for _, ss := range m.Subsystems {
mps[ss] = m.Mountpoint
}
}
return mps, nil
}
// New returns a new SysInfo, using the filesystem to detect which features
// the kernel supports. If `quiet` is `false` warnings are printed in logs
// whenever an error occurs or misconfigurations are present.
func New(quiet bool) *SysInfo {
sysInfo := &SysInfo{}
cgMounts, err := findCgroupMountpoints()
if err != nil {
logrus.Warnf("Failed to parse cgroup information: %v", err)
} else {
sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet)
sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet)
sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet)
sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet)
sysInfo.cgroupPids = checkCgroupPids(quiet)
}
_, ok := cgMounts["devices"]
sysInfo.CgroupDevicesEnabled = ok
sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
// Check if AppArmor is supported.
if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
sysInfo.AppArmor = true
}
// Check if Seccomp is supported, via CONFIG_SECCOMP.
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL {
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL {
sysInfo.Seccomp = true
}
}
return sysInfo
}
// checkCgroupMem reads the memory information from the memory cgroup mount point.
func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
mountPoint, ok := cgMounts["memory"]
if !ok {
if !quiet {
logrus.Warn("Your kernel does not support cgroup memory limit")
}
return cgroupMemInfo{}
}
swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
if !quiet && !swapLimit {
logrus.Warn("Your kernel does not support swap memory limit.")
}
memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
if !quiet && !memoryReservation {
logrus.Warn("Your kernel does not support memory reservation.")
}
oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
if !quiet && !oomKillDisable {
logrus.Warn("Your kernel does not support oom control.")
}
memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
if !quiet && !memorySwappiness {
logrus.Warn("Your kernel does not support memory swappiness.")
}
kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
if !quiet && !kernelMemory {
logrus.Warn("Your kernel does not support kernel memory limit.")
}
return cgroupMemInfo{
MemoryLimit: true,
SwapLimit: swapLimit,
MemoryReservation: memoryReservation,
OomKillDisable: oomKillDisable,
MemorySwappiness: memorySwappiness,
KernelMemory: kernelMemory,
}
}
// checkCgroupCPU reads the cpu information from the cpu cgroup mount point.
func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
mountPoint, ok := cgMounts["cpu"]
if !ok {
if !quiet {
logrus.Warn("Unable to find cpu cgroup in mounts")
}
return cgroupCPUInfo{}
}
cpuShares := cgroupEnabled(mountPoint, "cpu.shares")
if !quiet && !cpuShares {
logrus.Warn("Your kernel does not support cgroup cpu shares")
}
cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us")
if !quiet && !cpuCfsPeriod {
logrus.Warn("Your kernel does not support cgroup cfs period")
}
cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
if !quiet && !cpuCfsQuota {
logrus.Warn("Your kernel does not support cgroup cfs quotas")
}
return cgroupCPUInfo{
CPUShares: cpuShares,
CPUCfsPeriod: cpuCfsPeriod,
CPUCfsQuota: cpuCfsQuota,
}
}
// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
mountPoint, ok := cgMounts["blkio"]
if !ok {
if !quiet {
logrus.Warn("Unable to find blkio cgroup in mounts")
}
return cgroupBlkioInfo{}
}
weight := cgroupEnabled(mountPoint, "blkio.weight")
if !quiet && !weight {
logrus.Warn("Your kernel does not support cgroup blkio weight")
}
weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
if !quiet && !weightDevice {
logrus.Warn("Your kernel does not support cgroup blkio weight_device")
}
readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
if !quiet && !readBpsDevice {
logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
}
writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
if !quiet && !writeBpsDevice {
logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
}
readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
if !quiet && !readIOpsDevice {
logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
}
writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
if !quiet && !writeIOpsDevice {
logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
}
return cgroupBlkioInfo{
BlkioWeight: weight,
BlkioWeightDevice: weightDevice,
BlkioReadBpsDevice: readBpsDevice,
BlkioWriteBpsDevice: writeBpsDevice,
BlkioReadIOpsDevice: readIOpsDevice,
BlkioWriteIOpsDevice: writeIOpsDevice,
}
}
// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
mountPoint, ok := cgMounts["cpuset"]
if !ok {
if !quiet {
logrus.Warn("Unable to find cpuset cgroup in mounts")
}
return cgroupCpusetInfo{}
}
cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
if err != nil {
return cgroupCpusetInfo{}
}
mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
if err != nil {
return cgroupCpusetInfo{}
}
return cgroupCpusetInfo{
Cpuset: true,
Cpus: strings.TrimSpace(string(cpus)),
Mems: strings.TrimSpace(string(mems)),
}
}
// checkCgroupPids reads the pids information from the pids cgroup mount point.
func checkCgroupPids(quiet bool) cgroupPids {
_, err := cgroups.FindCgroupMountpoint("pids")
if err != nil {
if !quiet {
logrus.Warn(err)
}
return cgroupPids{}
}
return cgroupPids{
PidsLimit: true,
}
}
func cgroupEnabled(mountPoint, name string) bool {
_, err := os.Stat(path.Join(mountPoint, name))
return err == nil
}
func readProcBool(path string) bool {
val, err := ioutil.ReadFile(path)
if err != nil {
return false
}
return strings.TrimSpace(string(val)) == "1"
}

View file

@ -1,58 +0,0 @@
package sysinfo
import (
"io/ioutil"
"os"
"path"
"path/filepath"
"testing"
)
func TestReadProcBool(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "test-sysinfo-proc")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
procFile := filepath.Join(tmpDir, "read-proc-bool")
if err := ioutil.WriteFile(procFile, []byte("1"), 644); err != nil {
t.Fatal(err)
}
if !readProcBool(procFile) {
t.Fatal("expected proc bool to be true, got false")
}
if err := ioutil.WriteFile(procFile, []byte("0"), 644); err != nil {
t.Fatal(err)
}
if readProcBool(procFile) {
t.Fatal("expected proc bool to be false, got false")
}
if readProcBool(path.Join(tmpDir, "no-exist")) {
t.Fatal("should be false for non-existent entry")
}
}
func TestCgroupEnabled(t *testing.T) {
cgroupDir, err := ioutil.TempDir("", "cgroup-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(cgroupDir)
if cgroupEnabled(cgroupDir, "test") {
t.Fatal("cgroupEnabled should be false")
}
if err := ioutil.WriteFile(path.Join(cgroupDir, "test"), []byte{}, 644); err != nil {
t.Fatal(err)
}
if !cgroupEnabled(cgroupDir, "test") {
t.Fatal("cgroupEnabled should be true")
}
}

View file

@ -1,119 +0,0 @@
// +build solaris,cgo
package sysinfo
import (
"bytes"
"os/exec"
"strconv"
"strings"
)
/*
#cgo LDFLAGS: -llgrp
#include <unistd.h>
#include <stdlib.h>
#include <sys/lgrp_user.h>
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)
}

View file

@ -1,26 +0,0 @@
package sysinfo
import "testing"
func TestIsCpusetListAvailable(t *testing.T) {
cases := []struct {
provided string
available string
res bool
err bool
}{
{"1", "0-4", true, false},
{"01,3", "0-4", true, false},
{"", "0-7", true, false},
{"1--42", "0-7", false, true},
{"1-42", "00-1,8,,9", false, true},
{"1,41-42", "43,45", false, false},
{"0-3", "", false, false},
}
for _, c := range cases {
r, err := isCpusetListAvailable(c.provided, c.available)
if (c.err && err == nil) && r != c.res {
t.Fatalf("Expected pair: %v, %v for %s, %s. Got %v, %v instead", c.res, c.err, c.provided, c.available, (c.err && err == nil), r)
}
}
}

View file

@ -1,7 +0,0 @@
package sysinfo
// New returns an empty SysInfo for windows for now.
func New(quiet bool) *SysInfo {
sysInfo := &SysInfo{}
return sysInfo
}