pull out common parts of docker and raw container handlers for use by rkt handler
This commit is contained in:
parent
4a8ffcfc7e
commit
5e04a224ae
@ -16,7 +16,7 @@
|
||||
// an array of ContainerHint structs, each with a container's id and networkInterface
|
||||
// This allows collecting stats about network interfaces configured outside docker
|
||||
// and lxc
|
||||
package raw
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -25,7 +25,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var argContainerHints = flag.String("container_hints", "/etc/cadvisor/container_hints.json", "location of the container hints file")
|
||||
var ArgContainerHints = flag.String("container_hints", "/etc/cadvisor/container_hints.json", "location of the container hints file")
|
||||
|
||||
type containerHints struct {
|
||||
AllHosts []containerHint `json:"all_hosts,omitempty"`
|
||||
@ -34,10 +34,10 @@ type containerHints struct {
|
||||
type containerHint struct {
|
||||
FullName string `json:"full_path,omitempty"`
|
||||
NetworkInterface *networkInterface `json:"network_interface,omitempty"`
|
||||
Mounts []mount `json:"mounts,omitempty"`
|
||||
Mounts []Mount `json:"mounts,omitempty"`
|
||||
}
|
||||
|
||||
type mount struct {
|
||||
type Mount struct {
|
||||
HostDir string `json:"host_dir,omitempty"`
|
||||
ContainerDir string `json:"container_dir,omitempty"`
|
||||
}
|
||||
@ -47,7 +47,7 @@ type networkInterface struct {
|
||||
VethChild string `json:"veth_child,omitempty"`
|
||||
}
|
||||
|
||||
func getContainerHintsFromFile(containerHintsFile string) (containerHints, error) {
|
||||
func GetContainerHintsFromFile(containerHintsFile string) (containerHints, error) {
|
||||
dat, err := ioutil.ReadFile(containerHintsFile)
|
||||
if os.IsNotExist(err) {
|
||||
return containerHints{}, nil
|
@ -12,14 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package raw
|
||||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetContainerHintsFromFile(t *testing.T) {
|
||||
cHints, err := getContainerHintsFromFile("test_resources/container_hints.json")
|
||||
cHints, err := GetContainerHintsFromFile("test_resources/container_hints.json")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error in unmarshalling: %s", err)
|
||||
@ -50,8 +50,8 @@ func TestGetContainerHintsFromFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileNotExist(t *testing.T) {
|
||||
_, err := getContainerHintsFromFile("/file_does_not_exist.json")
|
||||
_, err := GetContainerHintsFromFile("/file_does_not_exist.json")
|
||||
if err != nil {
|
||||
t.Fatalf("getContainerHintsFromFile must not error for blank file: %s", err)
|
||||
t.Fatalf("GetContainerHintsFromFile must not error for blank file: %s", err)
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
// Handler for Docker containers.
|
||||
package docker
|
||||
package common
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@ -24,10 +24,10 @@ import (
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
type fsHandler interface {
|
||||
start()
|
||||
usage() (uint64, uint64)
|
||||
stop()
|
||||
type FsHandler interface {
|
||||
Start()
|
||||
Usage() (baseUsageBytes uint64, totalUsageBytes uint64)
|
||||
Stop()
|
||||
}
|
||||
|
||||
type realFsHandler struct {
|
||||
@ -50,9 +50,9 @@ const (
|
||||
maxDuBackoffFactor = 20
|
||||
)
|
||||
|
||||
var _ fsHandler = &realFsHandler{}
|
||||
var _ FsHandler = &realFsHandler{}
|
||||
|
||||
func newFsHandler(period time.Duration, rootfs, extraDir string, fsInfo fs.FsInfo) fsHandler {
|
||||
func NewFsHandler(period time.Duration, rootfs, extraDir string, fsInfo fs.FsInfo) FsHandler {
|
||||
return &realFsHandler{
|
||||
lastUpdate: time.Time{},
|
||||
usageBytes: 0,
|
||||
@ -119,15 +119,15 @@ func (fh *realFsHandler) trackUsage() {
|
||||
}
|
||||
}
|
||||
|
||||
func (fh *realFsHandler) start() {
|
||||
func (fh *realFsHandler) Start() {
|
||||
go fh.trackUsage()
|
||||
}
|
||||
|
||||
func (fh *realFsHandler) stop() {
|
||||
func (fh *realFsHandler) Stop() {
|
||||
close(fh.stopChan)
|
||||
}
|
||||
|
||||
func (fh *realFsHandler) usage() (baseUsageBytes, totalUsageBytes uint64) {
|
||||
func (fh *realFsHandler) Usage() (baseUsageBytes, totalUsageBytes uint64) {
|
||||
fh.RLock()
|
||||
defer fh.RUnlock()
|
||||
return fh.baseUsageBytes, fh.usageBytes
|
239
container/common/helpers.go
Normal file
239
container/common/helpers.go
Normal file
@ -0,0 +1,239 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/utils"
|
||||
"github.com/google/cadvisor/utils/machine"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
func DebugInfo(watches map[string][]string) map[string][]string {
|
||||
out := make(map[string][]string)
|
||||
|
||||
lines := make([]string, 0, len(watches))
|
||||
for containerName, cgroupWatches := range watches {
|
||||
lines = append(lines, fmt.Sprintf("%s:", containerName))
|
||||
for _, cg := range cgroupWatches {
|
||||
lines = append(lines, fmt.Sprintf("\t%s", cg))
|
||||
}
|
||||
}
|
||||
out["Inotify watches"] = lines
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type AbstractContainerHandler interface {
|
||||
GetCgroupPaths() map[string]string
|
||||
GetMachineInfoFactory() info.MachineInfoFactory
|
||||
GetName() string
|
||||
GetRootNetworkDevices() ([]info.NetInfo, error)
|
||||
GetExternalMounts() []Mount
|
||||
HasNetwork() bool
|
||||
HasFilesystem() bool
|
||||
}
|
||||
|
||||
func GetSpec(handler AbstractContainerHandler) (info.ContainerSpec, error) {
|
||||
cgroupPaths := handler.GetCgroupPaths()
|
||||
machineInfoFactory := handler.GetMachineInfoFactory()
|
||||
name := handler.GetName()
|
||||
externalMounts := handler.GetExternalMounts()
|
||||
|
||||
var spec info.ContainerSpec
|
||||
|
||||
// The raw driver assumes unified hierarchy containers.
|
||||
|
||||
// Get the lowest creation time from all hierarchies as the container creation time.
|
||||
now := time.Now()
|
||||
lowestTime := now
|
||||
for _, cgroupPath := range cgroupPaths {
|
||||
// The modified time of the cgroup directory changes whenever a subcontainer is created.
|
||||
// eg. /docker will have creation time matching the creation of latest docker container.
|
||||
// Use clone_children as a workaround as it isn't usually modified. It is only likely changed
|
||||
// immediately after creating a container.
|
||||
cgroupPath = path.Join(cgroupPath, "cgroup.clone_children")
|
||||
fi, err := os.Stat(cgroupPath)
|
||||
if err == nil && fi.ModTime().Before(lowestTime) {
|
||||
lowestTime = fi.ModTime()
|
||||
}
|
||||
}
|
||||
if lowestTime != now {
|
||||
spec.CreationTime = lowestTime
|
||||
}
|
||||
|
||||
// Get machine info.
|
||||
mi, err := machineInfoFactory.GetMachineInfo()
|
||||
if err != nil {
|
||||
return spec, err
|
||||
}
|
||||
|
||||
// CPU.
|
||||
cpuRoot, ok := cgroupPaths["cpu"]
|
||||
if ok {
|
||||
if utils.FileExists(cpuRoot) {
|
||||
spec.HasCpu = true
|
||||
spec.Cpu.Limit = readUInt64(cpuRoot, "cpu.shares")
|
||||
spec.Cpu.Period = readUInt64(cpuRoot, "cpu.cfs_period_us")
|
||||
quota := readString(cpuRoot, "cpu.cfs_quota_us")
|
||||
|
||||
if quota != "" && quota != "-1" {
|
||||
val, err := strconv.ParseUint(quota, 10, 64)
|
||||
if err != nil {
|
||||
glog.Errorf("GetSpec: Failed to parse CPUQuota from %q: %s", path.Join(cpuRoot, "cpu.cfs_quota_us"), err)
|
||||
}
|
||||
spec.Cpu.Quota = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cpu Mask.
|
||||
// This will fail for non-unified hierarchies. We'll return the whole machine mask in that case.
|
||||
cpusetRoot, ok := cgroupPaths["cpuset"]
|
||||
if ok {
|
||||
if utils.FileExists(cpusetRoot) {
|
||||
spec.HasCpu = true
|
||||
mask := readString(cpusetRoot, "cpuset.cpus")
|
||||
spec.Cpu.Mask = utils.FixCpuMask(mask, mi.NumCores)
|
||||
}
|
||||
}
|
||||
|
||||
// Memory
|
||||
if name == "/" {
|
||||
// Get memory and swap limits of the running machine
|
||||
memLimit, err := machine.GetMachineMemoryCapacity()
|
||||
if err != nil {
|
||||
glog.Warningf("failed to obtain memory limit for machine container")
|
||||
spec.HasMemory = false
|
||||
} else {
|
||||
spec.Memory.Limit = uint64(memLimit)
|
||||
// Spec is marked to have memory only if the memory limit is set
|
||||
spec.HasMemory = true
|
||||
}
|
||||
|
||||
swapLimit, err := machine.GetMachineSwapCapacity()
|
||||
if err != nil {
|
||||
glog.Warningf("failed to obtain swap limit for machine container")
|
||||
} else {
|
||||
spec.Memory.SwapLimit = uint64(swapLimit)
|
||||
}
|
||||
} else {
|
||||
memoryRoot, ok := cgroupPaths["memory"]
|
||||
if ok {
|
||||
if utils.FileExists(memoryRoot) {
|
||||
spec.HasMemory = true
|
||||
spec.Memory.Limit = readUInt64(memoryRoot, "memory.limit_in_bytes")
|
||||
spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.memsw.limit_in_bytes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spec.HasFilesystem = name == "/" || externalMounts != nil || handler.HasFilesystem()
|
||||
|
||||
spec.HasNetwork = handler.HasNetwork()
|
||||
|
||||
if blkioRoot, ok := cgroupPaths["blkio"]; ok && utils.FileExists(blkioRoot) {
|
||||
spec.HasDiskIo = true
|
||||
}
|
||||
|
||||
// Check physical network devices for root container.
|
||||
nd, err := handler.GetRootNetworkDevices()
|
||||
if err != nil {
|
||||
return spec, err
|
||||
}
|
||||
|
||||
spec.HasNetwork = spec.HasNetwork || len(nd) != 0
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func readString(dirpath string, file string) string {
|
||||
cgroupFile := path.Join(dirpath, file)
|
||||
|
||||
// Ignore non-existent files
|
||||
if !utils.FileExists(cgroupFile) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Read
|
||||
out, err := ioutil.ReadFile(cgroupFile)
|
||||
if err != nil {
|
||||
glog.Errorf("readString: Failed to read %q: %s", cgroupFile, err)
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(out))
|
||||
}
|
||||
|
||||
func readUInt64(dirpath string, file string) uint64 {
|
||||
out := readString(dirpath, file)
|
||||
if out == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
val, err := strconv.ParseUint(out, 10, 64)
|
||||
if err != nil {
|
||||
glog.Errorf("readUInt64: Failed to parse int %q from file %q: %s", out, path.Join(dirpath, file), err)
|
||||
return 0
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// Lists all directories under "path" and outputs the results as children of "parent".
|
||||
func ListDirectories(dirpath string, parent string, recursive bool, output map[string]struct{}) error {
|
||||
// Ignore if this hierarchy does not exist.
|
||||
if !utils.FileExists(dirpath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
entries, err := ioutil.ReadDir(dirpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
// We only grab directories.
|
||||
if entry.IsDir() {
|
||||
name := path.Join(parent, entry.Name())
|
||||
output[name] = struct{}{}
|
||||
|
||||
// List subcontainers if asked to.
|
||||
if recursive {
|
||||
err := ListDirectories(path.Join(dirpath, entry.Name()), name, true, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func MakeCgroupPaths(mountPoints map[string]string, name string) map[string]string {
|
||||
cgroupPaths := make(map[string]string, len(mountPoints))
|
||||
for key, val := range mountPoints {
|
||||
cgroupPaths[key] = path.Join(val, name)
|
||||
}
|
||||
|
||||
return cgroupPaths
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package raw
|
||||
package common
|
||||
|
||||
import (
|
||||
"sync"
|
@ -24,6 +24,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/common"
|
||||
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
@ -80,7 +81,7 @@ type dockerContainerHandler struct {
|
||||
networkMode string
|
||||
|
||||
// Filesystem handler.
|
||||
fsHandler fsHandler
|
||||
fsHandler common.FsHandler
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
}
|
||||
@ -169,7 +170,7 @@ func newDockerContainerHandler(
|
||||
}
|
||||
|
||||
if !ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
handler.fsHandler = newFsHandler(time.Minute, rootfsStorageDir, otherStorageDir, fsInfo)
|
||||
handler.fsHandler = common.NewFsHandler(time.Minute, rootfsStorageDir, otherStorageDir, fsInfo)
|
||||
}
|
||||
|
||||
// We assume that if Inspect fails then the container is not known to docker.
|
||||
@ -200,15 +201,14 @@ func newDockerContainerHandler(
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) Start() {
|
||||
// Start the filesystem handler.
|
||||
if self.fsHandler != nil {
|
||||
self.fsHandler.start()
|
||||
self.fsHandler.Start()
|
||||
}
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) Cleanup() {
|
||||
if self.fsHandler != nil {
|
||||
self.fsHandler.stop()
|
||||
self.fsHandler.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,6 +317,7 @@ func (self *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
limit uint64
|
||||
fsType string
|
||||
@ -333,7 +334,7 @@ func (self *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error
|
||||
|
||||
fsStat := info.FsStats{Device: deviceInfo.Device, Type: fsType, Limit: limit}
|
||||
|
||||
fsStat.BaseUsage, fsStat.Usage = self.fsHandler.usage()
|
||||
fsStat.BaseUsage, fsStat.Usage = self.fsHandler.Usage()
|
||||
stats.Filesystem = append(stats.Filesystem, fsStat)
|
||||
|
||||
return nil
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/common"
|
||||
"github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
@ -39,7 +40,7 @@ type rawFactory struct {
|
||||
fsInfo fs.FsInfo
|
||||
|
||||
// Watcher for inotify events.
|
||||
watcher *InotifyWatcher
|
||||
watcher *common.InotifyWatcher
|
||||
|
||||
// List of metrics to be ignored.
|
||||
ignoreMetrics map[container.MetricKind]struct{}
|
||||
@ -64,20 +65,7 @@ func (self *rawFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
||||
}
|
||||
|
||||
func (self *rawFactory) DebugInfo() map[string][]string {
|
||||
out := make(map[string][]string)
|
||||
|
||||
// Get information about inotify watches.
|
||||
watches := self.watcher.GetWatches()
|
||||
lines := make([]string, 0, len(watches))
|
||||
for containerName, cgroupWatches := range watches {
|
||||
lines = append(lines, fmt.Sprintf("%s:", containerName))
|
||||
for _, cg := range cgroupWatches {
|
||||
lines = append(lines, fmt.Sprintf("\t%s", cg))
|
||||
}
|
||||
}
|
||||
out["Inotify watches"] = lines
|
||||
|
||||
return out
|
||||
return common.DebugInfo(self.watcher.GetWatches())
|
||||
}
|
||||
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics map[container.MetricKind]struct{}) error {
|
||||
@ -89,7 +77,7 @@ func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, igno
|
||||
return fmt.Errorf("failed to find supported cgroup mounts for the raw factory")
|
||||
}
|
||||
|
||||
watcher, err := NewInotifyWatcher()
|
||||
watcher, err := common.NewInotifyWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,16 +20,14 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/common"
|
||||
"github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/utils"
|
||||
"github.com/google/cadvisor/utils/machine"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
@ -45,7 +43,7 @@ type rawContainerHandler struct {
|
||||
machineInfoFactory info.MachineInfoFactory
|
||||
|
||||
// Inotify event watcher.
|
||||
watcher *InotifyWatcher
|
||||
watcher *common.InotifyWatcher
|
||||
|
||||
// Signal for watcher thread to stop.
|
||||
stopWatcher chan error
|
||||
@ -58,7 +56,7 @@ type rawContainerHandler struct {
|
||||
cgroupManager cgroups.Manager
|
||||
|
||||
fsInfo fs.FsInfo
|
||||
externalMounts []mount
|
||||
externalMounts []common.Mount
|
||||
|
||||
rootFs string
|
||||
|
||||
@ -66,14 +64,34 @@ type rawContainerHandler struct {
|
||||
ignoreMetrics container.MetricSet
|
||||
}
|
||||
|
||||
func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, watcher *InotifyWatcher, rootFs string, ignoreMetrics container.MetricSet) (container.ContainerHandler, error) {
|
||||
// Create the cgroup paths.
|
||||
cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints))
|
||||
for key, val := range cgroupSubsystems.MountPoints {
|
||||
cgroupPaths[key] = path.Join(val, name)
|
||||
}
|
||||
func (self *rawContainerHandler) GetCgroupPaths() map[string]string {
|
||||
return self.cgroupPaths
|
||||
}
|
||||
|
||||
cHints, err := getContainerHintsFromFile(*argContainerHints)
|
||||
func (self *rawContainerHandler) GetMachineInfoFactory() info.MachineInfoFactory {
|
||||
return self.machineInfoFactory
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) GetName() string {
|
||||
return self.name
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) GetExternalMounts() []common.Mount {
|
||||
return self.externalMounts
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) HasNetwork() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) HasFilesystem() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, watcher *common.InotifyWatcher, rootFs string, ignoreMetrics container.MetricSet) (container.ContainerHandler, error) {
|
||||
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
|
||||
|
||||
cHints, err := common.GetContainerHintsFromFile(*common.ArgContainerHints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -86,7 +104,7 @@ func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSu
|
||||
Paths: cgroupPaths,
|
||||
}
|
||||
|
||||
var externalMounts []mount
|
||||
var externalMounts []common.Mount
|
||||
for _, container := range cHints.AllHosts {
|
||||
if name == container.FullName {
|
||||
externalMounts = container.Mounts
|
||||
@ -116,38 +134,6 @@ func (self *rawContainerHandler) ContainerReference() (info.ContainerReference,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readString(dirpath string, file string) string {
|
||||
cgroupFile := path.Join(dirpath, file)
|
||||
|
||||
// Ignore non-existent files
|
||||
if !utils.FileExists(cgroupFile) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Read
|
||||
out, err := ioutil.ReadFile(cgroupFile)
|
||||
if err != nil {
|
||||
glog.Errorf("raw driver: Failed to read %q: %s", cgroupFile, err)
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(out))
|
||||
}
|
||||
|
||||
func readUInt64(dirpath string, file string) uint64 {
|
||||
out := readString(dirpath, file)
|
||||
if out == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
val, err := strconv.ParseUint(out, 10, 64)
|
||||
if err != nil {
|
||||
glog.Errorf("raw driver: Failed to parse int %q from file %q: %s", out, path.Join(dirpath, file), err)
|
||||
return 0
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) GetRootNetworkDevices() ([]info.NetInfo, error) {
|
||||
nd := []info.NetInfo{}
|
||||
if self.name == "/" {
|
||||
@ -167,113 +153,7 @@ func (self *rawContainerHandler) Start() {}
|
||||
func (self *rawContainerHandler) Cleanup() {}
|
||||
|
||||
func (self *rawContainerHandler) GetSpec() (info.ContainerSpec, error) {
|
||||
var spec info.ContainerSpec
|
||||
|
||||
// The raw driver assumes unified hierarchy containers.
|
||||
|
||||
// Get the lowest creation time from all hierarchies as the container creation time.
|
||||
now := time.Now()
|
||||
lowestTime := now
|
||||
for _, cgroupPath := range self.cgroupPaths {
|
||||
// The modified time of the cgroup directory changes whenever a subcontainer is created.
|
||||
// eg. /docker will have creation time matching the creation of latest docker container.
|
||||
// Use clone_children as a workaround as it isn't usually modified. It is only likely changed
|
||||
// immediately after creating a container.
|
||||
cgroupPath = path.Join(cgroupPath, "cgroup.clone_children")
|
||||
fi, err := os.Stat(cgroupPath)
|
||||
if err == nil && fi.ModTime().Before(lowestTime) {
|
||||
lowestTime = fi.ModTime()
|
||||
}
|
||||
}
|
||||
if lowestTime != now {
|
||||
spec.CreationTime = lowestTime
|
||||
}
|
||||
|
||||
// Get machine info.
|
||||
mi, err := self.machineInfoFactory.GetMachineInfo()
|
||||
if err != nil {
|
||||
return spec, err
|
||||
}
|
||||
|
||||
// CPU.
|
||||
cpuRoot, ok := self.cgroupPaths["cpu"]
|
||||
if ok {
|
||||
if utils.FileExists(cpuRoot) {
|
||||
spec.HasCpu = true
|
||||
spec.Cpu.Limit = readUInt64(cpuRoot, "cpu.shares")
|
||||
spec.Cpu.Period = readUInt64(cpuRoot, "cpu.cfs_period_us")
|
||||
quota := readString(cpuRoot, "cpu.cfs_quota_us")
|
||||
|
||||
if quota != "" && quota != "-1" {
|
||||
val, err := strconv.ParseUint(quota, 10, 64)
|
||||
if err != nil {
|
||||
glog.Errorf("raw driver: Failed to parse CPUQuota from %q: %s", path.Join(cpuRoot, "cpu.cfs_quota_us"), err)
|
||||
}
|
||||
spec.Cpu.Quota = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cpu Mask.
|
||||
// This will fail for non-unified hierarchies. We'll return the whole machine mask in that case.
|
||||
cpusetRoot, ok := self.cgroupPaths["cpuset"]
|
||||
if ok {
|
||||
if utils.FileExists(cpusetRoot) {
|
||||
spec.HasCpu = true
|
||||
mask := readString(cpusetRoot, "cpuset.cpus")
|
||||
spec.Cpu.Mask = utils.FixCpuMask(mask, mi.NumCores)
|
||||
}
|
||||
}
|
||||
|
||||
// Memory
|
||||
if self.name == "/" {
|
||||
// Get memory and swap limits of the running machine
|
||||
memLimit, err := machine.GetMachineMemoryCapacity()
|
||||
if err != nil {
|
||||
glog.Warningf("failed to obtain memory limit for machine container")
|
||||
spec.HasMemory = false
|
||||
} else {
|
||||
spec.Memory.Limit = uint64(memLimit)
|
||||
// Spec is marked to have memory only if the memory limit is set
|
||||
spec.HasMemory = true
|
||||
}
|
||||
|
||||
swapLimit, err := machine.GetMachineSwapCapacity()
|
||||
if err != nil {
|
||||
glog.Warningf("failed to obtain swap limit for machine container")
|
||||
} else {
|
||||
spec.Memory.SwapLimit = uint64(swapLimit)
|
||||
}
|
||||
} else {
|
||||
memoryRoot, ok := self.cgroupPaths["memory"]
|
||||
if ok {
|
||||
if utils.FileExists(memoryRoot) {
|
||||
spec.HasMemory = true
|
||||
spec.Memory.Limit = readUInt64(memoryRoot, "memory.limit_in_bytes")
|
||||
spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.memsw.limit_in_bytes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fs.
|
||||
if self.name == "/" || self.externalMounts != nil {
|
||||
spec.HasFilesystem = true
|
||||
}
|
||||
|
||||
// DiskIo.
|
||||
if blkioRoot, ok := self.cgroupPaths["blkio"]; ok && utils.FileExists(blkioRoot) {
|
||||
spec.HasDiskIo = true
|
||||
}
|
||||
|
||||
// Check physical network devices for root container.
|
||||
nd, err := self.GetRootNetworkDevices()
|
||||
if err != nil {
|
||||
return spec, err
|
||||
}
|
||||
if len(nd) != 0 {
|
||||
spec.HasNetwork = true
|
||||
}
|
||||
return spec, nil
|
||||
return common.GetSpec(self)
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) getFsStats(stats *info.ContainerStats) error {
|
||||
@ -367,39 +247,10 @@ func (self *rawContainerHandler) GetContainerLabels() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// Lists all directories under "path" and outputs the results as children of "parent".
|
||||
func listDirectories(dirpath string, parent string, recursive bool, output map[string]struct{}) error {
|
||||
// Ignore if this hierarchy does not exist.
|
||||
if !utils.FileExists(dirpath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
entries, err := ioutil.ReadDir(dirpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
// We only grab directories.
|
||||
if entry.IsDir() {
|
||||
name := path.Join(parent, entry.Name())
|
||||
output[name] = struct{}{}
|
||||
|
||||
// List subcontainers if asked to.
|
||||
if recursive {
|
||||
err := listDirectories(path.Join(dirpath, entry.Name()), name, true, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
||||
containers := make(map[string]struct{})
|
||||
for _, cgroupPath := range self.cgroupPaths {
|
||||
err := listDirectories(cgroupPath, self.name, listType == container.ListRecursive, containers)
|
||||
err := common.ListDirectories(cgroupPath, self.name, listType == container.ListRecursive, containers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user