diff --git a/hack/vendor.sh b/hack/vendor.sh index 48f46072b3..23c768e96a 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -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 84ad9386a0240acb7475429a835d826007032bf9 +clone git github.com/docker/libcontainer 185328a42654f6dc9a41814e57882f69d65f6ab7 # 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')" diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go index 443dbb698b..133241e472 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go @@ -24,6 +24,23 @@ var ( CgroupProcesses = "cgroup.procs" ) +// The absolute path to the root of the cgroup hierarchies. +var cgroupRoot string + +// TODO(vmarmol): Report error here, we'll probably need to wait for the new API. +func init() { + // we can pick any subsystem to find the root + cpuRoot, err := cgroups.FindCgroupMountpoint("cpu") + if err != nil { + return + } + cgroupRoot = filepath.Dir(cpuRoot) + + if _, err := os.Stat(cgroupRoot); err != nil { + return + } +} + type subsystem interface { // Returns the stats, as 'stats', corresponding to the cgroup under 'path'. GetStats(path string, stats *cgroups.Stats) error @@ -121,15 +138,8 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) { } func getCgroupData(c *cgroups.Cgroup, pid int) (*data, error) { - // we can pick any subsystem to find the root - cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu") - if err != nil { - return nil, err - } - cgroupRoot = filepath.Dir(cgroupRoot) - - if _, err := os.Stat(cgroupRoot); err != nil { - return nil, fmt.Errorf("cgroups fs not found") + if cgroupRoot == "" { + return nil, fmt.Errorf("failed to find the cgroup root") } cgroup := c.Name diff --git a/vendor/src/github.com/docker/libcontainer/container.go b/vendor/src/github.com/docker/libcontainer/container.go index ace997b77c..307e8cbcbb 100644 --- a/vendor/src/github.com/docker/libcontainer/container.go +++ b/vendor/src/github.com/docker/libcontainer/container.go @@ -14,58 +14,65 @@ type Container interface { // Returns the current run state of the container. // - // Errors: container no longer exists, - // system error. - RunState() (*RunState, error) + // Errors: + // ContainerDestroyed - Container no longer exists, + // SystemError - System error. + RunState() (*RunState, Error) // Returns the current config of the container. Config() *Config // Start a process inside the container. Returns the PID of the new process (in the caller process's namespace) and a channel that will return the exit status of the process whenever it dies. // - // Errors: container no longer exists, - // config is invalid, - // container is paused, - // system error. - Start(*ProcessConfig) (pid int, exitChan chan int, err error) + // Errors: + // ContainerDestroyed - Container no longer exists, + // ConfigInvalid - config is invalid, + // ContainerPaused - Container is paused, + // SystemError - System error. + Start(config *ProcessConfig) (pid int, exitChan chan int, err Error) // Destroys the container after killing all running processes. // // Any event registrations are removed before the container is destroyed. // No error is returned if the container is already destroyed. // - // Errors: system error. - Destroy() error + // Errors: + // SystemError - System error. + Destroy() Error // Returns the PIDs inside this container. The PIDs are in the namespace of the calling process. // - // Errors: container no longer exists, - // system error. + // Errors: + // ContainerDestroyed - Container no longer exists, + // SystemError - System error. // // Some of the returned PIDs may no longer refer to processes in the Container, unless // the Container state is PAUSED in which case every PID in the slice is valid. - Processes() ([]int, error) + Processes() ([]int, Error) // Returns statistics for the container. // - // Errors: container no longer exists, - // system error. - Stats() (*ContainerStats, error) + // Errors: + // ContainerDestroyed - Container no longer exists, + // SystemError - System error. + Stats() (*ContainerStats, Error) // If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses // the execution of any user processes. Asynchronously, when the container finished being paused the // state is changed to PAUSED. // If the Container state is PAUSED, do nothing. // - // Errors: container no longer exists, - // system error. - Pause() error + // Errors: + // ContainerDestroyed - Container no longer exists, + // SystemError - System error. + Pause() Error // If the Container state is PAUSED, resumes the execution of any user processes in the // Container before setting the Container state to RUNNING. // If the Container state is RUNNING, do nothing. // - // Errors: container no longer exists, - // system error. - Resume() error + // Errors: + // ContainerDestroyed - Container no longer exists, + // SystemError - System error. + Resume() Error } diff --git a/vendor/src/github.com/docker/libcontainer/devices/devices.go b/vendor/src/github.com/docker/libcontainer/devices/devices.go index beb558ccf7..558f7f5f9c 100644 --- a/vendor/src/github.com/docker/libcontainer/devices/devices.go +++ b/vendor/src/github.com/docker/libcontainer/devices/devices.go @@ -17,6 +17,12 @@ var ( ErrNotADeviceNode = errors.New("not a device node") ) +// Testing dependencies +var ( + osLstat = os.Lstat + ioutilReadDir = ioutil.ReadDir +) + type Device struct { Type rune `json:"type,omitempty"` Path string `json:"path,omitempty"` // It is fine if this is an empty string in the case that you are using Wildcards @@ -42,7 +48,7 @@ func (device *Device) GetCgroupAllowString() string { // Given the path to a device and it's cgroup_permissions(which cannot be easilly queried) look up the information about a linux device and return that information as a Device struct. func GetDevice(path, cgroupPermissions string) (*Device, error) { - fileInfo, err := os.Lstat(path) + fileInfo, err := osLstat(path) if err != nil { return nil, err } @@ -87,7 +93,7 @@ func GetHostDeviceNodes() ([]*Device, error) { } func getDeviceNodes(path string) ([]*Device, error) { - files, err := ioutil.ReadDir(path) + files, err := ioutilReadDir(path) if err != nil { return nil, err } diff --git a/vendor/src/github.com/docker/libcontainer/devices/devices_test.go b/vendor/src/github.com/docker/libcontainer/devices/devices_test.go new file mode 100644 index 0000000000..fec4002237 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/devices/devices_test.go @@ -0,0 +1,61 @@ +package devices + +import ( + "errors" + "os" + "testing" +) + +func TestGetDeviceLstatFailure(t *testing.T) { + testError := errors.New("test error") + + // Override os.Lstat to inject error. + osLstat = func(path string) (os.FileInfo, error) { + return nil, testError + } + + _, err := GetDevice("", "") + if err != testError { + t.Fatalf("Unexpected error %v, expected %v", err, testError) + } +} + +func TestGetHostDeviceNodesIoutilReadDirFailure(t *testing.T) { + testError := errors.New("test error") + + // Override ioutil.ReadDir to inject error. + ioutilReadDir = func(dirname string) ([]os.FileInfo, error) { + return nil, testError + } + + _, err := GetHostDeviceNodes() + if err != testError { + t.Fatalf("Unexpected error %v, expected %v", err, testError) + } +} + +func TestGetHostDeviceNodesIoutilReadDirDeepFailure(t *testing.T) { + testError := errors.New("test error") + called := false + + // Override ioutil.ReadDir to inject error after the first call. + ioutilReadDir = func(dirname string) ([]os.FileInfo, error) { + if called { + return nil, testError + } + called = true + + // Provoke a second call. + fi, err := os.Lstat("/tmp") + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + + return []os.FileInfo{fi}, nil + } + + _, err := GetHostDeviceNodes() + if err != testError { + t.Fatalf("Unexpected error %v, expected %v", err, testError) + } +} diff --git a/vendor/src/github.com/docker/libcontainer/error.go b/vendor/src/github.com/docker/libcontainer/error.go new file mode 100644 index 0000000000..5ff56d80ba --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/error.go @@ -0,0 +1,37 @@ +package libcontainer + +// API error code type. +type ErrorCode int + +// API error codes. +const ( + // Factory errors + IdInUse ErrorCode = iota + InvalidIdFormat + // TODO: add Load errors + + // Container errors + ContainerDestroyed + ContainerPaused + + // Common errors + ConfigInvalid + SystemError +) + +// API Error type. +type Error interface { + error + + // Returns the stack trace, if any, which identifies the + // point at which the error occurred. + Stack() []byte + + // Returns a verbose string including the error message + // and a representation of the stack trace suitable for + // printing. + Detail() string + + // Returns the error code for this error. + Code() ErrorCode +} diff --git a/vendor/src/github.com/docker/libcontainer/factory.go b/vendor/src/github.com/docker/libcontainer/factory.go index f4c31160c0..e37773b2bd 100644 --- a/vendor/src/github.com/docker/libcontainer/factory.go +++ b/vendor/src/github.com/docker/libcontainer/factory.go @@ -12,13 +12,13 @@ type Factory interface { // Returns the new container with a running process. // // Errors: - // id is already in use by a container - // id has incorrect format - // config is invalid - // System error + // IdInUse - id is already in use by a container + // InvalidIdFormat - id has incorrect format + // ConfigInvalid - config is invalid + // SystemError - System error // // On error, any partially created container parts are cleaned up (the operation is atomic). - Create(id string, config *Config) (Container, error) + Create(id string, config *Config) (Container, Error) // Load takes an ID for an existing container and reconstructs the container // from the state. @@ -27,5 +27,6 @@ type Factory interface { // Path does not exist // Container is stopped // System error - Load(id string) (Container, error) + // TODO: fix description + Load(id string) (Container, Error) } diff --git a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go index 215fb178a0..7517a6de9e 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go +++ b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go @@ -3,6 +3,8 @@ package netlink import ( "encoding/binary" "fmt" + "io" + "math/rand" "net" "sync/atomic" "syscall" @@ -38,12 +40,15 @@ type ifreqFlags struct { Ifruflags uint16 } -func nativeEndian() binary.ByteOrder { +var native binary.ByteOrder + +func init() { var x uint32 = 0x01020304 if *(*byte)(unsafe.Pointer(&x)) == 0x01 { - return binary.BigEndian + native = binary.BigEndian + } else { + native = binary.LittleEndian } - return binary.LittleEndian } func getIpFamily(ip net.IP) int { @@ -80,8 +85,6 @@ func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg { } func (msg *IfInfomsg) ToWireFormat() []byte { - native := nativeEndian() - length := syscall.SizeofIfInfomsg b := make([]byte, length) b[0] = msg.Family @@ -110,8 +113,6 @@ func newIfAddrmsg(family int) *IfAddrmsg { } func (msg *IfAddrmsg) ToWireFormat() []byte { - native := nativeEndian() - length := syscall.SizeofIfAddrmsg b := make([]byte, length) b[0] = msg.Family @@ -142,8 +143,6 @@ func newRtMsg() *RtMsg { } func (msg *RtMsg) ToWireFormat() []byte { - native := nativeEndian() - length := syscall.SizeofRtMsg b := make([]byte, length) b[0] = msg.Family @@ -202,8 +201,6 @@ func (a *RtAttr) Len() int { } func (a *RtAttr) ToWireFormat() []byte { - native := nativeEndian() - length := a.Len() buf := make([]byte, rtaAlignOf(length)) @@ -225,14 +222,18 @@ func (a *RtAttr) ToWireFormat() []byte { return buf } +func uint32Attr(t int, n uint32) *RtAttr { + buf := make([]byte, 4) + native.PutUint32(buf, n) + return newRtAttr(t, buf) +} + type NetlinkRequest struct { syscall.NlMsghdr Data []NetlinkRequestData } func (rr *NetlinkRequest) ToWireFormat() []byte { - native := nativeEndian() - length := rr.Len dataBytes := make([][]byte, len(rr.Data)) for i, data := range rr.Data { @@ -329,36 +330,44 @@ func (s *NetlinkSocket) GetPid() (uint32, error) { return 0, ErrWrongSockType } -func (s *NetlinkSocket) HandleAck(seq uint32) error { - native := nativeEndian() +func (s *NetlinkSocket) CheckMessage(m syscall.NetlinkMessage, seq, pid uint32) error { + if m.Header.Seq != seq { + return fmt.Errorf("netlink: invalid seq %d, expected %d", m.Header.Seq, seq) + } + if m.Header.Pid != pid { + return fmt.Errorf("netlink: wrong pid %d, expected %d", m.Header.Pid, pid) + } + if m.Header.Type == syscall.NLMSG_DONE { + return io.EOF + } + if m.Header.Type == syscall.NLMSG_ERROR { + e := int32(native.Uint32(m.Data[0:4])) + if e == 0 { + return io.EOF + } + return syscall.Errno(-e) + } + return nil +} +func (s *NetlinkSocket) HandleAck(seq uint32) error { pid, err := s.GetPid() if err != nil { return err } -done: +outer: for { msgs, err := s.Receive() if err != nil { return err } for _, m := range msgs { - if m.Header.Seq != seq { - return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, seq) - } - if m.Header.Pid != pid { - return fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid) - } - if m.Header.Type == syscall.NLMSG_DONE { - break done - } - if m.Header.Type == syscall.NLMSG_ERROR { - error := int32(native.Uint32(m.Data[0:4])) - if error == 0 { - break done + if err := s.CheckMessage(m, seq, pid); err != nil { + if err == io.EOF { + break outer } - return syscall.Errno(-error) + return err } } } @@ -454,17 +463,11 @@ func AddRoute(destination, source, gateway, device string) error { wb.AddData(attr) } - var ( - native = nativeEndian() - b = make([]byte, 4) - ) iface, err := net.InterfaceByName(device) if err != nil { return err } - native.PutUint32(b, uint32(iface.Index)) - - wb.AddData(newRtAttr(syscall.RTA_OIF, b)) + wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index))) if err := s.Send(wb); err != nil { return err @@ -538,15 +541,7 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error { msg.Index = int32(iface.Index) msg.Change = DEFAULT_CHANGE wb.AddData(msg) - - var ( - b = make([]byte, 4) - native = nativeEndian() - ) - native.PutUint32(b, uint32(mtu)) - - data := newRtAttr(syscall.IFLA_MTU, b) - wb.AddData(data) + wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu))) if err := s.Send(wb); err != nil { return err @@ -570,15 +565,7 @@ func NetworkSetMaster(iface, master *net.Interface) error { msg.Index = int32(iface.Index) msg.Change = DEFAULT_CHANGE wb.AddData(msg) - - var ( - b = make([]byte, 4) - native = nativeEndian() - ) - native.PutUint32(b, uint32(master.Index)) - - data := newRtAttr(syscall.IFLA_MASTER, b) - wb.AddData(data) + wb.AddData(uint32Attr(syscall.IFLA_MASTER, uint32(master.Index))) if err := s.Send(wb); err != nil { return err @@ -602,15 +589,7 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error { msg.Index = int32(iface.Index) msg.Change = DEFAULT_CHANGE wb.AddData(msg) - - var ( - b = make([]byte, 4) - native = nativeEndian() - ) - native.PutUint32(b, uint32(nspid)) - - data := newRtAttr(syscall.IFLA_NET_NS_PID, b) - wb.AddData(data) + wb.AddData(uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid))) if err := s.Send(wb); err != nil { return err @@ -634,15 +613,7 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error { msg.Index = int32(iface.Index) msg.Change = DEFAULT_CHANGE wb.AddData(msg) - - var ( - b = make([]byte, 4) - native = nativeEndian() - ) - native.PutUint32(b, uint32(fd)) - - data := newRtAttr(IFLA_NET_NS_FD, b) - wb.AddData(data) + wb.AddData(uint32Attr(IFLA_NET_NS_FD, uint32(fd))) if err := s.Send(wb); err != nil { return err @@ -782,8 +753,6 @@ func NetworkLinkDel(name string) error { // Returns an array of IPNet for all the currently routed subnets on ipv4 // This is similar to the first column of "ip route" output func NetworkGetRoutes() ([]Route, error) { - native := nativeEndian() - s, err := getNetlinkSocket() if err != nil { return nil, err @@ -806,28 +775,18 @@ func NetworkGetRoutes() ([]Route, error) { res := make([]Route, 0) -done: +outer: for { msgs, err := s.Receive() if err != nil { return nil, err } for _, m := range msgs { - if m.Header.Seq != wb.Seq { - return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq) - } - if m.Header.Pid != pid { - return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid) - } - if m.Header.Type == syscall.NLMSG_DONE { - break done - } - if m.Header.Type == syscall.NLMSG_ERROR { - error := int32(native.Uint32(m.Data[0:4])) - if error == 0 { - break done + if err := s.CheckMessage(m, wb.Seq, pid); err != nil { + if err == io.EOF { + break outer } - return nil, syscall.Errno(-error) + return nil, err } if m.Header.Type != syscall.RTM_NEWROUTE { continue @@ -974,7 +933,7 @@ func CreateBridge(name string, setMacAddr bool) error { return err } if setMacAddr { - return setBridgeMacAddress(s, name) + return NetworkSetMacAddress(name, randMacAddr()) } return nil } @@ -1030,22 +989,40 @@ func AddToBridge(iface, master *net.Interface) error { return nil } -func setBridgeMacAddress(s int, name string) error { +func randMacAddr() string { + hw := make(net.HardwareAddr, 6) + for i := 0; i < 6; i++ { + hw[i] = byte(rand.Intn(255)) + } + hw[0] &^= 0x1 // clear multicast bit + hw[0] |= 0x2 // set local assignment bit (IEEE802) + return hw.String() +} + +func NetworkSetMacAddress(name, addr string) error { if len(name) >= IFNAMSIZ { return fmt.Errorf("Interface name %s too long", name) } + hw, err := net.ParseMAC(addr) + if err != nil { + return err + } + + s, err := getIfSocket() + if err != nil { + return err + } + defer syscall.Close(s) + ifr := ifreqHwaddr{} ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name) for i := 0; i < 6; i++ { - ifr.IfruHwaddr.Data[i] = randIfrDataByte() + ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i]) } - ifr.IfruHwaddr.Data[0] &^= 0x1 // clear multicast bit - ifr.IfruHwaddr.Data[0] |= 0x2 // set local assignment bit (IEEE802) - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 { return err } diff --git a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go index 7789ae275a..779e58a771 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go +++ b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go @@ -1,9 +1,5 @@ package netlink -import ( - "math/rand" -) - -func randIfrDataByte() uint8 { - return uint8(rand.Intn(255)) +func ifrDataByte(b byte) uint8 { + return uint8(b) } diff --git a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go index 23c4a92712..f151722a1b 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go +++ b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go @@ -2,10 +2,6 @@ package netlink -import ( - "math/rand" -) - -func randIfrDataByte() int8 { - return int8(rand.Intn(255)) +func ifrDataByte(b byte) int8 { + return int8(b) } diff --git a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go index 086aee7f0b..6c596ed9ff 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go +++ b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go @@ -115,6 +115,7 @@ func TestCreateVethPair(t *testing.T) { if err := NetworkCreateVethPair(name1, name2); err != nil { t.Fatal(err) } + defer NetworkLinkDel(name1) if _, err := net.InterfaceByName(name1); err != nil { t.Fatal(err) @@ -124,3 +125,30 @@ func TestCreateVethPair(t *testing.T) { t.Fatal(err) } } + +func TestSetMACAddress(t *testing.T) { + if testing.Short() { + return + } + + name := "testmac" + mac := randMacAddr() + + if err := NetworkLinkAdd(name, "bridge"); err != nil { + t.Fatal(err) + } + defer NetworkLinkDel(name) + + if err := NetworkSetMacAddress(name, mac); err != nil { + t.Fatal(err) + } + + iface, err := net.InterfaceByName(name) + if err != nil { + t.Fatal(err) + } + + if iface.HardwareAddr.String() != mac { + t.Fatalf("mac address %q does not match %q", iface.HardwareAddr, mac) + } +}