From a2824bb7a337861708a8b098fa5933b23e38ec2f Mon Sep 17 00:00:00 2001 From: Yu-Ju Hong Date: Tue, 16 Aug 2016 16:34:14 -0700 Subject: [PATCH] Fix building pkg/util/procfs on non-linux platforms --- pkg/util/procfs/procfs.go | 133 +-------------- pkg/util/procfs/procfs_linux.go | 151 ++++++++++++++++++ .../{procfs_test.go => procfs_linux_test.go} | 2 + ...cfs_interface.go => procfs_unsupported.go} | 14 +- 4 files changed, 166 insertions(+), 134 deletions(-) create mode 100644 pkg/util/procfs/procfs_linux.go rename pkg/util/procfs/{procfs_test.go => procfs_linux_test.go} (99%) rename pkg/util/procfs/{procfs_interface.go => procfs_unsupported.go} (64%) diff --git a/pkg/util/procfs/procfs.go b/pkg/util/procfs/procfs.go index b60f53933d8..f75a839983e 100644 --- a/pkg/util/procfs/procfs.go +++ b/pkg/util/procfs/procfs.go @@ -16,134 +16,7 @@ limitations under the License. package procfs -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "regexp" - "strconv" - "strings" - "syscall" - "unicode" - - "github.com/golang/glog" - utilerrors "k8s.io/kubernetes/pkg/util/errors" -) - -type ProcFS struct{} - -func NewProcFS() ProcFSInterface { - return &ProcFS{} -} - -func containerNameFromProcCgroup(content string) (string, error) { - lines := strings.Split(content, "\n") - for _, line := range lines { - entries := strings.SplitN(line, ":", 3) - if len(entries) == 3 && entries[1] == "devices" { - return strings.TrimSpace(entries[2]), nil - } - } - return "", fmt.Errorf("could not find devices cgroup location") -} - -// getFullContainerName gets the container name given the root process id of the container. -// Eg. If the devices cgroup for the container is stored in /sys/fs/cgroup/devices/docker/nginx, -// return docker/nginx. Assumes that the process is part of exactly one cgroup hierarchy. -func (pfs *ProcFS) GetFullContainerName(pid int) (string, error) { - filePath := path.Join("/proc", strconv.Itoa(pid), "cgroup") - content, err := ioutil.ReadFile(filePath) - if err != nil { - if os.IsNotExist(err) { - return "", os.ErrNotExist - } - return "", err - } - return containerNameFromProcCgroup(string(content)) -} - -// Find process(es) using a regular expression and send a specified -// signal to each process -func PKill(name string, sig syscall.Signal) error { - if len(name) == 0 { - return fmt.Errorf("name should not be empty") - } - re, err := regexp.Compile(name) - if err != nil { - return err - } - pids := getPids(re) - if len(pids) == 0 { - return fmt.Errorf("unable to fetch pids for process name : %q", name) - } - errList := []error{} - for _, pid := range pids { - if err = syscall.Kill(pid, sig); err != nil { - errList = append(errList, err) - } - } - return utilerrors.NewAggregate(errList) -} - -// Find process(es) with a specified name (exact match) -// and return their pid(s) -func PidOf(name string) ([]int, error) { - if len(name) == 0 { - return []int{}, fmt.Errorf("name should not be empty") - } - re, err := regexp.Compile("(^|/)" + name + "$") - if err != nil { - return []int{}, err - } - return getPids(re), nil -} - -func getPids(re *regexp.Regexp) []int { - pids := []int{} - filepath.Walk("/proc", func(path string, info os.FileInfo, err error) error { - if err != nil { - // We should continue processing other directories/files - return nil - } - base := filepath.Base(path) - // Traverse only the directories we are interested in - if info.IsDir() && path != "/proc" { - // If the directory is not a number (i.e. not a PID), skip it - if _, err := strconv.Atoi(base); err != nil { - return filepath.SkipDir - } - } - if base != "cmdline" { - return nil - } - cmdline, err := ioutil.ReadFile(path) - if err != nil { - glog.V(4).Infof("Error reading file %s: %+v", path, err) - return nil - } - // The bytes we read have '\0' as a separator for the command line - parts := bytes.SplitN(cmdline, []byte{0}, 2) - if len(parts) == 0 { - return nil - } - // Split the command line itself we are interested in just the first part - exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool { - return unicode.IsSpace(c) || c == ':' - }) - if len(exe) == 0 { - return nil - } - // Check if the name of the executable is what we are looking for - if re.MatchString(exe[0]) { - dirname := filepath.Base(filepath.Dir(path)) - // Grab the PID from the directory path - pid, _ := strconv.Atoi(dirname) - pids = append(pids, pid) - } - return nil - }) - return pids +type ProcFSInterface interface { + // GetFullContainerName gets the container name given the root process id of the container. + GetFullContainerName(pid int) (string, error) } diff --git a/pkg/util/procfs/procfs_linux.go b/pkg/util/procfs/procfs_linux.go new file mode 100644 index 00000000000..5b67dcd36cd --- /dev/null +++ b/pkg/util/procfs/procfs_linux.go @@ -0,0 +1,151 @@ +// +build linux + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package procfs + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "regexp" + "strconv" + "strings" + "syscall" + "unicode" + + "github.com/golang/glog" + utilerrors "k8s.io/kubernetes/pkg/util/errors" +) + +type ProcFS struct{} + +func NewProcFS() ProcFSInterface { + return &ProcFS{} +} + +func containerNameFromProcCgroup(content string) (string, error) { + lines := strings.Split(content, "\n") + for _, line := range lines { + entries := strings.SplitN(line, ":", 3) + if len(entries) == 3 && entries[1] == "devices" { + return strings.TrimSpace(entries[2]), nil + } + } + return "", fmt.Errorf("could not find devices cgroup location") +} + +// getFullContainerName gets the container name given the root process id of the container. +// Eg. If the devices cgroup for the container is stored in /sys/fs/cgroup/devices/docker/nginx, +// return docker/nginx. Assumes that the process is part of exactly one cgroup hierarchy. +func (pfs *ProcFS) GetFullContainerName(pid int) (string, error) { + filePath := path.Join("/proc", strconv.Itoa(pid), "cgroup") + content, err := ioutil.ReadFile(filePath) + if err != nil { + if os.IsNotExist(err) { + return "", os.ErrNotExist + } + return "", err + } + return containerNameFromProcCgroup(string(content)) +} + +// Find process(es) using a regular expression and send a specified +// signal to each process +func PKill(name string, sig syscall.Signal) error { + if len(name) == 0 { + return fmt.Errorf("name should not be empty") + } + re, err := regexp.Compile(name) + if err != nil { + return err + } + pids := getPids(re) + if len(pids) == 0 { + return fmt.Errorf("unable to fetch pids for process name : %q", name) + } + errList := []error{} + for _, pid := range pids { + if err = syscall.Kill(pid, sig); err != nil { + errList = append(errList, err) + } + } + return utilerrors.NewAggregate(errList) +} + +// Find process(es) with a specified name (exact match) +// and return their pid(s) +func PidOf(name string) ([]int, error) { + if len(name) == 0 { + return []int{}, fmt.Errorf("name should not be empty") + } + re, err := regexp.Compile("(^|/)" + name + "$") + if err != nil { + return []int{}, err + } + return getPids(re), nil +} + +func getPids(re *regexp.Regexp) []int { + pids := []int{} + filepath.Walk("/proc", func(path string, info os.FileInfo, err error) error { + if err != nil { + // We should continue processing other directories/files + return nil + } + base := filepath.Base(path) + // Traverse only the directories we are interested in + if info.IsDir() && path != "/proc" { + // If the directory is not a number (i.e. not a PID), skip it + if _, err := strconv.Atoi(base); err != nil { + return filepath.SkipDir + } + } + if base != "cmdline" { + return nil + } + cmdline, err := ioutil.ReadFile(path) + if err != nil { + glog.V(4).Infof("Error reading file %s: %+v", path, err) + return nil + } + // The bytes we read have '\0' as a separator for the command line + parts := bytes.SplitN(cmdline, []byte{0}, 2) + if len(parts) == 0 { + return nil + } + // Split the command line itself we are interested in just the first part + exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool { + return unicode.IsSpace(c) || c == ':' + }) + if len(exe) == 0 { + return nil + } + // Check if the name of the executable is what we are looking for + if re.MatchString(exe[0]) { + dirname := filepath.Base(filepath.Dir(path)) + // Grab the PID from the directory path + pid, _ := strconv.Atoi(dirname) + pids = append(pids, pid) + } + return nil + }) + return pids +} diff --git a/pkg/util/procfs/procfs_test.go b/pkg/util/procfs/procfs_linux_test.go similarity index 99% rename from pkg/util/procfs/procfs_test.go rename to pkg/util/procfs/procfs_linux_test.go index 380b23e4143..c268ec6ae06 100644 --- a/pkg/util/procfs/procfs_test.go +++ b/pkg/util/procfs/procfs_linux_test.go @@ -1,3 +1,5 @@ +// +build linux + /* Copyright 2015 The Kubernetes Authors. diff --git a/pkg/util/procfs/procfs_interface.go b/pkg/util/procfs/procfs_unsupported.go similarity index 64% rename from pkg/util/procfs/procfs_interface.go rename to pkg/util/procfs/procfs_unsupported.go index f75a839983e..4857fd81357 100644 --- a/pkg/util/procfs/procfs_interface.go +++ b/pkg/util/procfs/procfs_unsupported.go @@ -1,5 +1,7 @@ +// +build !linux + /* -Copyright 2015 The Kubernetes Authors. +Copyright 2016 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,7 +18,11 @@ limitations under the License. package procfs -type ProcFSInterface interface { - // GetFullContainerName gets the container name given the root process id of the container. - GetFullContainerName(pid int) (string, error) +import ( + "fmt" +) + +// GetFullContainerName gets the container name given the root process id of the container. +func GetFullContainerName(pid int) (string, error) { + return "", fmt.Errorf("GetFullContainerName is unsupported in this build") }