mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Update libcontainer to 84ad9386a0240acb7475429a835
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
		
							parent
							
								
									1ed467a9ae
								
							
						
					
					
						commit
						c604dc292e
					
				
					 9 changed files with 84 additions and 103 deletions
				
			
		| 
						 | 
				
			
			@ -62,7 +62,7 @@ if [ "$1" = '--go' ]; then
 | 
			
		|||
	mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
clone git github.com/docker/libcontainer 55430d0db7c6bb1198c0bb573a9700a859d5ec26
 | 
			
		||||
clone git github.com/docker/libcontainer 84ad9386a0240acb7475429a835d826007032bf9
 | 
			
		||||
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
 | 
			
		||||
rm -rf src/github.com/docker/libcontainer/vendor
 | 
			
		||||
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,26 +1,22 @@
 | 
			
		|||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/libcontainer/cgroups"
 | 
			
		||||
	"github.com/docker/libcontainer/system"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	cpuCount   = uint64(runtime.NumCPU())
 | 
			
		||||
	clockTicks = uint64(system.GetClockTicks())
 | 
			
		||||
const (
 | 
			
		||||
	cgroupCpuacctStat   = "cpuacct.stat"
 | 
			
		||||
	nanosecondsInSecond = 1000000000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const nanosecondsInSecond = 1000000000
 | 
			
		||||
var clockTicks = uint64(system.GetClockTicks())
 | 
			
		||||
 | 
			
		||||
type CpuacctGroup struct {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -39,103 +35,53 @@ func (s *CpuacctGroup) Remove(d *data) error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
 | 
			
		||||
	var (
 | 
			
		||||
		err                                                                                                           error
 | 
			
		||||
		startCpu, lastCpu, startSystem, lastSystem, startUsage, lastUsage, kernelModeUsage, userModeUsage, percentage uint64
 | 
			
		||||
	)
 | 
			
		||||
	if kernelModeUsage, userModeUsage, err = getCpuUsage(path); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	startCpu = kernelModeUsage + userModeUsage
 | 
			
		||||
	if startSystem, err = getSystemCpuUsage(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	startUsageTime := time.Now()
 | 
			
		||||
	if startUsage, err = getCgroupParamInt(path, "cpuacct.usage"); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// sample for 100ms
 | 
			
		||||
	time.Sleep(1000 * time.Millisecond)
 | 
			
		||||
	if kernelModeUsage, userModeUsage, err = getCpuUsage(path); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	lastCpu = kernelModeUsage + userModeUsage
 | 
			
		||||
	if lastSystem, err = getSystemCpuUsage(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	usageSampleDuration := time.Since(startUsageTime)
 | 
			
		||||
	if lastUsage, err = getCgroupParamInt(path, "cpuacct.usage"); err != nil {
 | 
			
		||||
	userModeUsage, kernelModeUsage, err := getCpuUsageBreakdown(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		deltaProc   = lastCpu - startCpu
 | 
			
		||||
		deltaSystem = lastSystem - startSystem
 | 
			
		||||
		deltaUsage  = lastUsage - startUsage
 | 
			
		||||
	)
 | 
			
		||||
	if deltaSystem > 0.0 {
 | 
			
		||||
		percentage = uint64((float64(deltaProc) / float64(deltaSystem)) * float64(clockTicks*cpuCount))
 | 
			
		||||
	totalUsage, err := getCgroupParamInt(path, "cpuacct.usage")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// NOTE: a percentage over 100% is valid for POSIX because that means the
 | 
			
		||||
	// processes is using multiple cores
 | 
			
		||||
	stats.CpuStats.CpuUsage.PercentUsage = percentage
 | 
			
		||||
	// Delta usage is in nanoseconds of CPU time so get the usage (in cores) over the sample time.
 | 
			
		||||
	stats.CpuStats.CpuUsage.CurrentUsage = deltaUsage / uint64(usageSampleDuration.Nanoseconds())
 | 
			
		||||
 | 
			
		||||
	percpuUsage, err := getPercpuUsage(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	stats.CpuStats.CpuUsage.TotalUsage = lastUsage
 | 
			
		||||
 | 
			
		||||
	stats.CpuStats.CpuUsage.TotalUsage = totalUsage
 | 
			
		||||
	stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage
 | 
			
		||||
	stats.CpuStats.CpuUsage.UsageInKernelmode = (kernelModeUsage * nanosecondsInSecond) / clockTicks
 | 
			
		||||
	stats.CpuStats.CpuUsage.UsageInUsermode = (userModeUsage * nanosecondsInSecond) / clockTicks
 | 
			
		||||
	stats.CpuStats.CpuUsage.UsageInUsermode = userModeUsage
 | 
			
		||||
	stats.CpuStats.CpuUsage.UsageInKernelmode = kernelModeUsage
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO(vmarmol): Use cgroups stats.
 | 
			
		||||
func getSystemCpuUsage() (uint64, error) {
 | 
			
		||||
 | 
			
		||||
	f, err := os.Open("/proc/stat")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	sc := bufio.NewScanner(f)
 | 
			
		||||
	for sc.Scan() {
 | 
			
		||||
		parts := strings.Fields(sc.Text())
 | 
			
		||||
		switch parts[0] {
 | 
			
		||||
		case "cpu":
 | 
			
		||||
			if len(parts) < 8 {
 | 
			
		||||
				return 0, fmt.Errorf("invalid number of cpu fields")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var total uint64
 | 
			
		||||
			for _, i := range parts[1:8] {
 | 
			
		||||
				v, err := strconv.ParseUint(i, 10, 64)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return 0.0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
 | 
			
		||||
				}
 | 
			
		||||
				total += v
 | 
			
		||||
			}
 | 
			
		||||
			return total, nil
 | 
			
		||||
		default:
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, fmt.Errorf("invalid stat format")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getCpuUsage(path string) (uint64, uint64, error) {
 | 
			
		||||
	kernelModeUsage := uint64(0)
 | 
			
		||||
// Returns user and kernel usage breakdown in nanoseconds.
 | 
			
		||||
func getCpuUsageBreakdown(path string) (uint64, uint64, error) {
 | 
			
		||||
	userModeUsage := uint64(0)
 | 
			
		||||
	data, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.stat"))
 | 
			
		||||
	kernelModeUsage := uint64(0)
 | 
			
		||||
	const (
 | 
			
		||||
		userField   = "user"
 | 
			
		||||
		systemField = "system"
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// Expected format:
 | 
			
		||||
	// user <usage in ticks>
 | 
			
		||||
	// system <usage in ticks>
 | 
			
		||||
	data, err := ioutil.ReadFile(filepath.Join(path, cgroupCpuacctStat))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, 0, err
 | 
			
		||||
	}
 | 
			
		||||
	fields := strings.Fields(string(data))
 | 
			
		||||
	if len(fields) != 4 {
 | 
			
		||||
		return 0, 0, fmt.Errorf("Failure - %s is expected to have 4 fields", filepath.Join(path, "cpuacct.stat"))
 | 
			
		||||
		return 0, 0, fmt.Errorf("failure - %s is expected to have 4 fields", filepath.Join(path, cgroupCpuacctStat))
 | 
			
		||||
	}
 | 
			
		||||
	if fields[0] != userField {
 | 
			
		||||
		return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[0], cgroupCpuacctStat, userField)
 | 
			
		||||
	}
 | 
			
		||||
	if fields[2] != systemField {
 | 
			
		||||
		return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[2], cgroupCpuacctStat, systemField)
 | 
			
		||||
	}
 | 
			
		||||
	if userModeUsage, err = strconv.ParseUint(fields[1], 10, 64); err != nil {
 | 
			
		||||
		return 0, 0, err
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +90,7 @@ func getCpuUsage(path string) (uint64, uint64, error) {
 | 
			
		|||
		return 0, 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return kernelModeUsage, userModeUsage, nil
 | 
			
		||||
	return (userModeUsage * nanosecondsInSecond) / clockTicks, (kernelModeUsage * nanosecondsInSecond) / clockTicks, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getPercpuUsage(path string) ([]uint64, error) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,17 +9,19 @@ type ThrottlingData struct {
 | 
			
		|||
	ThrottledTime uint64 `json:"throttled_time,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// All CPU stats are aggregate since container inception.
 | 
			
		||||
type CpuUsage struct {
 | 
			
		||||
	// percentage of available CPUs currently being used.
 | 
			
		||||
	PercentUsage uint64 `json:"percent_usage,omitempty"`
 | 
			
		||||
	// nanoseconds of cpu time consumed over the last 100 ms.
 | 
			
		||||
	CurrentUsage uint64 `json:"current_usage,omitempty"`
 | 
			
		||||
	// total nanoseconds of cpu time consumed
 | 
			
		||||
	TotalUsage  uint64   `json:"total_usage,omitempty"`
 | 
			
		||||
	// Total CPU time consumed.
 | 
			
		||||
	// Units: nanoseconds.
 | 
			
		||||
	TotalUsage uint64 `json:"total_usage,omitempty"`
 | 
			
		||||
	// Total CPU time consumed per core.
 | 
			
		||||
	// Units: nanoseconds.
 | 
			
		||||
	PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
 | 
			
		||||
	// Time spent by tasks of the cgroup in kernel mode. Units: nanoseconds.
 | 
			
		||||
	// Time spent by tasks of the cgroup in kernel mode.
 | 
			
		||||
	// Units: nanoseconds.
 | 
			
		||||
	UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
 | 
			
		||||
	// Time spent by tasks of the cgroup in user mode. Units: nanoseconds.
 | 
			
		||||
	// Time spent by tasks of the cgroup in user mode.
 | 
			
		||||
	// Units: nanoseconds.
 | 
			
		||||
	UsageInUsermode uint64 `json:"usage_in_usermode"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,8 @@ type Device struct {
 | 
			
		|||
	MinorNumber       int64       `json:"minor_number,omitempty"`       // Use the wildcard constant for wildcards.
 | 
			
		||||
	CgroupPermissions string      `json:"cgroup_permissions,omitempty"` // Typically just "rwm"
 | 
			
		||||
	FileMode          os.FileMode `json:"file_mode,omitempty"`          // The permission bits of the file's mode
 | 
			
		||||
	Uid               uint32      `json:"uid,omitempty"`
 | 
			
		||||
	Gid               uint32      `json:"gid,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetDeviceNumberString(deviceNumber int64) string {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +77,8 @@ func GetDevice(path, cgroupPermissions string) (*Device, error) {
 | 
			
		|||
		MinorNumber:       Minor(devNumber),
 | 
			
		||||
		CgroupPermissions: cgroupPermissions,
 | 
			
		||||
		FileMode:          fileModePermissionBits,
 | 
			
		||||
		Uid:               stat_t.Uid,
 | 
			
		||||
		Gid:               stat_t.Gid,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,20 @@
 | 
			
		|||
package libcontainer
 | 
			
		||||
 | 
			
		||||
type Factory interface {
 | 
			
		||||
	// Creates a new container in the given path. A unique ID is generated for the container and
 | 
			
		||||
	// starts the initial process inside the container.
 | 
			
		||||
 | 
			
		||||
	// Creates a new container with the given id and starts the initial process inside it.
 | 
			
		||||
	// id must be a string containing only letters, digits and underscores and must contain
 | 
			
		||||
	// between 1 and 1024 characters, inclusive.
 | 
			
		||||
	//
 | 
			
		||||
	// The id must not already be in use by an existing container. Containers created using
 | 
			
		||||
	// a factory with the same path (and file system) must have distinct ids.
 | 
			
		||||
	//
 | 
			
		||||
	// Returns the new container with a running process.
 | 
			
		||||
	//
 | 
			
		||||
	// Errors:
 | 
			
		||||
	// Path already exists
 | 
			
		||||
	// Config or initialConfig is invalid
 | 
			
		||||
	// id is already in use by a container
 | 
			
		||||
	// id has incorrect format
 | 
			
		||||
	// config is invalid
 | 
			
		||||
	// System error
 | 
			
		||||
	//
 | 
			
		||||
	// On error, any partially created container parts are cleaned up (the operation is atomic).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@ type Mount struct {
 | 
			
		|||
	Writable    bool   `json:"writable,omitempty"`
 | 
			
		||||
	Relabel     string `json:"relabel,omitempty"` // Relabel source if set, "z" indicates shared, "Z" indicates unshared
 | 
			
		||||
	Private     bool   `json:"private,omitempty"`
 | 
			
		||||
	Slave       bool   `json:"slave,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mount) Mount(rootfs, mountLabel string) error {
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +41,10 @@ func (m *Mount) bindMount(rootfs, mountLabel string) error {
 | 
			
		|||
		flags = flags | syscall.MS_RDONLY
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if m.Slave {
 | 
			
		||||
		flags = flags | syscall.MS_SLAVE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stat, err := os.Stat(m.Source)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,5 +48,10 @@ func CreateDeviceNode(rootfs string, node *devices.Device) error {
 | 
			
		|||
	if err := syscall.Mknod(dest, uint32(fileMode), devices.Mkdev(node.MajorNumber, node.MinorNumber)); err != nil && !os.IsExist(err) {
 | 
			
		||||
		return fmt.Errorf("mknod %s %s", node.Path, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := syscall.Chown(dest, int(node.Uid), int(node.Gid)); err != nil {
 | 
			
		||||
		return fmt.Errorf("chown %s to %d:%d", node.Path, node.Uid, node.Gid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,10 @@ func (s *SyncPipe) ReadFromParent(v interface{}) error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (s *SyncPipe) ReportChildError(err error) {
 | 
			
		||||
	// ensure that any data sent from the parent is consumed so it doesn't
 | 
			
		||||
	// receive ECONNRESET when the child writes to the pipe.
 | 
			
		||||
	ioutil.ReadAll(s.child)
 | 
			
		||||
 | 
			
		||||
	s.child.Write([]byte(err.Error()))
 | 
			
		||||
	s.CloseChild()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package syncpipe
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -20,9 +21,17 @@ func TestSendErrorFromChild(t *testing.T) {
 | 
			
		|||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	expected := "something bad happened"
 | 
			
		||||
	childfd, err := syscall.Dup(int(pipe.Child().Fd()))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	childPipe, _ := NewSyncPipeFromFd(0, uintptr(childfd))
 | 
			
		||||
 | 
			
		||||
	pipe.ReportChildError(fmt.Errorf(expected))
 | 
			
		||||
	pipe.CloseChild()
 | 
			
		||||
	pipe.SendToChild(nil)
 | 
			
		||||
 | 
			
		||||
	expected := "something bad happened"
 | 
			
		||||
	childPipe.ReportChildError(fmt.Errorf(expected))
 | 
			
		||||
 | 
			
		||||
	childError := pipe.ReadFromChild()
 | 
			
		||||
	if childError == nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue