Commit cb2252b5 authored by k8s-merge-robot's avatar k8s-merge-robot

Merge pull request #13296 from kubernetes/revert-13248-revert-13191-cadvisor-update

Auto commit by PR queue bot
parents 66a644b2 24a5f7b9
...@@ -265,93 +265,93 @@ ...@@ -265,93 +265,93 @@
}, },
{ {
"ImportPath": "github.com/google/cadvisor/api", "ImportPath": "github.com/google/cadvisor/api",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/cache/memory", "ImportPath": "github.com/google/cadvisor/cache/memory",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/collector", "ImportPath": "github.com/google/cadvisor/collector",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/container", "ImportPath": "github.com/google/cadvisor/container",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/events", "ImportPath": "github.com/google/cadvisor/events",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/fs", "ImportPath": "github.com/google/cadvisor/fs",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/healthz", "ImportPath": "github.com/google/cadvisor/healthz",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/http", "ImportPath": "github.com/google/cadvisor/http",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/info/v1", "ImportPath": "github.com/google/cadvisor/info/v1",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/info/v2", "ImportPath": "github.com/google/cadvisor/info/v2",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/manager", "ImportPath": "github.com/google/cadvisor/manager",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/metrics", "ImportPath": "github.com/google/cadvisor/metrics",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/pages", "ImportPath": "github.com/google/cadvisor/pages",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/storage", "ImportPath": "github.com/google/cadvisor/storage",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/summary", "ImportPath": "github.com/google/cadvisor/summary",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/utils", "ImportPath": "github.com/google/cadvisor/utils",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/validate", "ImportPath": "github.com/google/cadvisor/validate",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/cadvisor/version", "ImportPath": "github.com/google/cadvisor/version",
"Comment": "0.16.0-81-g27fb6d5", "Comment": "0.16.0.1",
"Rev": "27fb6d593c6bffe274718119659815771e79e198" "Rev": "f99e491a989bd3b1b9565c55c556138d7e3c2ac5"
}, },
{ {
"ImportPath": "github.com/google/gofuzz", "ImportPath": "github.com/google/gofuzz",
...@@ -550,6 +550,10 @@ ...@@ -550,6 +550,10 @@
"Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1" "Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"
}, },
{ {
"ImportPath": "github.com/vishvananda/netns",
"Rev": "604eaf189ee867d8c147fafc28def2394e878d25"
},
{
"ImportPath": "github.com/xyproto/simpleredis", "ImportPath": "github.com/xyproto/simpleredis",
"Comment": "v1.0-13-g5292687", "Comment": "v1.0-13-g5292687",
"Rev": "5292687f5379e01054407da44d7c4590a61fd3de" "Rev": "5292687f5379e01054407da44d7c4590a61fd3de"
......
...@@ -71,6 +71,9 @@ type dockerContainerHandler struct { ...@@ -71,6 +71,9 @@ type dockerContainerHandler struct {
// Metadata labels associated with the container. // Metadata labels associated with the container.
labels map[string]string labels map[string]string
// The container PID used to switch namespaces as required
pid int
} }
func newDockerContainerHandler( func newDockerContainerHandler(
...@@ -114,6 +117,7 @@ func newDockerContainerHandler( ...@@ -114,6 +117,7 @@ func newDockerContainerHandler(
return nil, fmt.Errorf("failed to inspect container %q: %v", id, err) return nil, fmt.Errorf("failed to inspect container %q: %v", id, err)
} }
handler.creationTime = ctnr.Created handler.creationTime = ctnr.Created
handler.pid = ctnr.State.Pid
// Add the name and bare ID as aliases of the container. // Add the name and bare ID as aliases of the container.
handler.aliases = append(handler.aliases, strings.TrimPrefix(ctnr.Name, "/")) handler.aliases = append(handler.aliases, strings.TrimPrefix(ctnr.Name, "/"))
...@@ -176,12 +180,21 @@ func libcontainerConfigToContainerSpec(config *libcontainerConfigs.Config, mi *i ...@@ -176,12 +180,21 @@ func libcontainerConfigToContainerSpec(config *libcontainerConfigs.Config, mi *i
} }
} }
spec.HasNetwork = networkCount > 0 spec.HasNetwork = networkCount > 0 || hasNetNs(config.Namespaces)
spec.HasDiskIo = true spec.HasDiskIo = true
return spec return spec
} }
func hasNetNs(namespaces libcontainerConfigs.Namespaces) bool {
for _, ns := range namespaces {
if ns.Type == libcontainerConfigs.NEWNET {
return true
}
}
return false
}
func (self *dockerContainerHandler) GetSpec() (info.ContainerSpec, error) { func (self *dockerContainerHandler) GetSpec() (info.ContainerSpec, error) {
mi, err := self.machineInfoFactory.GetMachineInfo() mi, err := self.machineInfoFactory.GetMachineInfo()
if err != nil { if err != nil {
...@@ -264,7 +277,7 @@ func (self *dockerContainerHandler) GetStats() (*info.ContainerStats, error) { ...@@ -264,7 +277,7 @@ func (self *dockerContainerHandler) GetStats() (*info.ContainerStats, error) {
} }
} }
} }
stats, err := containerLibcontainer.GetStats(self.cgroupManager, networkInterfaces) stats, err := containerLibcontainer.GetStats(self.cgroupManager, networkInterfaces, self.pid)
if err != nil { if err != nil {
return stats, err return stats, err
} }
......
...@@ -15,14 +15,22 @@ ...@@ -15,14 +15,22 @@
package libcontainer package libcontainer
import ( import (
"bufio"
"fmt" "fmt"
"net"
"os/exec"
"path" "path"
"regexp"
"runtime"
"strings"
"time" "time"
"github.com/docker/libcontainer" "github.com/docker/libcontainer"
"github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/cgroups"
"github.com/golang/glog"
info "github.com/google/cadvisor/info/v1" info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/utils/sysinfo" "github.com/google/cadvisor/utils/sysinfo"
"github.com/vishvananda/netns"
) )
type CgroupSubsystems struct { type CgroupSubsystems struct {
...@@ -74,7 +82,7 @@ var supportedSubsystems map[string]struct{} = map[string]struct{}{ ...@@ -74,7 +82,7 @@ var supportedSubsystems map[string]struct{} = map[string]struct{}{
} }
// Get cgroup and networking stats of the specified container // Get cgroup and networking stats of the specified container
func GetStats(cgroupManager cgroups.Manager, networkInterfaces []string) (*info.ContainerStats, error) { func GetStats(cgroupManager cgroups.Manager, networkInterfaces []string, pid int) (*info.ContainerStats, error) {
cgroupStats, err := cgroupManager.GetStats() cgroupStats, err := cgroupManager.GetStats()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -93,14 +101,121 @@ func GetStats(cgroupManager cgroups.Manager, networkInterfaces []string) (*info. ...@@ -93,14 +101,121 @@ func GetStats(cgroupManager cgroups.Manager, networkInterfaces []string) (*info.
} }
stats.Network.Interfaces[i] = interfaceStats stats.Network.Interfaces[i] = interfaceStats
} }
// If we know the pid & we haven't discovered any network interfaces yet
// try the network namespace.
if pid > 0 && len(stats.Network.Interfaces) == 0 {
nsStats, err := networkStatsFromNs(pid)
if err != nil {
glog.V(2).Infof("Unable to get network stats from pid %d: %v", pid, err)
} else {
stats.Network.Interfaces = append(stats.Network.Interfaces, nsStats...)
}
}
// For backwards compatibility. // For backwards compatibility.
if len(networkInterfaces) > 0 { if len(stats.Network.Interfaces) > 0 {
stats.Network.InterfaceStats = stats.Network.Interfaces[0] stats.Network.InterfaceStats = stats.Network.Interfaces[0]
} }
return stats, nil return stats, nil
} }
func networkStatsFromNs(pid int) ([]info.InterfaceStats, error) {
// Lock the OS Thread so we only change the ns for this thread exclusively
runtime.LockOSThread()
defer runtime.UnlockOSThread()
stats := []info.InterfaceStats{}
// Save the current network namespace
origns, _ := netns.Get()
defer origns.Close()
// Switch to the pid netns
pidns, err := netns.GetFromPid(pid)
defer pidns.Close()
if err != nil {
return stats, nil
}
netns.Set(pidns)
// Defer setting back to original ns
defer netns.Set(origns)
ifaceStats, err := scanInterfaceStats()
if err != nil {
return stats, fmt.Errorf("couldn't read network stats: %v", err)
}
ifaces, err := net.Interfaces()
if err != nil {
return stats, fmt.Errorf("cannot find interfaces: %v", err)
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 {
if s, ok := ifaceStats[iface.Name]; ok {
stats = append(stats, s)
}
}
}
return stats, nil
}
// Borrowed from libnetwork Stats - https://github.com/docker/libnetwork/blob/master/sandbox/interface_linux.go
// In older kernels (like the one in Centos 6.6 distro) sysctl does not have netns support. Therefore
// we cannot gather the statistics from /sys/class/net/<dev>/statistics/<counter> files. Per-netns stats
// are naturally found in /proc/net/dev in kernels which support netns (ifconfig relyes on that).
const (
netStatsFile = "/proc/net/dev"
)
func scanInterfaceStats() (map[string]info.InterfaceStats, error) {
re := regexp.MustCompile("[ ]*(.+):([ ]+[0-9]+){16}")
var (
bkt uint64
)
stats := map[string]info.InterfaceStats{}
// For some reason ioutil.ReadFile(netStatsFile) reads the file in
// the default netns when this code is invoked from docker.
// Executing "cat <netStatsFile>" works as expected.
data, err := exec.Command("cat", netStatsFile).Output()
if err != nil {
return stats, fmt.Errorf("failure opening %s: %v", netStatsFile, err)
}
reader := strings.NewReader(string(data))
scanner := bufio.NewScanner(reader)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
if re.MatchString(line) {
line = strings.Replace(line, ":", "", -1)
i := info.InterfaceStats{}
_, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
&i.Name, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt,
&bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt)
if err != nil {
return stats, fmt.Errorf("failure opening %s: %v", netStatsFile, err)
}
stats[i.Name] = i
}
}
return stats, nil
}
func GetProcesses(cgroupManager cgroups.Manager) ([]int, error) { func GetProcesses(cgroupManager cgroups.Manager) ([]int, error) {
pids, err := cgroupManager.GetPids() pids, err := cgroupManager.GetPids()
if err != nil { if err != nil {
......
...@@ -334,7 +334,7 @@ func (self *rawContainerHandler) GetStats() (*info.ContainerStats, error) { ...@@ -334,7 +334,7 @@ func (self *rawContainerHandler) GetStats() (*info.ContainerStats, error) {
for i := range nd { for i := range nd {
networkInterfaces[i] = nd[i].Name networkInterfaces[i] = nd[i].Name
} }
stats, err := libcontainer.GetStats(self.cgroupManager, networkInterfaces) stats, err := libcontainer.GetStats(self.cgroupManager, networkInterfaces, -1)
if err != nil { if err != nil {
return stats, err return stats, err
} }
......
# netns - network namespaces in go #
The netns package provides an ultra-simple interface for handling
network namespaces in go. Changing namespaces requires elevated
privileges, so in most cases this code needs to be run as root.
## Local Build and Test ##
You can use go get command:
go get github.com/vishvananda/netns
Testing (requires root):
sudo -E go test github.com/vishvananda/netns
## Example ##
```go
package main
import (
"net"
"runtime"
"github.com/vishvananada/netns"
)
func main() {
// Lock the OS Thread so we don't accidentally switch namespaces
runtime.LockOSThread()
defer runtime.UnlockOSThread()
// Save the current network namespace
origns, _ := netns.Get()
defer origns.Close()
// Create a new network namespace
newns, _ := netns.New()
defer newns.Close()
// Do something with tne network namespace
ifaces, _ := net.Interfaces()
fmt.Printf("Interfaces: %v\n", ifaces)
// Switch back to the original namespace
netns.Set(origns)
}
```
// Package netns allows ultra-simple network namespace handling. NsHandles
// can be retrieved and set. Note that the current namespace is thread
// local so actions that set and reset namespaces should use LockOSThread
// to make sure the namespace doesn't change due to a goroutine switch.
// It is best to close NsHandles when you are done with them. This can be
// accomplished via a `defer ns.Close()` on the handle. Changing namespaces
// requires elevated privileges, so in most cases this code needs to be run
// as root.
package netns
import (
"fmt"
"syscall"
)
// NsHandle is a handle to a network namespace. It can be cast directly
// to an int and used as a file descriptor.
type NsHandle int
// Equal determines if two network handles refer to the same network
// namespace. This is done by comparing the device and inode that the
// file descripors point to.
func (ns NsHandle) Equal(other NsHandle) bool {
if ns == other {
return true
}
var s1, s2 syscall.Stat_t
if err := syscall.Fstat(int(ns), &s1); err != nil {
return false
}
if err := syscall.Fstat(int(other), &s2); err != nil {
return false
}
return (s1.Dev == s2.Dev) && (s1.Ino == s2.Ino)
}
// String shows the file descriptor number and its dev and inode.
func (ns NsHandle) String() string {
var s syscall.Stat_t
if ns == -1 {
return "NS(None)"
}
if err := syscall.Fstat(int(ns), &s); err != nil {
return fmt.Sprintf("NS(%d: unknown)", ns)
}
return fmt.Sprintf("NS(%d: %d, %d)", ns, s.Dev, s.Ino)
}
// IsOpen returns true if Close() has not been called.
func (ns NsHandle) IsOpen() bool {
return ns != -1
}
// Close closes the NsHandle and resets its file descriptor to -1.
// It is not safe to use an NsHandle after Close() is called.
func (ns *NsHandle) Close() error {
if err := syscall.Close(int(*ns)); err != nil {
return err
}
(*ns) = -1
return nil
}
// Get an empty (closed) NsHandle
func None() NsHandle {
return NsHandle(-1)
}
// +build linux
package netns
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
)
const (
// These constants belong in the syscall library but have not been
// added yet.
CLONE_NEWUTS = 0x04000000 /* New utsname group? */
CLONE_NEWIPC = 0x08000000 /* New ipcs */
CLONE_NEWUSER = 0x10000000 /* New user namespace */
CLONE_NEWPID = 0x20000000 /* New pid namespace */
CLONE_NEWNET = 0x40000000 /* New network namespace */
CLONE_IO = 0x80000000 /* Get io context */
)
// Setns sets namespace using syscall. Note that this should be a method
// in syscall but it has not been added.
func Setns(ns NsHandle, nstype int) (err error) {
_, _, e1 := syscall.Syscall(SYS_SETNS, uintptr(ns), uintptr(nstype), 0)
if e1 != 0 {
err = e1
}
return
}
// Set sets the current network namespace to the namespace represented
// by NsHandle.
func Set(ns NsHandle) (err error) {
return Setns(ns, CLONE_NEWNET)
}
// New creates a new network namespace and returns a handle to it.
func New() (ns NsHandle, err error) {
if err := syscall.Unshare(CLONE_NEWNET); err != nil {
return -1, err
}
return Get()
}
// Get gets a handle to the current threads network namespace.
func Get() (NsHandle, error) {
return GetFromThread(os.Getpid(), syscall.Gettid())
}
// GetFromPath gets a handle to a network namespace
// identified by the path
func GetFromPath(path string) (NsHandle, error) {
fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
if err != nil {
return -1, err
}
return NsHandle(fd), nil
}
// GetFromName gets a handle to a named network namespace such as one
// created by `ip netns add`.
func GetFromName(name string) (NsHandle, error) {
return GetFromPath(fmt.Sprintf("/var/run/netns/%s", name))
}
// GetFromPid gets a handle to the network namespace of a given pid.
func GetFromPid(pid int) (NsHandle, error) {
return GetFromPath(fmt.Sprintf("/proc/%d/ns/net", pid))
}
// GetFromThread gets a handle to the network namespace of a given pid and tid.
func GetFromThread(pid, tid int) (NsHandle, error) {
return GetFromPath(fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid))
}
// GetFromDocker gets a handle to the network namespace of a docker container.
// Id is prefixed matched against the running docker containers, so a short
// identifier can be used as long as it isn't ambiguous.
func GetFromDocker(id string) (NsHandle, error) {
pid, err := getPidForContainer(id)
if err != nil {
return -1, err
}
return GetFromPid(pid)
}
// borrowed from docker/utils/utils.go
func findCgroupMountpoint(cgroupType string) (string, error) {
output, err := ioutil.ReadFile("/proc/mounts")
if err != nil {
return "", err
}
// /proc/mounts has 6 fields per line, one mount per line, e.g.
// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
for _, line := range strings.Split(string(output), "\n") {
parts := strings.Split(line, " ")
if len(parts) == 6 && parts[2] == "cgroup" {
for _, opt := range strings.Split(parts[3], ",") {
if opt == cgroupType {
return parts[1], nil
}
}
}
}
return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
}
// Returns the relative path to the cgroup docker is running in.
// borrowed from docker/utils/utils.go
// modified to get the docker pid instead of using /proc/self
func getThisCgroup(cgroupType string) (string, error) {
dockerpid, err := ioutil.ReadFile("/var/run/docker.pid")
if err != nil {
return "", err
}
result := strings.Split(string(dockerpid), "\n")
if len(result) == 0 || len(result[0]) == 0 {
return "", fmt.Errorf("docker pid not found in /var/run/docker.pid")
}
pid, err := strconv.Atoi(result[0])
output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
if err != nil {
return "", err
}
for _, line := range strings.Split(string(output), "\n") {
parts := strings.Split(line, ":")
// any type used by docker should work
if parts[1] == cgroupType {
return parts[2], nil
}
}
return "", fmt.Errorf("cgroup '%s' not found in /proc/%d/cgroup", cgroupType, pid)
}
// Returns the first pid in a container.
// borrowed from docker/utils/utils.go
// modified to only return the first pid
// modified to glob with id
// modified to search for newer docker containers
func getPidForContainer(id string) (int, error) {
pid := 0
// memory is chosen randomly, any cgroup used by docker works
cgroupType := "memory"
cgroupRoot, err := findCgroupMountpoint(cgroupType)
if err != nil {
return pid, err
}
cgroupThis, err := getThisCgroup(cgroupType)
if err != nil {
return pid, err
}
id += "*"
attempts := []string{
filepath.Join(cgroupRoot, cgroupThis, id, "tasks"),
// With more recent lxc versions use, cgroup will be in lxc/
filepath.Join(cgroupRoot, cgroupThis, "lxc", id, "tasks"),
// With more recent dockee, cgroup will be in docker/
filepath.Join(cgroupRoot, cgroupThis, "docker", id, "tasks"),
}
var filename string
for _, attempt := range attempts {
filenames, _ := filepath.Glob(attempt)
if len(filenames) > 1 {
return pid, fmt.Errorf("Ambiguous id supplied: %v", filenames)
} else if len(filenames) == 1 {
filename = filenames[0]
break
}
}
if filename == "" {
return pid, fmt.Errorf("Unable to find container: %v", id[:len(id)-1])
}
output, err := ioutil.ReadFile(filename)
if err != nil {
return pid, err
}
result := strings.Split(string(output), "\n")
if len(result) == 0 || len(result[0]) == 0 {
return pid, fmt.Errorf("No pid found for container")
}
pid, err = strconv.Atoi(result[0])
if err != nil {
return pid, fmt.Errorf("Invalid pid '%s': %s", result[0], err)
}
return pid, nil
}
// +build linux,386
package netns
const (
SYS_SETNS = 346
)
// +build linux,amd64
package netns
const (
SYS_SETNS = 308
)
// +build linux,arm
package netns
const (
SYS_SETNS = 375
)
// +build linux,arm64
package netns
const (
SYS_SETNS = 268
)
// +build linux,ppc64le
package netns
const (
SYS_SETNS = 350
)
// +build linux,s390x
package netns
const (
SYS_SETNS = 339
)
package netns
import (
"runtime"
"sync"
"testing"
)
func TestGetNewSetDelete(t *testing.T) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
origns, err := Get()
if err != nil {
t.Fatal(err)
}
newns, err := New()
if err != nil {
t.Fatal(err)
}
if origns.Equal(newns) {
t.Fatal("New ns failed")
}
if err := Set(origns); err != nil {
t.Fatal(err)
}
newns.Close()
if newns.IsOpen() {
t.Fatal("newns still open after close", newns)
}
ns, err := Get()
if err != nil {
t.Fatal(err)
}
if !ns.Equal(origns) {
t.Fatal("Reset ns failed", origns, newns, ns)
}
}
func TestNone(t *testing.T) {
ns := None()
if ns.IsOpen() {
t.Fatal("None ns is open", ns)
}
}
func TestThreaded(t *testing.T) {
ncpu := runtime.GOMAXPROCS(-1)
if ncpu < 2 {
t.Skip("-cpu=2 or larger required")
}
// Lock this thread simply to ensure other threads get used.
runtime.LockOSThread()
defer runtime.UnlockOSThread()
wg := &sync.WaitGroup{}
for i := 0; i < ncpu; i++ {
wg.Add(1)
go func() {
defer wg.Done()
TestGetNewSetDelete(t)
}()
}
wg.Wait()
}
// +build !linux
package netns
import (
"errors"
)
var (
ErrNotImplemented = errors.New("not implemented")
)
func Set(ns NsHandle) (err error) {
return ErrNotImplemented
}
func New() (ns NsHandle, err error) {
return -1, ErrNotImplemented
}
func Get() (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromName(name string) (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromPid(pid int) (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromDocker(id string) (NsHandle, error) {
return -1, ErrNotImplemented
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment