зеркало из https://github.com/microsoft/docker.git
Merge pull request #8293 from crosbymichael/update-libcontainer-sep8
Update libcontainer to c744f6470e37be5ce1f1ae09b842c15c1bee120d
This commit is contained in:
Коммит
07179a7eb1
|
@ -30,6 +30,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e
|
||||||
container.Cgroups.Name = c.ID
|
container.Cgroups.Name = c.ID
|
||||||
container.Cgroups.AllowedDevices = c.AllowedDevices
|
container.Cgroups.AllowedDevices = c.AllowedDevices
|
||||||
container.MountConfig.DeviceNodes = c.AutoCreatedDevices
|
container.MountConfig.DeviceNodes = c.AutoCreatedDevices
|
||||||
|
container.RootFs = c.Rootfs
|
||||||
|
|
||||||
// check to see if we are running in ramdisk to disable pivot root
|
// check to see if we are running in ramdisk to disable pivot root
|
||||||
container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
||||||
|
|
|
@ -100,7 +100,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return namespaces.Exec(container, c.ProcessConfig.Stdin, c.ProcessConfig.Stdout, c.ProcessConfig.Stderr, c.ProcessConfig.Console, c.Rootfs, dataPath, args, func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd {
|
return namespaces.Exec(container, c.ProcessConfig.Stdin, c.ProcessConfig.Stdout, c.ProcessConfig.Stderr, c.ProcessConfig.Console, dataPath, args, func(container *libcontainer.Config, console, dataPath, init string, child *os.File, args []string) *exec.Cmd {
|
||||||
c.ProcessConfig.Path = d.initPath
|
c.ProcessConfig.Path = d.initPath
|
||||||
c.ProcessConfig.Args = append([]string{
|
c.ProcessConfig.Args = append([]string{
|
||||||
DriverName,
|
DriverName,
|
||||||
|
@ -117,7 +117,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||||
c.ProcessConfig.ExtraFiles = []*os.File{child}
|
c.ProcessConfig.ExtraFiles = []*os.File{child}
|
||||||
|
|
||||||
c.ProcessConfig.Env = container.Env
|
c.ProcessConfig.Env = container.Env
|
||||||
c.ProcessConfig.Dir = c.Rootfs
|
c.ProcessConfig.Dir = container.RootFs
|
||||||
|
|
||||||
return &c.ProcessConfig.Cmd
|
return &c.ProcessConfig.Cmd
|
||||||
}, func() {
|
}, func() {
|
||||||
|
|
|
@ -64,7 +64,7 @@ if [ "$1" = '--go' ]; then
|
||||||
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
|
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
|
||||||
fi
|
fi
|
||||||
|
|
||||||
clone git github.com/docker/libcontainer 185328a42654f6dc9a41814e57882f69d65f6ab7
|
clone git github.com/docker/libcontainer c744f6470e37be5ce1f1ae09b842c15c1bee120d
|
||||||
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
|
# 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
|
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')"
|
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
|
||||||
|
|
|
@ -40,7 +40,7 @@ func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
totalUsage, err := getCgroupParamInt(path, "cpuacct.usage")
|
totalUsage, err := getCgroupParamUint(path, "cpuacct.usage")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -66,25 +67,25 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||||
for sc.Scan() {
|
for sc.Scan() {
|
||||||
t, v, err := getCgroupParamKeyValue(sc.Text())
|
t, v, err := getCgroupParamKeyValue(sc.Text())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err)
|
||||||
}
|
}
|
||||||
stats.MemoryStats.Stats[t] = v
|
stats.MemoryStats.Stats[t] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set memory usage and max historical usage.
|
// Set memory usage and max historical usage.
|
||||||
value, err := getCgroupParamInt(path, "memory.usage_in_bytes")
|
value, err := getCgroupParamUint(path, "memory.usage_in_bytes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to parse memory.usage_in_bytes - %v", err)
|
||||||
}
|
}
|
||||||
stats.MemoryStats.Usage = value
|
stats.MemoryStats.Usage = value
|
||||||
value, err = getCgroupParamInt(path, "memory.max_usage_in_bytes")
|
value, err = getCgroupParamUint(path, "memory.max_usage_in_bytes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to parse memory.max_usage_in_bytes - %v", err)
|
||||||
}
|
}
|
||||||
stats.MemoryStats.MaxUsage = value
|
stats.MemoryStats.MaxUsage = value
|
||||||
value, err = getCgroupParamInt(path, "memory.failcnt")
|
value, err = getCgroupParamUint(path, "memory.failcnt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to parse memory.failcnt - %v", err)
|
||||||
}
|
}
|
||||||
stats.MemoryStats.Failcnt = value
|
stats.MemoryStats.Failcnt = value
|
||||||
|
|
||||||
|
|
|
@ -14,27 +14,49 @@ var (
|
||||||
ErrNotValidFormat = errors.New("line is not a valid key value format")
|
ErrNotValidFormat = errors.New("line is not a valid key value format")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Saturates negative values at zero and returns a uint64.
|
||||||
|
// Due to kernel bugs, some of the memory cgroup stats can be negative.
|
||||||
|
func parseUint(s string, base, bitSize int) (uint64, error) {
|
||||||
|
value, err := strconv.ParseUint(s, base, bitSize)
|
||||||
|
if err != nil {
|
||||||
|
intValue, intErr := strconv.ParseInt(s, base, bitSize)
|
||||||
|
// 1. Handle negative values greater than MinInt64 (and)
|
||||||
|
// 2. Handle negative values lesser than MinInt64
|
||||||
|
if intErr == nil && intValue < 0 {
|
||||||
|
return 0, nil
|
||||||
|
} else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Parses a cgroup param and returns as name, value
|
// Parses a cgroup param and returns as name, value
|
||||||
// i.e. "io_service_bytes 1234" will return as io_service_bytes, 1234
|
// i.e. "io_service_bytes 1234" will return as io_service_bytes, 1234
|
||||||
func getCgroupParamKeyValue(t string) (string, uint64, error) {
|
func getCgroupParamKeyValue(t string) (string, uint64, error) {
|
||||||
parts := strings.Fields(t)
|
parts := strings.Fields(t)
|
||||||
switch len(parts) {
|
switch len(parts) {
|
||||||
case 2:
|
case 2:
|
||||||
value, err := strconv.ParseUint(parts[1], 10, 64)
|
value, err := parseUint(parts[1], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, fmt.Errorf("Unable to convert param value to uint64: %s", err)
|
return "", 0, fmt.Errorf("Unable to convert param value (%q) to uint64: %v", parts[1], err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return parts[0], value, nil
|
return parts[0], value, nil
|
||||||
default:
|
default:
|
||||||
return "", 0, ErrNotValidFormat
|
return "", 0, ErrNotValidFormat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a single int64 value from the specified cgroup file.
|
// Gets a single uint64 value from the specified cgroup file.
|
||||||
func getCgroupParamInt(cgroupPath, cgroupFile string) (uint64, error) {
|
func getCgroupParamUint(cgroupPath, cgroupFile string) (uint64, error) {
|
||||||
contents, err := ioutil.ReadFile(filepath.Join(cgroupPath, cgroupFile))
|
contents, err := ioutil.ReadFile(filepath.Join(cgroupPath, cgroupFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return strconv.ParseUint(strings.TrimSpace(string(contents)), 10, 64)
|
|
||||||
|
return parseUint(strings.TrimSpace(string(contents)), 10, 64)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,10 @@ package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,7 +29,7 @@ func TestGetCgroupParamsInt(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
value, err := getCgroupParamInt(tempDir, cgroupFile)
|
value, err := getCgroupParamUint(tempDir, cgroupFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if value != floatValue {
|
} else if value != floatValue {
|
||||||
|
@ -39,19 +41,44 @@ func TestGetCgroupParamsInt(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
value, err = getCgroupParamInt(tempDir, cgroupFile)
|
value, err = getCgroupParamUint(tempDir, cgroupFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if value != floatValue {
|
} else if value != floatValue {
|
||||||
t.Fatalf("Expected %d to equal %f", value, floatValue)
|
t.Fatalf("Expected %d to equal %f", value, floatValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Success with negative values
|
||||||
|
err = ioutil.WriteFile(tempFile, []byte("-12345"), 0755)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
value, err = getCgroupParamUint(tempDir, cgroupFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if value != 0 {
|
||||||
|
t.Fatalf("Expected %d to equal %f", value, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success with negative values lesser than min int64
|
||||||
|
s := strconv.FormatFloat(math.MinInt64, 'f', -1, 64)
|
||||||
|
err = ioutil.WriteFile(tempFile, []byte(s), 0755)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
value, err = getCgroupParamUint(tempDir, cgroupFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if value != 0 {
|
||||||
|
t.Fatalf("Expected %d to equal %f", value, 0)
|
||||||
|
}
|
||||||
|
|
||||||
// Not a float.
|
// Not a float.
|
||||||
err = ioutil.WriteFile(tempFile, []byte("not-a-float"), 0755)
|
err = ioutil.WriteFile(tempFile, []byte("not-a-float"), 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = getCgroupParamInt(tempDir, cgroupFile)
|
_, err = getCgroupParamUint(tempDir, cgroupFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Expecting error, got none")
|
t.Fatal("Expecting error, got none")
|
||||||
}
|
}
|
||||||
|
@ -61,7 +88,7 @@ func TestGetCgroupParamsInt(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = getCgroupParamInt(tempDir, cgroupFile)
|
_, err = getCgroupParamUint(tempDir, cgroupFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Expecting error, got none")
|
t.Fatal("Expecting error, got none")
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@ type Config struct {
|
||||||
// Mount specific options.
|
// Mount specific options.
|
||||||
MountConfig *MountConfig `json:"mount_config,omitempty"`
|
MountConfig *MountConfig `json:"mount_config,omitempty"`
|
||||||
|
|
||||||
|
// Pathname to container's root filesystem
|
||||||
|
RootFs string `json:"root_fs,omitempty"`
|
||||||
|
|
||||||
// Hostname optionally sets the container's hostname if provided
|
// Hostname optionally sets the container's hostname if provided
|
||||||
Hostname string `json:"hostname,omitempty"`
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
|
||||||
|
|
|
@ -7,4 +7,4 @@ import (
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateCommand func(container *libcontainer.Config, console, rootfs, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd
|
type CreateCommand func(container *libcontainer.Config, console, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
// Move this to libcontainer package.
|
// Move this to libcontainer package.
|
||||||
// Exec performs setup outside of a namespace so that a container can be
|
// Exec performs setup outside of a namespace so that a container can be
|
||||||
// executed. Exec is a high level function for working with container namespaces.
|
// executed. Exec is a high level function for working with container namespaces.
|
||||||
func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Writer, console string, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
|
func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Writer, console, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
@ -34,7 +34,7 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
|
||||||
}
|
}
|
||||||
defer syncPipe.Close()
|
defer syncPipe.Close()
|
||||||
|
|
||||||
command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.Child(), args)
|
command := createCommand(container, console, dataPath, os.Args[0], syncPipe.Child(), args)
|
||||||
// Note: these are only used in non-tty mode
|
// Note: these are only used in non-tty mode
|
||||||
// if there is a tty for the container it will be opened within the namespace and the
|
// if there is a tty for the container it will be opened within the namespace and the
|
||||||
// fds will be duped to stdin, stdiout, and stderr
|
// fds will be duped to stdin, stdiout, and stderr
|
||||||
|
@ -121,7 +121,7 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
|
||||||
// root: the path to the container json file and information
|
// root: the path to the container json file and information
|
||||||
// pipe: sync pipe to synchronize the parent and child processes
|
// pipe: sync pipe to synchronize the parent and child processes
|
||||||
// args: the arguments to pass to the container to run as the user's program
|
// args: the arguments to pass to the container to run as the user's program
|
||||||
func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
func DefaultCreateCommand(container *libcontainer.Config, console, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
||||||
// get our binary name from arg0 so we can always reexec ourself
|
// get our binary name from arg0 so we can always reexec ourself
|
||||||
env := []string{
|
env := []string{
|
||||||
"console=" + console,
|
"console=" + console,
|
||||||
|
@ -141,7 +141,7 @@ func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataP
|
||||||
|
|
||||||
command := exec.Command(init, append([]string{"init", "--"}, args...)...)
|
command := exec.Command(init, append([]string{"init", "--"}, args...)...)
|
||||||
// make sure the process is executed inside the context of the rootfs
|
// make sure the process is executed inside the context of the rootfs
|
||||||
command.Dir = rootfs
|
command.Dir = container.RootFs
|
||||||
command.Env = append(os.Environ(), env...)
|
command.Env = append(os.Environ(), env...)
|
||||||
|
|
||||||
if command.SysProcAttr == nil {
|
if command.SysProcAttr == nil {
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -3,9 +3,50 @@ package netlink
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type testLink struct {
|
||||||
|
name string
|
||||||
|
linkType string
|
||||||
|
}
|
||||||
|
|
||||||
|
func addLink(t *testing.T, name string, linkType string) {
|
||||||
|
if err := NetworkLinkAdd(name, linkType); err != nil {
|
||||||
|
t.Fatalf("Unable to create %s link: %s", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readLink(t *testing.T, name string) *net.Interface {
|
||||||
|
iface, err := net.InterfaceByName(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not find %s interface: %s", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return iface
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteLink(t *testing.T, name string) {
|
||||||
|
if err := NetworkLinkDel(name); err != nil {
|
||||||
|
t.Fatalf("Unable to delete %s link: %s", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func upLink(t *testing.T, name string) {
|
||||||
|
iface := readLink(t, name)
|
||||||
|
if err := NetworkLinkUp(iface); err != nil {
|
||||||
|
t.Fatalf("Could not bring UP %#v interface: %s", iface, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func downLink(t *testing.T, name string) {
|
||||||
|
iface := readLink(t, name)
|
||||||
|
if err := NetworkLinkDown(iface); err != nil {
|
||||||
|
t.Fatalf("Could not bring DOWN %#v interface: %s", iface, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ipAssigned(iface *net.Interface, ip net.IP) bool {
|
func ipAssigned(iface *net.Interface, ip net.IP) bool {
|
||||||
addrs, _ := iface.Addrs()
|
addrs, _ := iface.Addrs()
|
||||||
|
|
||||||
|
@ -19,6 +60,194 @@ func ipAssigned(iface *net.Interface, ip net.IP) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNetworkLinkAddDel(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
testLinks := []testLink{
|
||||||
|
{"tstEth", "dummy"},
|
||||||
|
{"tstBr", "bridge"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tl := range testLinks {
|
||||||
|
addLink(t, tl.name, tl.linkType)
|
||||||
|
defer deleteLink(t, tl.name)
|
||||||
|
readLink(t, tl.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkLinkUpDown(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||||
|
|
||||||
|
addLink(t, tl.name, tl.linkType)
|
||||||
|
defer deleteLink(t, tl.name)
|
||||||
|
|
||||||
|
upLink(t, tl.name)
|
||||||
|
ifcAfterUp := readLink(t, tl.name)
|
||||||
|
|
||||||
|
if (ifcAfterUp.Flags & syscall.IFF_UP) != syscall.IFF_UP {
|
||||||
|
t.Fatalf("Could not bring UP %#v initerface", tl)
|
||||||
|
}
|
||||||
|
|
||||||
|
downLink(t, tl.name)
|
||||||
|
ifcAfterDown := readLink(t, tl.name)
|
||||||
|
|
||||||
|
if (ifcAfterDown.Flags & syscall.IFF_UP) == syscall.IFF_UP {
|
||||||
|
t.Fatalf("Could not bring DOWN %#v initerface", tl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkSetMacAddress(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||||
|
macaddr := "22:ce:e0:99:63:6f"
|
||||||
|
|
||||||
|
addLink(t, tl.name, tl.linkType)
|
||||||
|
defer deleteLink(t, tl.name)
|
||||||
|
|
||||||
|
ifcBeforeSet := readLink(t, tl.name)
|
||||||
|
|
||||||
|
if err := NetworkSetMacAddress(ifcBeforeSet, macaddr); err != nil {
|
||||||
|
t.Fatalf("Could not set %s MAC address on %#v interface: err", macaddr, tl, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ifcAfterSet := readLink(t, tl.name)
|
||||||
|
|
||||||
|
if ifcAfterSet.HardwareAddr.String() != macaddr {
|
||||||
|
t.Fatalf("Could not set %s MAC address on %#v interface", macaddr, tl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkSetMTU(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||||
|
mtu := 1400
|
||||||
|
|
||||||
|
addLink(t, tl.name, tl.linkType)
|
||||||
|
defer deleteLink(t, tl.name)
|
||||||
|
|
||||||
|
ifcBeforeSet := readLink(t, tl.name)
|
||||||
|
|
||||||
|
if err := NetworkSetMTU(ifcBeforeSet, mtu); err != nil {
|
||||||
|
t.Fatalf("Could not set %d MTU on %#v interface: err", mtu, tl, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ifcAfterSet := readLink(t, tl.name)
|
||||||
|
|
||||||
|
if ifcAfterSet.MTU != mtu {
|
||||||
|
t.Fatalf("Could not set %d MTU on %#v interface", mtu, tl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkSetMasterNoMaster(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
master := testLink{"tstBr", "bridge"}
|
||||||
|
slave := testLink{"tstEth", "dummy"}
|
||||||
|
testLinks := []testLink{master, slave}
|
||||||
|
|
||||||
|
for _, tl := range testLinks {
|
||||||
|
addLink(t, tl.name, tl.linkType)
|
||||||
|
defer deleteLink(t, tl.name)
|
||||||
|
upLink(t, tl.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
masterIfc := readLink(t, master.name)
|
||||||
|
slaveIfc := readLink(t, slave.name)
|
||||||
|
if err := NetworkSetMaster(slaveIfc, masterIfc); err != nil {
|
||||||
|
t.Fatalf("Could not set %#v to be the master of %#v: %s", master, slave, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trying to figure out a way to test which will not break on RHEL6.
|
||||||
|
// We could check for existence of /sys/class/net/tstEth/upper_tstBr
|
||||||
|
// which should point to the ../tstBr which is the UPPER device i.e. network bridge
|
||||||
|
|
||||||
|
if err := NetworkSetNoMaster(slaveIfc); err != nil {
|
||||||
|
t.Fatalf("Could not UNset %#v master of %#v: %s", master, slave, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkChangeName(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tl := testLink{"tstEth", "dummy"}
|
||||||
|
newName := "newTst"
|
||||||
|
|
||||||
|
addLink(t, tl.name, tl.linkType)
|
||||||
|
|
||||||
|
linkIfc := readLink(t, tl.name)
|
||||||
|
if err := NetworkChangeName(linkIfc, newName); err != nil {
|
||||||
|
deleteLink(t, tl.name)
|
||||||
|
t.Fatalf("Could not change %#v interface name to %s: %s", tl, newName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
readLink(t, newName)
|
||||||
|
deleteLink(t, newName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkLinkAddVlan(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tl := struct {
|
||||||
|
name string
|
||||||
|
id uint16
|
||||||
|
}{
|
||||||
|
name: "tstVlan",
|
||||||
|
id: 32,
|
||||||
|
}
|
||||||
|
masterLink := testLink{"tstEth", "dummy"}
|
||||||
|
|
||||||
|
addLink(t, masterLink.name, masterLink.linkType)
|
||||||
|
defer deleteLink(t, masterLink.name)
|
||||||
|
|
||||||
|
if err := NetworkLinkAddVlan(masterLink.name, tl.name, tl.id); err != nil {
|
||||||
|
t.Fatalf("Unable to create %#v VLAN interface: %s", tl, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
readLink(t, tl.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkLinkAddMacVlan(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tl := struct {
|
||||||
|
name string
|
||||||
|
mode string
|
||||||
|
}{
|
||||||
|
name: "tstVlan",
|
||||||
|
mode: "private",
|
||||||
|
}
|
||||||
|
masterLink := testLink{"tstEth", "dummy"}
|
||||||
|
|
||||||
|
addLink(t, masterLink.name, masterLink.linkType)
|
||||||
|
defer deleteLink(t, masterLink.name)
|
||||||
|
|
||||||
|
if err := NetworkLinkAddMacVlan(masterLink.name, tl.name, tl.mode); err != nil {
|
||||||
|
t.Fatalf("Unable to create %#v MAC VLAN interface: %s", tl, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
readLink(t, tl.name)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAddDelNetworkIp(t *testing.T) {
|
func TestAddDelNetworkIp(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
return
|
return
|
||||||
|
@ -35,7 +264,7 @@ func TestAddDelNetworkIp(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ipAssigned(iface, ip) {
|
if !ipAssigned(iface, ip) {
|
||||||
|
@ -43,7 +272,7 @@ func TestAddDelNetworkIp(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil {
|
if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatalf("Could not delete IP address %s from interface %#v: %s", ip.String(), iface, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ipAssigned(iface, ip) {
|
if ipAssigned(iface, ip) {
|
||||||
|
@ -51,6 +280,28 @@ func TestAddDelNetworkIp(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateVethPair(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
name1 = "veth1"
|
||||||
|
name2 = "veth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := NetworkCreateVethPair(name1, name2); err != nil {
|
||||||
|
t.Fatalf("Could not create veth pair %s %s: %s", name1, name2, err)
|
||||||
|
}
|
||||||
|
defer NetworkLinkDel(name1)
|
||||||
|
|
||||||
|
readLink(t, name1)
|
||||||
|
readLink(t, name2)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// netlink package tests which do not use RTNETLINK
|
||||||
|
//
|
||||||
func TestCreateBridgeWithMac(t *testing.T) {
|
func TestCreateBridgeWithMac(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
return
|
return
|
||||||
|
@ -77,55 +328,6 @@ func TestCreateBridgeWithMac(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateBridgeLink(t *testing.T) {
|
|
||||||
if testing.Short() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
name := "mybrlink"
|
|
||||||
|
|
||||||
if err := NetworkLinkAdd(name, "bridge"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := net.InterfaceByName(name); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := NetworkLinkDel(name); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := net.InterfaceByName(name); err == nil {
|
|
||||||
t.Fatalf("expected error getting interface because %s bridge was deleted", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateVethPair(t *testing.T) {
|
|
||||||
if testing.Short() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
name1 = "veth1"
|
|
||||||
name2 = "veth2"
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := NetworkCreateVethPair(name1, name2); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer NetworkLinkDel(name1)
|
|
||||||
|
|
||||||
if _, err := net.InterfaceByName(name1); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := net.InterfaceByName(name2); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetMACAddress(t *testing.T) {
|
func TestSetMACAddress(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
return
|
return
|
||||||
|
@ -139,7 +341,7 @@ func TestSetMACAddress(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer NetworkLinkDel(name)
|
defer NetworkLinkDel(name)
|
||||||
|
|
||||||
if err := NetworkSetMacAddress(name, mac); err != nil {
|
if err := SetMacAddress(name, mac); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,10 @@ func (v *NetNS) Initialize(config *Network, networkState *NetworkState) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := system.Setns(f.Fd(), syscall.CLONE_NEWNET); err != nil {
|
if err := system.Setns(f.Fd(), syscall.CLONE_NEWNET); err != nil {
|
||||||
|
f.Close()
|
||||||
return fmt.Errorf("failed to setns current network namespace: %v", err)
|
return fmt.Errorf("failed to setns current network namespace: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,18 @@ type Network struct {
|
||||||
// Prefix for the veth interfaces.
|
// Prefix for the veth interfaces.
|
||||||
VethPrefix string `json:"veth_prefix,omitempty"`
|
VethPrefix string `json:"veth_prefix,omitempty"`
|
||||||
|
|
||||||
// Address contains the IP and mask to set on the network interface
|
// Address contains the IPv4 and mask to set on the network interface
|
||||||
Address string `json:"address,omitempty"`
|
Address string `json:"address,omitempty"`
|
||||||
|
|
||||||
|
// IPv6Address contains the IPv6 and mask to set on the network interface
|
||||||
|
IPv6Address string `json:"ipv6_address,omitempty"`
|
||||||
|
|
||||||
// Gateway sets the gateway address that is used as the default for the interface
|
// Gateway sets the gateway address that is used as the default for the interface
|
||||||
Gateway string `json:"gateway,omitempty"`
|
Gateway string `json:"gateway,omitempty"`
|
||||||
|
|
||||||
|
// IPv6Gateway sets the ipv6 gateway address that is used as the default for the interface
|
||||||
|
IPv6Gateway string `json:"ipv6_gateway,omitempty"`
|
||||||
|
|
||||||
// Mtu sets the mtu value for the interface and will be mirrored on both the host and
|
// Mtu sets the mtu value for the interface and will be mirrored on both the host and
|
||||||
// container's interfaces if a pair is created, specifically in the case of type veth
|
// container's interfaces if a pair is created, specifically in the case of type veth
|
||||||
// Note: This does not apply to loopback interfaces.
|
// Note: This does not apply to loopback interfaces.
|
||||||
|
|
|
@ -63,6 +63,12 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error {
|
||||||
if err := SetInterfaceIp(defaultDevice, config.Address); err != nil {
|
if err := SetInterfaceIp(defaultDevice, config.Address); err != nil {
|
||||||
return fmt.Errorf("set %s ip %s", defaultDevice, err)
|
return fmt.Errorf("set %s ip %s", defaultDevice, err)
|
||||||
}
|
}
|
||||||
|
if config.IPv6Address != "" {
|
||||||
|
if err := SetInterfaceIp(defaultDevice, config.IPv6Address); err != nil {
|
||||||
|
return fmt.Errorf("set %s ipv6 %s", defaultDevice, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := SetMtu(defaultDevice, config.Mtu); err != nil {
|
if err := SetMtu(defaultDevice, config.Mtu); err != nil {
|
||||||
return fmt.Errorf("set %s mtu to %d %s", defaultDevice, config.Mtu, err)
|
return fmt.Errorf("set %s mtu to %d %s", defaultDevice, config.Mtu, err)
|
||||||
}
|
}
|
||||||
|
@ -74,6 +80,11 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error {
|
||||||
return fmt.Errorf("set gateway to %s on device %s failed with %s", config.Gateway, defaultDevice, err)
|
return fmt.Errorf("set gateway to %s on device %s failed with %s", config.Gateway, defaultDevice, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if config.IPv6Gateway != "" {
|
||||||
|
if err := SetDefaultGateway(config.IPv6Gateway, defaultDevice); err != nil {
|
||||||
|
return fmt.Errorf("set gateway for ipv6 to %s on device %s failed with %s", config.IPv6Gateway, defaultDevice, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,8 +135,8 @@ func startContainer(container *libcontainer.Config, dataPath string, args []stri
|
||||||
|
|
||||||
signal.Notify(sigc)
|
signal.Notify(sigc)
|
||||||
|
|
||||||
createCommand := func(container *libcontainer.Config, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
createCommand := func(container *libcontainer.Config, console, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
||||||
cmd = namespaces.DefaultCreateCommand(container, console, rootfs, dataPath, init, pipe, args)
|
cmd = namespaces.DefaultCreateCommand(container, console, dataPath, init, pipe, args)
|
||||||
if logPath != "" {
|
if logPath != "" {
|
||||||
cmd.Env = append(cmd.Env, fmt.Sprintf("log=%s", logPath))
|
cmd.Env = append(cmd.Env, fmt.Sprintf("log=%s", logPath))
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ func startContainer(container *libcontainer.Config, dataPath string, args []stri
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
return namespaces.Exec(container, stdin, stdout, stderr, console, "", dataPath, args, createCommand, startCallback)
|
return namespaces.Exec(container, stdin, stdout, stderr, console, dataPath, args, createCommand, startCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resizeTty(master *os.File) {
|
func resizeTty(master *os.File) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче