diff --git a/jsonmessage/jsonmessage.go b/jsonmessage/jsonmessage.go deleted file mode 100644 index 0287dd0..0000000 --- a/jsonmessage/jsonmessage.go +++ /dev/null @@ -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 { - // [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. - // [{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. - // [{diff}B = move cursor down diff rows - fmt.Fprintf(out, "%c[%dB", 27, diff) - } - if err != nil { - return err - } - } - return nil -} diff --git a/jsonmessage/jsonmessage_test.go b/jsonmessage/jsonmessage_test.go deleted file mode 100644 index 1b9c50a..0000000 --- a/jsonmessage/jsonmessage_test.go +++ /dev/null @@ -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()) - } - } - -} diff --git a/parsers/operatingsystem/operatingsystem_linux.go b/parsers/operatingsystem/operatingsystem_linux.go deleted file mode 100644 index e04a349..0000000 --- a/parsers/operatingsystem/operatingsystem_linux.go +++ /dev/null @@ -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 -} diff --git a/parsers/operatingsystem/operatingsystem_solaris.go b/parsers/operatingsystem/operatingsystem_solaris.go deleted file mode 100644 index d08ad14..0000000 --- a/parsers/operatingsystem/operatingsystem_solaris.go +++ /dev/null @@ -1,37 +0,0 @@ -// +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/parsers/operatingsystem/operatingsystem_unix.go b/parsers/operatingsystem/operatingsystem_unix.go deleted file mode 100644 index bc91c3c..0000000 --- a/parsers/operatingsystem/operatingsystem_unix.go +++ /dev/null @@ -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") -} diff --git a/parsers/operatingsystem/operatingsystem_unix_test.go b/parsers/operatingsystem/operatingsystem_unix_test.go deleted file mode 100644 index e7120c6..0000000 --- a/parsers/operatingsystem/operatingsystem_unix_test.go +++ /dev/null @@ -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) - } -} diff --git a/parsers/operatingsystem/operatingsystem_windows.go b/parsers/operatingsystem/operatingsystem_windows.go deleted file mode 100644 index 3c86b6a..0000000 --- a/parsers/operatingsystem/operatingsystem_windows.go +++ /dev/null @@ -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 -} diff --git a/pidfile/pidfile.go b/pidfile/pidfile.go deleted file mode 100644 index e1ac6be..0000000 --- a/pidfile/pidfile.go +++ /dev/null @@ -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 -} diff --git a/pidfile/pidfile_test.go b/pidfile/pidfile_test.go deleted file mode 100644 index 73e8af7..0000000 --- a/pidfile/pidfile_test.go +++ /dev/null @@ -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") - } -} diff --git a/pidfile/pidfile_unix.go b/pidfile/pidfile_unix.go deleted file mode 100644 index 28f3dec..0000000 --- a/pidfile/pidfile_unix.go +++ /dev/null @@ -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 -} diff --git a/pidfile/pidfile_windows.go b/pidfile/pidfile_windows.go deleted file mode 100644 index ae489c6..0000000 --- a/pidfile/pidfile_windows.go +++ /dev/null @@ -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 -} diff --git a/sysinfo/numcpu.go b/sysinfo/numcpu.go deleted file mode 100644 index aeb1a3a..0000000 --- a/sysinfo/numcpu.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !linux,!windows - -package sysinfo - -import ( - "runtime" -) - -// NumCPU returns the number of CPUs -func NumCPU() int { - return runtime.NumCPU() -} diff --git a/sysinfo/numcpu_linux.go b/sysinfo/numcpu_linux.go deleted file mode 100644 index 5eacd35..0000000 --- a/sysinfo/numcpu_linux.go +++ /dev/null @@ -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() -} diff --git a/sysinfo/numcpu_windows.go b/sysinfo/numcpu_windows.go deleted file mode 100644 index 5077af7..0000000 --- a/sysinfo/numcpu_windows.go +++ /dev/null @@ -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() -} diff --git a/sysinfo/sysinfo.go b/sysinfo/sysinfo.go deleted file mode 100644 index dc6f9ea..0000000 --- a/sysinfo/sysinfo.go +++ /dev/null @@ -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) -} diff --git a/sysinfo/sysinfo_freebsd.go b/sysinfo/sysinfo_freebsd.go deleted file mode 100644 index 22ae0d9..0000000 --- a/sysinfo/sysinfo_freebsd.go +++ /dev/null @@ -1,7 +0,0 @@ -package sysinfo - -// New returns an empty SysInfo for freebsd for now. -func New(quiet bool) *SysInfo { - sysInfo := &SysInfo{} - return sysInfo -} diff --git a/sysinfo/sysinfo_linux.go b/sysinfo/sysinfo_linux.go deleted file mode 100644 index 8ba3ce4..0000000 --- a/sysinfo/sysinfo_linux.go +++ /dev/null @@ -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" -} diff --git a/sysinfo/sysinfo_linux_test.go b/sysinfo/sysinfo_linux_test.go deleted file mode 100644 index fae0fdf..0000000 --- a/sysinfo/sysinfo_linux_test.go +++ /dev/null @@ -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") - } -} diff --git a/sysinfo/sysinfo_solaris.go b/sysinfo/sysinfo_solaris.go deleted file mode 100644 index 75a9c9b..0000000 --- a/sysinfo/sysinfo_solaris.go +++ /dev/null @@ -1,119 +0,0 @@ -// +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/sysinfo/sysinfo_test.go b/sysinfo/sysinfo_test.go deleted file mode 100644 index b61fbcf..0000000 --- a/sysinfo/sysinfo_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/sysinfo/sysinfo_windows.go b/sysinfo/sysinfo_windows.go deleted file mode 100644 index 8889318..0000000 --- a/sysinfo/sysinfo_windows.go +++ /dev/null @@ -1,7 +0,0 @@ -package sysinfo - -// New returns an empty SysInfo for windows for now. -func New(quiet bool) *SysInfo { - sysInfo := &SysInfo{} - return sysInfo -}