Additional blkio stats
This adds blkio.io_wait_time, blkio.io_service_time, blkio.io_merged, and blkio.time to the api
This commit is contained in:
parent
3a6faf5653
commit
e6406ef6d0
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -55,8 +55,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/libcontainer",
|
||||
"Comment": "v1.2.0-46-g0da391f",
|
||||
"Rev": "0da391f51c1586544f02c1cc8bd634444e740747"
|
||||
"Comment": "v1.2.0-94-g342b086",
|
||||
"Rev": "342b0860fa8ad4e6feac1581fa86f03c9cb5803d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/fsouza/go-dockerclient",
|
||||
|
@ -6,7 +6,7 @@ feels wrong or incomplete.
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
When reporting [issues](https://github.com/docker/libcontainer/issues)
|
||||
When reporting [issues](https://github.com/docker/libcontainer/issues)
|
||||
on GitHub please include your host OS (Ubuntu 12.04, Fedora 19, etc),
|
||||
the output of `uname -a`. Please include the steps required to reproduce
|
||||
the problem if possible and applicable.
|
||||
@ -14,7 +14,60 @@ This information will help us review and fix your issue faster.
|
||||
|
||||
## Development Environment
|
||||
|
||||
*Add instructions on setting up the development environment.*
|
||||
### Requirements
|
||||
|
||||
For best results, use a Linux development environment.
|
||||
The following packages are required to compile libcontainer natively.
|
||||
|
||||
- Golang 1.3
|
||||
- GCC
|
||||
- git
|
||||
- cgutils
|
||||
|
||||
You can develop on OSX, but you are limited to Dockerfile-based builds only.
|
||||
|
||||
### Building libcontainer from Dockerfile
|
||||
|
||||
make all
|
||||
|
||||
This is the easiest way of building libcontainer.
|
||||
As this build is done using Docker, you can even run this from [OSX](https://github.com/boot2docker/boot2docker)
|
||||
|
||||
### Testing changes with "nsinit"
|
||||
|
||||
make sh
|
||||
|
||||
This will create an container that runs `nsinit exec sh` on a busybox rootfs with the configuration from ['minimal.json'](https://github.com/docker/libcontainer/blob/master/sample_configs/minimal.json).
|
||||
Like the previous command, you can run this on OSX too!
|
||||
|
||||
### Building libcontainer directly
|
||||
|
||||
> Note: You should add the `vendor` directory to your GOPATH to use the vendored libraries
|
||||
|
||||
./update-vendor.sh
|
||||
go get -d ./...
|
||||
make direct-build
|
||||
# Run the tests
|
||||
make direct-test-short | egrep --color 'FAIL|$'
|
||||
# Run all the test
|
||||
make direct-test | egrep --color 'FAIL|$'
|
||||
|
||||
### Testing Changes with "nsinit" directly
|
||||
|
||||
To test a change:
|
||||
|
||||
# Install nsinit
|
||||
make direct-install
|
||||
|
||||
# Optional, add a docker0 bridge
|
||||
ip link add docker0 type bridge
|
||||
ifconfig docker0 172.17.0.1/16 up
|
||||
|
||||
mkdir testfs
|
||||
curl -sSL https://github.com/jpetazzo/docker-busybox/raw/buildroot-2014.02/rootfs.tar | tar -xC testfs
|
||||
cd testfs
|
||||
cp <your-sample-config.json> container.json
|
||||
nsinit exec sh
|
||||
|
||||
## Contribution Guidelines
|
||||
|
5
Godeps/_workspace/src/github.com/docker/libcontainer/Dockerfile
generated
vendored
5
Godeps/_workspace/src/github.com/docker/libcontainer/Dockerfile
generated
vendored
@ -3,6 +3,9 @@ FROM crosbymichael/golang
|
||||
RUN apt-get update && apt-get install -y gcc make
|
||||
RUN go get code.google.com/p/go.tools/cmd/cover
|
||||
|
||||
ENV GOPATH $GOPATH:/go/src/github.com/docker/libcontainer/vendor
|
||||
RUN go get github.com/docker/docker/pkg/term
|
||||
|
||||
# setup a playground for us to spawn containers in
|
||||
RUN mkdir /busybox && \
|
||||
curl -sSL 'https://github.com/jpetazzo/docker-busybox/raw/buildroot-2014.02/rootfs.tar' | tar -xC /busybox
|
||||
@ -14,8 +17,6 @@ COPY . /go/src/github.com/docker/libcontainer
|
||||
WORKDIR /go/src/github.com/docker/libcontainer
|
||||
RUN cp sample_configs/minimal.json /busybox/container.json
|
||||
|
||||
ENV GOPATH $GOPATH:/go/src/github.com/docker/libcontainer/vendor
|
||||
|
||||
RUN go get -d -v ./...
|
||||
RUN make direct-install
|
||||
|
||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/Makefile
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/Makefile
generated
vendored
@ -9,7 +9,7 @@ test:
|
||||
sh:
|
||||
docker run --rm -it --privileged -w /busybox docker/libcontainer nsinit exec sh
|
||||
|
||||
GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u)
|
||||
GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune -o -wholename ./.git -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u)
|
||||
|
||||
direct-test:
|
||||
go test -cover -v $(GO_PACKAGES)
|
||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/cgroups_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/cgroups_test.go
generated
vendored
@ -20,7 +20,7 @@ const (
|
||||
|
||||
func TestParseCgroups(t *testing.T) {
|
||||
r := bytes.NewBuffer([]byte(cgroupsContents))
|
||||
_, err := parseCgroupFile("blkio", r)
|
||||
_, err := ParseCgroupFile("blkio", r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
13
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
13
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
@ -73,6 +73,19 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// Symmetrical public function to update device based cgroups. Also available
|
||||
// in the systemd implementation.
|
||||
func ApplyDevices(c *cgroups.Cgroup, pid int) error {
|
||||
d, err := getCgroupData(c, pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
devices := subsystems["devices"]
|
||||
|
||||
return devices.Set(d)
|
||||
}
|
||||
|
||||
func Cleanup(c *cgroups.Cgroup) error {
|
||||
d, err := getCgroupData(c, 0)
|
||||
if err != nil {
|
||||
|
20
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio.go
generated
vendored
20
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio.go
generated
vendored
@ -146,6 +146,26 @@ func getCFQStats(path string, stats *cgroups.Stats) error {
|
||||
}
|
||||
stats.BlkioStats.IoQueuedRecursive = blkioStats
|
||||
|
||||
if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_service_time_recursive")); err != nil {
|
||||
return err
|
||||
}
|
||||
stats.BlkioStats.IoServiceTimeRecursive = blkioStats
|
||||
|
||||
if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_wait_time_recursive")); err != nil {
|
||||
return err
|
||||
}
|
||||
stats.BlkioStats.IoWaitTimeRecursive = blkioStats
|
||||
|
||||
if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_merged_recursive")); err != nil {
|
||||
return err
|
||||
}
|
||||
stats.BlkioStats.IoMergedRecursive = blkioStats
|
||||
|
||||
if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.time_recursive")); err != nil {
|
||||
return err
|
||||
}
|
||||
stats.BlkioStats.IoTimeRecursive = blkioStats
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
162
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go
generated
vendored
162
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go
generated
vendored
@ -26,7 +26,25 @@ Total 50`
|
||||
8:0 Async 3
|
||||
8:0 Total 5
|
||||
Total 5`
|
||||
throttleServiceBytes = `8:0 Read 11030528
|
||||
serviceTimeRecursiveContents = `8:0 Read 173959
|
||||
8:0 Write 0
|
||||
8:0 Sync 0
|
||||
8:0 Async 173959
|
||||
8:0 Total 17395
|
||||
Total 17395`
|
||||
waitTimeRecursiveContents = `8:0 Read 15571
|
||||
8:0 Write 0
|
||||
8:0 Sync 0
|
||||
8:0 Async 15571
|
||||
8:0 Total 15571`
|
||||
mergedRecursiveContents = `8:0 Read 5
|
||||
8:0 Write 10
|
||||
8:0 Sync 0
|
||||
8:0 Async 0
|
||||
8:0 Total 15
|
||||
Total 15`
|
||||
timeRecursiveContents = `8:0 8`
|
||||
throttleServiceBytes = `8:0 Read 11030528
|
||||
8:0 Write 23
|
||||
8:0 Sync 42
|
||||
8:0 Async 11030528
|
||||
@ -61,6 +79,10 @@ func TestBlkioStats(t *testing.T) {
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
})
|
||||
|
||||
@ -93,6 +115,26 @@ func TestBlkioStats(t *testing.T) {
|
||||
appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 3, "Async")
|
||||
appendBlkioStatEntry(&expectedStats.IoQueuedRecursive, 8, 0, 5, "Total")
|
||||
|
||||
appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 173959, "Read")
|
||||
appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 0, "Write")
|
||||
appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 0, "Sync")
|
||||
appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 173959, "Async")
|
||||
appendBlkioStatEntry(&expectedStats.IoServiceTimeRecursive, 8, 0, 17395, "Total")
|
||||
|
||||
appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Read")
|
||||
appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 0, "Write")
|
||||
appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 0, "Sync")
|
||||
appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Async")
|
||||
appendBlkioStatEntry(&expectedStats.IoWaitTimeRecursive, 8, 0, 15571, "Total")
|
||||
|
||||
appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 5, "Read")
|
||||
appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 10, "Write")
|
||||
appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 0, "Sync")
|
||||
appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 0, "Async")
|
||||
appendBlkioStatEntry(&expectedStats.IoMergedRecursive, 8, 0, 15, "Total")
|
||||
|
||||
appendBlkioStatEntry(&expectedStats.IoTimeRecursive, 8, 0, 8, "")
|
||||
|
||||
expectBlkioStatsEquals(t, expectedStats, actualStats.BlkioStats)
|
||||
}
|
||||
|
||||
@ -103,6 +145,10 @@ func TestBlkioStatsNoSectorsFile(t *testing.T) {
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
@ -117,9 +163,13 @@ func TestBlkioStatsNoServiceBytesFile(t *testing.T) {
|
||||
helper := NewCgroupTestUtil("blkio", t)
|
||||
defer helper.cleanup()
|
||||
helper.writeFileContents(map[string]string{
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
@ -137,6 +187,10 @@ func TestBlkioStatsNoServicedFile(t *testing.T) {
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
@ -154,6 +208,94 @@ func TestBlkioStatsNoQueuedFile(t *testing.T) {
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
actualStats := *cgroups.NewStats()
|
||||
err := blkio.GetStats(helper.CgroupPath, &actualStats)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed unexpectedly: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlkioStatsNoServiceTimeFile(t *testing.T) {
|
||||
helper := NewCgroupTestUtil("blkio", t)
|
||||
defer helper.cleanup()
|
||||
helper.writeFileContents(map[string]string{
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
actualStats := *cgroups.NewStats()
|
||||
err := blkio.GetStats(helper.CgroupPath, &actualStats)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed unexpectedly: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlkioStatsNoWaitTimeFile(t *testing.T) {
|
||||
helper := NewCgroupTestUtil("blkio", t)
|
||||
defer helper.cleanup()
|
||||
helper.writeFileContents(map[string]string{
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
actualStats := *cgroups.NewStats()
|
||||
err := blkio.GetStats(helper.CgroupPath, &actualStats)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed unexpectedly: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlkioStatsNoMergedFile(t *testing.T) {
|
||||
helper := NewCgroupTestUtil("blkio", t)
|
||||
defer helper.cleanup()
|
||||
helper.writeFileContents(map[string]string{
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
actualStats := *cgroups.NewStats()
|
||||
err := blkio.GetStats(helper.CgroupPath, &actualStats)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed unexpectedly: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlkioStatsNoTimeFile(t *testing.T) {
|
||||
helper := NewCgroupTestUtil("blkio", t)
|
||||
defer helper.cleanup()
|
||||
helper.writeFileContents(map[string]string{
|
||||
"blkio.io_service_bytes_recursive": serviceBytesRecursiveContents,
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
@ -172,6 +314,10 @@ func TestBlkioStatsUnexpectedNumberOfFields(t *testing.T) {
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
@ -190,6 +336,10 @@ func TestBlkioStatsUnexpectedFieldType(t *testing.T) {
|
||||
"blkio.io_serviced_recursive": servicedRecursiveContents,
|
||||
"blkio.io_queued_recursive": queuedRecursiveContents,
|
||||
"blkio.sectors_recursive": sectorsRecursiveContents,
|
||||
"blkio.io_service_time_recursive": serviceTimeRecursiveContents,
|
||||
"blkio.io_wait_time_recursive": waitTimeRecursiveContents,
|
||||
"blkio.io_merged_recursive": mergedRecursiveContents,
|
||||
"blkio.time_recursive": timeRecursiveContents,
|
||||
})
|
||||
|
||||
blkio := &BlkioGroup{}
|
||||
@ -208,6 +358,10 @@ func TestNonCFQBlkioStats(t *testing.T) {
|
||||
"blkio.io_serviced_recursive": "",
|
||||
"blkio.io_queued_recursive": "",
|
||||
"blkio.sectors_recursive": "",
|
||||
"blkio.io_service_time_recursive": "",
|
||||
"blkio.io_wait_time_recursive": "",
|
||||
"blkio.io_merged_recursive": "",
|
||||
"blkio.time_recursive": "",
|
||||
"blkio.throttle.io_service_bytes": throttleServiceBytes,
|
||||
"blkio.throttle.io_serviced": throttleServiced,
|
||||
})
|
||||
|
20
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/stats_util_test.go
generated
vendored
20
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/stats_util_test.go
generated
vendored
@ -41,6 +41,26 @@ func expectBlkioStatsEquals(t *testing.T, expected, actual cgroups.BlkioStats) {
|
||||
log.Printf("blkio SectorsRecursive do not match - %s\n", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if err := blkioStatEntryEquals(expected.IoServiceTimeRecursive, actual.IoServiceTimeRecursive); err != nil {
|
||||
log.Printf("blkio IoServiceTimeRecursive do not match - %s\n", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if err := blkioStatEntryEquals(expected.IoWaitTimeRecursive, actual.IoWaitTimeRecursive); err != nil {
|
||||
log.Printf("blkio IoWaitTimeRecursive do not match - %s\n", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if err := blkioStatEntryEquals(expected.IoMergedRecursive, actual.IoMergedRecursive); err != nil {
|
||||
log.Printf("blkio IoMergedRecursive do not match - %s vs %s\n", expected.IoMergedRecursive, actual.IoMergedRecursive)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if err := blkioStatEntryEquals(expected.IoTimeRecursive, actual.IoTimeRecursive); err != nil {
|
||||
log.Printf("blkio IoTimeRecursive do not match - %s\n", err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func expectThrottlingDataEquals(t *testing.T, expected, actual cgroups.ThrottlingData) {
|
||||
|
6
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/stats.go
generated
vendored
6
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/stats.go
generated
vendored
@ -52,8 +52,12 @@ type BlkioStatEntry struct {
|
||||
type BlkioStats struct {
|
||||
// number of bytes tranferred to and from the block device
|
||||
IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive,omitempty"`
|
||||
IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recusrive,omitempty"`
|
||||
IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive,omitempty"`
|
||||
IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive,omitempty"`
|
||||
IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive,omitempty"`
|
||||
IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive,omitempty"`
|
||||
IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive,omitempty"`
|
||||
IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive,omitempty"`
|
||||
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,10 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) {
|
||||
return nil, fmt.Errorf("Systemd not supported")
|
||||
}
|
||||
|
||||
func ApplyDevices(c *cgroups.Cgroup, pid int) error {
|
||||
return fmt.Errorf("Systemd not supported")
|
||||
}
|
||||
|
||||
func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error {
|
||||
return fmt.Errorf("Systemd not supported")
|
||||
}
|
||||
|
@ -327,6 +327,12 @@ func joinDevices(c *cgroups.Cgroup, pid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Symmetrical public function to update device based cgroups. Also available
|
||||
// in the fs implementation.
|
||||
func ApplyDevices(c *cgroups.Cgroup, pid int) error {
|
||||
return joinDevices(c, pid)
|
||||
}
|
||||
|
||||
func joinMemory(c *cgroups.Cgroup, pid int) error {
|
||||
memorySwap := c.MemorySwap
|
||||
|
||||
|
6
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/utils.go
generated
vendored
6
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/utils.go
generated
vendored
@ -115,7 +115,7 @@ func GetThisCgroupDir(subsystem string) (string, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseCgroupFile(subsystem, f)
|
||||
return ParseCgroupFile(subsystem, f)
|
||||
}
|
||||
|
||||
func GetInitCgroupDir(subsystem string) (string, error) {
|
||||
@ -125,7 +125,7 @@ func GetInitCgroupDir(subsystem string) (string, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseCgroupFile(subsystem, f)
|
||||
return ParseCgroupFile(subsystem, f)
|
||||
}
|
||||
|
||||
func ReadProcsFile(dir string) ([]int, error) {
|
||||
@ -152,7 +152,7 @@ func ReadProcsFile(dir string) ([]int, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func parseCgroupFile(subsystem string, r io.Reader) (string, error) {
|
||||
func ParseCgroupFile(subsystem string, r io.Reader) (string, error) {
|
||||
s := bufio.NewScanner(r)
|
||||
|
||||
for s.Scan() {
|
||||
|
4
Godeps/_workspace/src/github.com/docker/libcontainer/console/console.go
generated
vendored
4
Godeps/_workspace/src/github.com/docker/libcontainer/console/console.go
generated
vendored
@ -67,14 +67,14 @@ func OpenAndDup(consolePath string) error {
|
||||
// Unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
|
||||
// Unlockpt should be called before opening the slave side of a pseudoterminal.
|
||||
func Unlockpt(f *os.File) error {
|
||||
var u int
|
||||
var u int32
|
||||
|
||||
return Ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u)))
|
||||
}
|
||||
|
||||
// Ptsname retrieves the name of the first available pts for the given master.
|
||||
func Ptsname(f *os.File) (string, error) {
|
||||
var n int
|
||||
var n int32
|
||||
|
||||
if err := Ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil {
|
||||
return "", err
|
||||
|
5
Godeps/_workspace/src/github.com/docker/libcontainer/devices/devices.go
generated
vendored
5
Godeps/_workspace/src/github.com/docker/libcontainer/devices/devices.go
generated
vendored
@ -100,7 +100,8 @@ func getDeviceNodes(path string) ([]*Device, error) {
|
||||
|
||||
out := []*Device{}
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
case "pts", "shm", "fd":
|
||||
continue
|
||||
@ -113,6 +114,8 @@ func getDeviceNodes(path string) ([]*Device, error) {
|
||||
out = append(out, sub...)
|
||||
continue
|
||||
}
|
||||
case f.Name() == "console":
|
||||
continue
|
||||
}
|
||||
|
||||
device, err := GetDevice(filepath.Join(path, f.Name()), "rwm")
|
||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/integration/doc.go
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/docker/libcontainer/integration/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// integration is used for integration testing of libcontainer
|
||||
package integration
|
38
Godeps/_workspace/src/github.com/docker/libcontainer/integration/exec_test.go
generated
vendored
Normal file
38
Godeps/_workspace/src/github.com/docker/libcontainer/integration/exec_test.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExecPS(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
rootfs, err := newRootFs()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer remove(rootfs)
|
||||
|
||||
config := newTemplateConfig(rootfs)
|
||||
buffers, exitCode, err := runContainer(config, "", "ps")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if exitCode != 0 {
|
||||
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
|
||||
}
|
||||
|
||||
lines := strings.Split(buffers.Stdout.String(), "\n")
|
||||
if len(lines) < 2 {
|
||||
t.Fatalf("more than one process running for output %q", buffers.Stdout.String())
|
||||
}
|
||||
expected := `1 root ps`
|
||||
actual := strings.Trim(lines[1], "\n ")
|
||||
if actual != expected {
|
||||
t.Fatalf("expected output %q but received %q", expected, actual)
|
||||
}
|
||||
}
|
39
Godeps/_workspace/src/github.com/docker/libcontainer/integration/init_test.go
generated
vendored
Normal file
39
Godeps/_workspace/src/github.com/docker/libcontainer/integration/init_test.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/libcontainer/namespaces"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
)
|
||||
|
||||
// init runs the libcontainer initialization code because of the busybox style needs
|
||||
// to work around the go runtime and the issues with forking
|
||||
func init() {
|
||||
if len(os.Args) < 2 || os.Args[1] != "init" {
|
||||
return
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
|
||||
container, err := loadConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
rootfs, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create sync pipe: %s", err)
|
||||
}
|
||||
|
||||
if err := namespaces.Init(container, rootfs, "", syncPipe, os.Args[3:]); err != nil {
|
||||
log.Fatalf("unable to initialize for container: %s", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
64
Godeps/_workspace/src/github.com/docker/libcontainer/integration/template_test.go
generated
vendored
Normal file
64
Godeps/_workspace/src/github.com/docker/libcontainer/integration/template_test.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/cgroups"
|
||||
"github.com/docker/libcontainer/devices"
|
||||
)
|
||||
|
||||
// newTemplateConfig returns a base template for running a container
|
||||
//
|
||||
// it uses a network strategy of just setting a loopback interface
|
||||
// and the default setup for devices
|
||||
func newTemplateConfig(rootfs string) *libcontainer.Config {
|
||||
return &libcontainer.Config{
|
||||
RootFs: rootfs,
|
||||
Tty: false,
|
||||
Capabilities: []string{
|
||||
"CHOWN",
|
||||
"DAC_OVERRIDE",
|
||||
"FSETID",
|
||||
"FOWNER",
|
||||
"MKNOD",
|
||||
"NET_RAW",
|
||||
"SETGID",
|
||||
"SETUID",
|
||||
"SETFCAP",
|
||||
"SETPCAP",
|
||||
"NET_BIND_SERVICE",
|
||||
"SYS_CHROOT",
|
||||
"KILL",
|
||||
"AUDIT_WRITE",
|
||||
},
|
||||
Namespaces: map[string]bool{
|
||||
"NEWNS": true,
|
||||
"NEWUTS": true,
|
||||
"NEWIPC": true,
|
||||
"NEWPID": true,
|
||||
"NEWNET": true,
|
||||
},
|
||||
Cgroups: &cgroups.Cgroup{
|
||||
Parent: "integration",
|
||||
AllowAllDevices: false,
|
||||
AllowedDevices: devices.DefaultAllowedDevices,
|
||||
},
|
||||
|
||||
MountConfig: &libcontainer.MountConfig{
|
||||
DeviceNodes: devices.DefaultAutoCreatedDevices,
|
||||
},
|
||||
Hostname: "integration",
|
||||
Env: []string{
|
||||
"HOME=/root",
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"HOSTNAME=integration",
|
||||
"TERM=xterm",
|
||||
},
|
||||
Networks: []*libcontainer.Network{
|
||||
{
|
||||
Type: "loopback",
|
||||
Address: "127.0.0.1/0",
|
||||
Gateway: "localhost",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
95
Godeps/_workspace/src/github.com/docker/libcontainer/integration/utils_test.go
generated
vendored
Normal file
95
Godeps/_workspace/src/github.com/docker/libcontainer/integration/utils_test.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/namespaces"
|
||||
)
|
||||
|
||||
func newStdBuffers() *stdBuffers {
|
||||
return &stdBuffers{
|
||||
Stdin: bytes.NewBuffer(nil),
|
||||
Stdout: bytes.NewBuffer(nil),
|
||||
Stderr: bytes.NewBuffer(nil),
|
||||
}
|
||||
}
|
||||
|
||||
type stdBuffers struct {
|
||||
Stdin *bytes.Buffer
|
||||
Stdout *bytes.Buffer
|
||||
Stderr *bytes.Buffer
|
||||
}
|
||||
|
||||
func writeConfig(config *libcontainer.Config) error {
|
||||
f, err := os.OpenFile(filepath.Join(config.RootFs, "container.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return json.NewEncoder(f).Encode(config)
|
||||
}
|
||||
|
||||
func loadConfig() (*libcontainer.Config, error) {
|
||||
f, err := os.Open(filepath.Join(os.Getenv("data_path"), "container.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var container *libcontainer.Config
|
||||
if err := json.NewDecoder(f).Decode(&container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return container, nil
|
||||
}
|
||||
|
||||
// newRootFs creates a new tmp directory and copies the busybox root filesystem
|
||||
func newRootFs() (string, error) {
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := copyBusybox(dir); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func remove(dir string) {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
// copyBusybox copies the rootfs for a busybox container created for the test image
|
||||
// into the new directory for the specific test
|
||||
func copyBusybox(dest string) error {
|
||||
out, err := exec.Command("sh", "-c", fmt.Sprintf("cp -R /busybox/* %s/", dest)).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("copy error %q: %q", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// runContainer runs the container with the specific config and arguments
|
||||
//
|
||||
// buffers are returned containing the STDOUT and STDERR output for the run
|
||||
// along with the exit code and any go error
|
||||
func runContainer(config *libcontainer.Config, console string, args ...string) (buffers *stdBuffers, exitCode int, err error) {
|
||||
if err := writeConfig(config); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
|
||||
buffers = newStdBuffers()
|
||||
exitCode, err = namespaces.Exec(config, buffers.Stdin, buffers.Stdout, buffers.Stderr,
|
||||
console, config.RootFs, args, namespaces.DefaultCreateCommand, nil)
|
||||
return
|
||||
}
|
14
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux.go
generated
vendored
14
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux.go
generated
vendored
@ -67,20 +67,17 @@ func FormatMountLabel(src, mountLabel string) string {
|
||||
// SetProcessLabel takes a process label and tells the kernel to assign the
|
||||
// label to the next program executed by the current process.
|
||||
func SetProcessLabel(processLabel string) error {
|
||||
if selinux.SelinuxEnabled() {
|
||||
return selinux.Setexeccon(processLabel)
|
||||
if processLabel == "" {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
return selinux.Setexeccon(processLabel)
|
||||
}
|
||||
|
||||
// GetProcessLabel returns the process label that the kernel will assign
|
||||
// to the next program executed by the current process. If "" is returned
|
||||
// this indicates that the default labeling will happen for the process.
|
||||
func GetProcessLabel() (string, error) {
|
||||
if selinux.SelinuxEnabled() {
|
||||
return selinux.Getexeccon()
|
||||
}
|
||||
return "", nil
|
||||
return selinux.Getexeccon()
|
||||
}
|
||||
|
||||
// SetFileLabel modifies the "path" label to the specified file label
|
||||
@ -110,9 +107,6 @@ func Relabel(path string, fileLabel string, relabel string) error {
|
||||
|
||||
// GetPidLabel will return the label of the process running with the specified pid
|
||||
func GetPidLabel(pid int) (string, error) {
|
||||
if !selinux.SelinuxEnabled() {
|
||||
return "", nil
|
||||
}
|
||||
return selinux.Getpidcon(pid)
|
||||
}
|
||||
|
||||
|
5
Godeps/_workspace/src/github.com/docker/libcontainer/namespaces/execin.go
generated
vendored
5
Godeps/_workspace/src/github.com/docker/libcontainer/namespaces/execin.go
generated
vendored
@ -12,6 +12,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/apparmor"
|
||||
"github.com/docker/libcontainer/cgroups"
|
||||
"github.com/docker/libcontainer/label"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
@ -96,6 +97,10 @@ func FinalizeSetns(container *libcontainer.Config, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := apparmor.ApplyProfile(container.AppArmorProfile); err != nil {
|
||||
return fmt.Errorf("set apparmor profile %s: %s", container.AppArmorProfile, err)
|
||||
}
|
||||
|
||||
if container.ProcessLabel != "" {
|
||||
if err := label.SetProcessLabel(container.ProcessLabel); err != nil {
|
||||
return err
|
||||
|
5
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
generated
vendored
5
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
generated
vendored
@ -11,8 +11,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrWrongSockType = errors.New("Wrong socket type")
|
||||
ErrShortResponse = errors.New("Got short response from netlink")
|
||||
ErrWrongSockType = errors.New("Wrong socket type")
|
||||
ErrShortResponse = errors.New("Got short response from netlink")
|
||||
ErrInterfaceExists = errors.New("Network interface already exists")
|
||||
)
|
||||
|
||||
// A Route is a subnet associated with the interface to reach it.
|
||||
|
281
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
generated
vendored
281
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
generated
vendored
@ -6,22 +6,32 @@ import (
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
IFNAMSIZ = 16
|
||||
DEFAULT_CHANGE = 0xFFFFFFFF
|
||||
IFLA_INFO_KIND = 1
|
||||
IFLA_INFO_DATA = 2
|
||||
VETH_INFO_PEER = 1
|
||||
IFLA_NET_NS_FD = 28
|
||||
IFLA_ADDRESS = 1
|
||||
SIOC_BRADDBR = 0x89a0
|
||||
SIOC_BRDELBR = 0x89a1
|
||||
SIOC_BRADDIF = 0x89a2
|
||||
IFNAMSIZ = 16
|
||||
DEFAULT_CHANGE = 0xFFFFFFFF
|
||||
IFLA_INFO_KIND = 1
|
||||
IFLA_INFO_DATA = 2
|
||||
VETH_INFO_PEER = 1
|
||||
IFLA_MACVLAN_MODE = 1
|
||||
IFLA_VLAN_ID = 1
|
||||
IFLA_NET_NS_FD = 28
|
||||
IFLA_ADDRESS = 1
|
||||
SIOC_BRADDBR = 0x89a0
|
||||
SIOC_BRDELBR = 0x89a1
|
||||
SIOC_BRADDIF = 0x89a2
|
||||
)
|
||||
|
||||
const (
|
||||
MACVLAN_MODE_PRIVATE = 1 << iota
|
||||
MACVLAN_MODE_VEPA
|
||||
MACVLAN_MODE_BRIDGE
|
||||
MACVLAN_MODE_PASSTHRU
|
||||
)
|
||||
|
||||
var nextSeqNr uint32
|
||||
@ -385,7 +395,7 @@ func nonZeroTerminated(s string) []byte {
|
||||
}
|
||||
|
||||
// Add a new network link of a specified type.
|
||||
// This is identical to running: ip add link $name type $linkType
|
||||
// This is identical to running: ip link add $name type $linkType
|
||||
func NetworkLinkAdd(name string, linkType string) error {
|
||||
if name == "" || linkType == "" {
|
||||
return fmt.Errorf("Neither link name nor link type can be empty!")
|
||||
@ -603,22 +613,18 @@ func NetworkSetNoMaster(iface *net.Interface) error {
|
||||
return networkMasterAction(iface, data)
|
||||
}
|
||||
|
||||
func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
||||
func networkSetNsAction(iface *net.Interface, rtattr *RtAttr) error {
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
||||
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(iface.Index)
|
||||
msg.Change = DEFAULT_CHANGE
|
||||
wb.AddData(msg)
|
||||
wb.AddData(uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid)))
|
||||
wb.AddData(rtattr)
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
@ -627,7 +633,29 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
||||
return s.HandleAck(wb.Seq)
|
||||
}
|
||||
|
||||
// Move a particular network interface to a particular network namespace
|
||||
// specified by PID. This is idential to running: ip link set dev $name netns $pid
|
||||
func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
||||
data := uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid))
|
||||
return networkSetNsAction(iface, data)
|
||||
}
|
||||
|
||||
// Move a particular network interface to a particular mounted
|
||||
// network namespace specified by file descriptor.
|
||||
// This is idential to running: ip link set dev $name netns $fd
|
||||
func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
||||
data := uint32Attr(IFLA_NET_NS_FD, uint32(fd))
|
||||
return networkSetNsAction(iface, data)
|
||||
}
|
||||
|
||||
// Rname a particular interface to a different name
|
||||
// !!! Note that you can't rename an active interface. You need to bring it down before renaming it.
|
||||
// This is identical to running: ip link set dev ${oldName} name ${newName}
|
||||
func NetworkChangeName(iface *net.Interface, newName string) error {
|
||||
if len(newName) >= IFNAMSIZ {
|
||||
return fmt.Errorf("Interface name %s too long", newName)
|
||||
}
|
||||
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -637,12 +665,12 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
||||
wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(iface.Index)
|
||||
msg.Change = DEFAULT_CHANGE
|
||||
wb.AddData(msg)
|
||||
wb.AddData(uint32Attr(IFLA_NET_NS_FD, uint32(fd)))
|
||||
|
||||
nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(newName))
|
||||
wb.AddData(nameData)
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
@ -651,6 +679,140 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
||||
return s.HandleAck(wb.Seq)
|
||||
}
|
||||
|
||||
// Add a new VETH pair link on the host
|
||||
// This is identical to running: ip link add name $name type veth peer name $peername
|
||||
func NetworkCreateVethPair(name1, name2 string, txQueueLen int) error {
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
|
||||
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
||||
wb.AddData(msg)
|
||||
|
||||
nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1))
|
||||
wb.AddData(nameData)
|
||||
|
||||
txqLen := make([]byte, 4)
|
||||
native.PutUint32(txqLen, uint32(txQueueLen))
|
||||
txqData := newRtAttr(syscall.IFLA_TXQLEN, txqLen)
|
||||
wb.AddData(txqData)
|
||||
|
||||
nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
||||
newRtAttrChild(nest1, IFLA_INFO_KIND, zeroTerminated("veth"))
|
||||
nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
||||
nest3 := newRtAttrChild(nest2, VETH_INFO_PEER, nil)
|
||||
|
||||
newIfInfomsgChild(nest3, syscall.AF_UNSPEC)
|
||||
newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2))
|
||||
|
||||
txqLen2 := make([]byte, 4)
|
||||
native.PutUint32(txqLen2, uint32(txQueueLen))
|
||||
newRtAttrChild(nest3, syscall.IFLA_TXQLEN, txqLen2)
|
||||
|
||||
wb.AddData(nest1)
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.HandleAck(wb.Seq); err != nil {
|
||||
if os.IsExist(err) {
|
||||
return ErrInterfaceExists
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add a new VLAN interface with masterDev as its upper device
|
||||
// This is identical to running:
|
||||
// ip link add name $name link $masterdev type vlan id $id
|
||||
func NetworkLinkAddVlan(masterDev, vlanDev string, vlanId uint16) error {
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
|
||||
masterDevIfc, err := net.InterfaceByName(masterDev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
||||
wb.AddData(msg)
|
||||
|
||||
nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
||||
newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("vlan"))
|
||||
|
||||
nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
||||
vlanData := make([]byte, 2)
|
||||
native.PutUint16(vlanData, vlanId)
|
||||
newRtAttrChild(nest2, IFLA_VLAN_ID, vlanData)
|
||||
wb.AddData(nest1)
|
||||
|
||||
wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
|
||||
wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(vlanDev)))
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.HandleAck(wb.Seq)
|
||||
}
|
||||
|
||||
// Add MAC VLAN network interface with masterDev as its upper device
|
||||
// This is identical to running:
|
||||
// ip link add name $name link $masterdev type macvlan mode $mode
|
||||
func NetworkLinkAddMacVlan(masterDev, macVlanDev string, mode string) error {
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
macVlan := map[string]uint32{
|
||||
"private": MACVLAN_MODE_PRIVATE,
|
||||
"vepa": MACVLAN_MODE_VEPA,
|
||||
"bridge": MACVLAN_MODE_BRIDGE,
|
||||
"passthru": MACVLAN_MODE_PASSTHRU,
|
||||
}
|
||||
|
||||
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
|
||||
masterDevIfc, err := net.InterfaceByName(masterDev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
||||
wb.AddData(msg)
|
||||
|
||||
nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
||||
newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("macvlan"))
|
||||
|
||||
nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
||||
macVlanData := make([]byte, 4)
|
||||
native.PutUint32(macVlanData, macVlan[mode])
|
||||
newRtAttrChild(nest2, IFLA_MACVLAN_MODE, macVlanData)
|
||||
wb.AddData(nest1)
|
||||
|
||||
wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
|
||||
wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(macVlanDev)))
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.HandleAck(wb.Seq)
|
||||
}
|
||||
|
||||
func networkLinkIpAction(action, flags int, ifa IfAddr) error {
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
@ -906,60 +1068,6 @@ func AddDefaultGw(ip, device string) error {
|
||||
return AddRoute("", "", ip, device)
|
||||
}
|
||||
|
||||
func NetworkChangeName(iface *net.Interface, newName string) error {
|
||||
if len(newName) >= IFNAMSIZ {
|
||||
return fmt.Errorf("Interface name %s too long", newName)
|
||||
}
|
||||
|
||||
fd, err := getIfSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
data := [IFNAMSIZ * 2]byte{}
|
||||
// the "-1"s here are very important for ensuring we get proper null
|
||||
// termination of our new C strings
|
||||
copy(data[:IFNAMSIZ-1], iface.Name)
|
||||
copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName)
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NetworkCreateVethPair(name1, name2 string) error {
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
|
||||
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
||||
wb.AddData(msg)
|
||||
|
||||
nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1))
|
||||
wb.AddData(nameData)
|
||||
|
||||
nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
||||
newRtAttrChild(nest1, IFLA_INFO_KIND, zeroTerminated("veth"))
|
||||
nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
||||
nest3 := newRtAttrChild(nest2, VETH_INFO_PEER, nil)
|
||||
|
||||
newIfInfomsgChild(nest3, syscall.AF_UNSPEC)
|
||||
newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2))
|
||||
|
||||
wb.AddData(nest1)
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.HandleAck(wb.Seq)
|
||||
}
|
||||
|
||||
// THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
|
||||
// IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
|
||||
// WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
|
||||
@ -1095,3 +1203,26 @@ func SetMacAddress(name, addr string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ChangeName(iface *net.Interface, newName string) error {
|
||||
if len(newName) >= IFNAMSIZ {
|
||||
return fmt.Errorf("Interface name %s too long", newName)
|
||||
}
|
||||
|
||||
fd, err := getIfSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
data := [IFNAMSIZ * 2]byte{}
|
||||
// the "-1"s here are very important for ensuring we get proper null
|
||||
// termination of our new C strings
|
||||
copy(data[:IFNAMSIZ-1], iface.Name)
|
||||
copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName)
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
74
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
generated
vendored
74
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
generated
vendored
@ -180,6 +180,74 @@ func TestNetworkSetMasterNoMaster(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if testing.Short() {
|
||||
return
|
||||
@ -222,7 +290,7 @@ func TestCreateVethPair(t *testing.T) {
|
||||
name2 = "veth2"
|
||||
)
|
||||
|
||||
if err := NetworkCreateVethPair(name1, name2); err != nil {
|
||||
if err := NetworkCreateVethPair(name1, name2, 0); err != nil {
|
||||
t.Fatalf("Could not create veth pair %s %s: %s", name1, name2, err)
|
||||
}
|
||||
defer NetworkLinkDel(name1)
|
||||
@ -232,7 +300,7 @@ func TestCreateVethPair(t *testing.T) {
|
||||
}
|
||||
|
||||
//
|
||||
// netlink package test which do not use RTNETLINK
|
||||
// netlink package tests which do not use RTNETLINK
|
||||
//
|
||||
func TestCreateBridgeWithMac(t *testing.T) {
|
||||
if testing.Short() {
|
||||
@ -260,7 +328,7 @@ func TestCreateBridgeWithMac(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMACAddress(t *testing.T) {
|
||||
func TestSetMacAddress(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
generated
vendored
@ -47,7 +47,7 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkCreateVethPair(name1, name2 string) error {
|
||||
func NetworkCreateVethPair(name1, name2 string, txQueueLen int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/network/netns.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/network/netns.go
generated
vendored
@ -30,8 +30,10 @@ func (v *NetNS) Initialize(config *Network, networkState *NetworkState) error {
|
||||
}
|
||||
|
||||
if err := system.Setns(f.Fd(), syscall.CLONE_NEWNET); err != nil {
|
||||
f.Close()
|
||||
return fmt.Errorf("failed to setns current network namespace: %v", err)
|
||||
}
|
||||
|
||||
f.Close()
|
||||
return nil
|
||||
}
|
||||
|
12
Godeps/_workspace/src/github.com/docker/libcontainer/network/network.go
generated
vendored
12
Godeps/_workspace/src/github.com/docker/libcontainer/network/network.go
generated
vendored
@ -32,8 +32,8 @@ func ChangeInterfaceName(old, newName string) error {
|
||||
return netlink.NetworkChangeName(iface, newName)
|
||||
}
|
||||
|
||||
func CreateVethPair(name1, name2 string) error {
|
||||
return netlink.NetworkCreateVethPair(name1, name2)
|
||||
func CreateVethPair(name1, name2 string, txQueueLen int) error {
|
||||
return netlink.NetworkCreateVethPair(name1, name2, txQueueLen)
|
||||
}
|
||||
|
||||
func SetInterfaceInNamespacePid(name string, nsPid int) error {
|
||||
@ -68,6 +68,14 @@ func SetDefaultGateway(ip, ifaceName string) error {
|
||||
return netlink.AddDefaultGw(ip, ifaceName)
|
||||
}
|
||||
|
||||
func SetInterfaceMac(name string, macaddr string) error {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return netlink.NetworkSetMacAddress(iface, macaddr)
|
||||
}
|
||||
|
||||
func SetInterfaceIp(name string, rawIp string) error {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
|
16
Godeps/_workspace/src/github.com/docker/libcontainer/network/types.go
generated
vendored
16
Godeps/_workspace/src/github.com/docker/libcontainer/network/types.go
generated
vendored
@ -17,16 +17,30 @@ type Network struct {
|
||||
// Prefix for the veth interfaces.
|
||||
VethPrefix string `json:"veth_prefix,omitempty"`
|
||||
|
||||
// Address contains the IP and mask to set on the network interface
|
||||
// MacAddress contains the MAC address to set on the network interface
|
||||
MacAddress string `json:"mac_address,omitempty"`
|
||||
|
||||
// Address contains the IPv4 and mask to set on the network interface
|
||||
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 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
|
||||
// container's interfaces if a pair is created, specifically in the case of type veth
|
||||
// Note: This does not apply to loopback interfaces.
|
||||
Mtu int `json:"mtu,omitempty"`
|
||||
|
||||
// TxQueueLen sets the tx_queuelen 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
|
||||
// Note: This does not apply to loopback interfaces.
|
||||
TxQueueLen int `json:"txqueuelen,omitempty"`
|
||||
}
|
||||
|
||||
// Struct describing the network specific runtime state that will be maintained by libcontainer for all running containers
|
||||
|
55
Godeps/_workspace/src/github.com/docker/libcontainer/network/veth.go
generated
vendored
55
Godeps/_workspace/src/github.com/docker/libcontainer/network/veth.go
generated
vendored
@ -5,6 +5,7 @@ package network
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
"github.com/docker/libcontainer/utils"
|
||||
)
|
||||
|
||||
@ -18,8 +19,9 @@ const defaultDevice = "eth0"
|
||||
|
||||
func (v *Veth) Create(n *Network, nspid int, networkState *NetworkState) error {
|
||||
var (
|
||||
bridge = n.Bridge
|
||||
prefix = n.VethPrefix
|
||||
bridge = n.Bridge
|
||||
prefix = n.VethPrefix
|
||||
txQueueLen = n.TxQueueLen
|
||||
)
|
||||
if bridge == "" {
|
||||
return fmt.Errorf("bridge is not specified")
|
||||
@ -27,7 +29,7 @@ func (v *Veth) Create(n *Network, nspid int, networkState *NetworkState) error {
|
||||
if prefix == "" {
|
||||
return fmt.Errorf("veth prefix is not specified")
|
||||
}
|
||||
name1, name2, err := createVethPair(prefix)
|
||||
name1, name2, err := createVethPair(prefix, txQueueLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -60,9 +62,20 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error {
|
||||
if err := ChangeInterfaceName(vethChild, defaultDevice); err != nil {
|
||||
return fmt.Errorf("change %s to %s %s", vethChild, defaultDevice, err)
|
||||
}
|
||||
if config.MacAddress != "" {
|
||||
if err := SetInterfaceMac(defaultDevice, config.MacAddress); err != nil {
|
||||
return fmt.Errorf("set %s mac %s", defaultDevice, err)
|
||||
}
|
||||
}
|
||||
if err := SetInterfaceIp(defaultDevice, config.Address); err != nil {
|
||||
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 {
|
||||
return fmt.Errorf("set %s mtu to %d %s", defaultDevice, config.Mtu, err)
|
||||
}
|
||||
@ -74,22 +87,36 @@ 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)
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// createVethPair will automatically generage two random names for
|
||||
// the veth pair and ensure that they have been created
|
||||
func createVethPair(prefix string) (name1 string, name2 string, err error) {
|
||||
name1, err = utils.GenerateRandomName(prefix, 4)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
name2, err = utils.GenerateRandomName(prefix, 4)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = CreateVethPair(name1, name2); err != nil {
|
||||
return
|
||||
func createVethPair(prefix string, txQueueLen int) (name1 string, name2 string, err error) {
|
||||
for i := 0; i < 10; i++ {
|
||||
if name1, err = utils.GenerateRandomName(prefix, 7); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if name2, err = utils.GenerateRandomName(prefix, 7); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = CreateVethPair(name1, name2, txQueueLen); err != nil {
|
||||
if err == netlink.ErrInterfaceExists {
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
53
Godeps/_workspace/src/github.com/docker/libcontainer/network/veth_test.go
generated
vendored
Normal file
53
Godeps/_workspace/src/github.com/docker/libcontainer/network/veth_test.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// +build linux
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
)
|
||||
|
||||
func TestGenerateVethNames(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
prefix := "veth"
|
||||
|
||||
name1, name2, err := createVethPair(prefix, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if name1 == "" {
|
||||
t.Fatal("name1 should not be empty")
|
||||
}
|
||||
|
||||
if name2 == "" {
|
||||
t.Fatal("name2 should not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateDuplicateVethPair(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
prefix := "veth"
|
||||
|
||||
name1, name2, err := createVethPair(prefix, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// retry to create the name interfaces and make sure that we get the correct error
|
||||
err = CreateVethPair(name1, name2, 0)
|
||||
if err == nil {
|
||||
t.Fatal("expected error to not be nil with duplicate interface")
|
||||
}
|
||||
|
||||
if err != netlink.ErrInterfaceExists {
|
||||
t.Fatalf("expected error to be ErrInterfaceExists but received %q", err)
|
||||
}
|
||||
}
|
10
Godeps/_workspace/src/github.com/docker/libcontainer/selinux/selinux.go
generated
vendored
10
Godeps/_workspace/src/github.com/docker/libcontainer/selinux/selinux.go
generated
vendored
@ -173,13 +173,10 @@ func Getpidcon(pid int) (string, error) {
|
||||
}
|
||||
|
||||
func Getexeccon() (string, error) {
|
||||
return readCon("/proc/self/attr/exec")
|
||||
return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()))
|
||||
}
|
||||
|
||||
func writeCon(name string, val string) error {
|
||||
if !SelinuxEnabled() {
|
||||
return nil
|
||||
}
|
||||
out, err := os.OpenFile(name, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -388,9 +385,6 @@ func SecurityCheckContext(val string) error {
|
||||
}
|
||||
|
||||
func CopyLevel(src, dest string) (string, error) {
|
||||
if !SelinuxEnabled() {
|
||||
return "", nil
|
||||
}
|
||||
if src == "" {
|
||||
return "", nil
|
||||
}
|
||||
@ -424,7 +418,7 @@ func badPrefix(fpath string) error {
|
||||
// If the fpath is a directory and recurse is true Chcon will walk the
|
||||
// directory tree setting the label
|
||||
func Chcon(fpath string, scon string, recurse bool) error {
|
||||
if !SelinuxEnabled() {
|
||||
if scon == "" {
|
||||
return nil
|
||||
}
|
||||
if err := badPrefix(fpath); err != nil {
|
||||
|
24
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_386.go
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_386.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// +build linux,386
|
||||
package system
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Setuid sets the uid of the calling thread to the specified uid.
|
||||
func Setuid(uid int) (err error) {
|
||||
_, _, e1 := syscall.RawSyscall(syscall.SYS_SETUID, uintptr(uid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Setgid sets the gid of the calling thread to the specified gid.
|
||||
func Setgid(gid int) (err error) {
|
||||
_, _, e1 := syscall.RawSyscall(syscall.SYS_SETGID32, uintptr(gid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
24
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_amd64.go
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_amd64.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// +build linux,amd64
|
||||
package system
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Setuid sets the uid of the calling thread to the specified uid.
|
||||
func Setuid(uid int) (err error) {
|
||||
_, _, e1 := syscall.RawSyscall(syscall.SYS_SETUID, uintptr(uid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Setgid sets the gid of the calling thread to the specified gid.
|
||||
func Setgid(gid int) (err error) {
|
||||
_, _, e1 := syscall.RawSyscall(syscall.SYS_SETGID, uintptr(gid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
24
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_arm.go
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_arm.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// +build linux,arm
|
||||
package system
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Setuid sets the uid of the calling thread to the specified uid.
|
||||
func Setuid(uid int) (err error) {
|
||||
_, _, e1 := syscall.RawSyscall(syscall.SYS_SETUID, uintptr(uid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Setgid sets the gid of the calling thread to the specified gid.
|
||||
func Setgid(gid int) (err error) {
|
||||
_, _, e1 := syscall.RawSyscall(syscall.SYS_SETGID32, uintptr(gid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
66
Godeps/_workspace/src/github.com/docker/libcontainer/system/xattrs_linux.go
generated
vendored
66
Godeps/_workspace/src/github.com/docker/libcontainer/system/xattrs_linux.go
generated
vendored
@ -5,8 +5,35 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Returns a nil slice and nil error if the xattr is not set
|
||||
var _zero uintptr
|
||||
|
||||
// Returns the size of xattrs and nil error
|
||||
// Requires path, takes allocated []byte or nil as last argument
|
||||
func Llistxattr(path string, dest []byte) (size int, err error) {
|
||||
pathBytes, err := syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
var newpathBytes unsafe.Pointer
|
||||
if len(dest) > 0 {
|
||||
newpathBytes = unsafe.Pointer(&dest[0])
|
||||
} else {
|
||||
newpathBytes = unsafe.Pointer(&_zero)
|
||||
}
|
||||
|
||||
_size, _, errno := syscall.Syscall6(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(newpathBytes), uintptr(len(dest)), 0, 0, 0)
|
||||
size = int(_size)
|
||||
if errno != 0 {
|
||||
return -1, errno
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// Returns a []byte slice if the xattr is set and nil otherwise
|
||||
// Requires path and its attribute as arguments
|
||||
func Lgetxattr(path string, attr string) ([]byte, error) {
|
||||
var sz int
|
||||
pathBytes, err := syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -16,26 +43,39 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dest := make([]byte, 128)
|
||||
// Start with a 128 length byte array
|
||||
sz = 128
|
||||
dest := make([]byte, sz)
|
||||
destBytes := unsafe.Pointer(&dest[0])
|
||||
sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
|
||||
if errno == syscall.ENODATA {
|
||||
return nil, nil
|
||||
}
|
||||
if errno == syscall.ERANGE {
|
||||
_sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
|
||||
|
||||
switch {
|
||||
case errno == syscall.ENODATA:
|
||||
return nil, errno
|
||||
case errno == syscall.ENOTSUP:
|
||||
return nil, errno
|
||||
case errno == syscall.ERANGE:
|
||||
// 128 byte array might just not be good enough,
|
||||
// A dummy buffer is used ``uintptr(0)`` to get real size
|
||||
// of the xattrs on disk
|
||||
_sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0)
|
||||
sz = int(_sz)
|
||||
if sz < 0 {
|
||||
return nil, errno
|
||||
}
|
||||
dest = make([]byte, sz)
|
||||
destBytes := unsafe.Pointer(&dest[0])
|
||||
sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
|
||||
}
|
||||
if errno != 0 {
|
||||
_sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
case errno != 0:
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
sz = int(_sz)
|
||||
return dest[:sz], nil
|
||||
}
|
||||
|
||||
var _zero uintptr
|
||||
|
||||
func Lsetxattr(path string, attr string, data []byte, flags int) error {
|
||||
pathBytes, err := syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
|
15
Godeps/_workspace/src/github.com/docker/libcontainer/utils/utils_test.go
generated
vendored
Normal file
15
Godeps/_workspace/src/github.com/docker/libcontainer/utils/utils_test.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGenerateName(t *testing.T) {
|
||||
name, err := GenerateRandomName("veth", 5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := 5 + len("veth")
|
||||
if len(name) != 5+len("veth") {
|
||||
t.Fatalf("expected name to be %d chars but received %d", expected, len(name))
|
||||
}
|
||||
}
|
8
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/errors.go
generated
vendored
Normal file
8
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/errors.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
package xattr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var ErrNotSupportedPlatform = fmt.Errorf("platform and architecture is not supported %s %s", runtime.GOOS, runtime.GOARCH)
|
53
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/xattr_linux.go
generated
vendored
Normal file
53
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/xattr_linux.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// +build linux
|
||||
|
||||
package xattr
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/libcontainer/system"
|
||||
)
|
||||
|
||||
func XattrEnabled(path string) bool {
|
||||
if Setxattr(path, "user.test", "") == syscall.ENOTSUP {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func stringsfromByte(buf []byte) (result []string) {
|
||||
offset := 0
|
||||
for index, b := range buf {
|
||||
if b == 0 {
|
||||
result = append(result, string(buf[offset:index]))
|
||||
offset = index + 1
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Listxattr(path string) ([]string, error) {
|
||||
size, err := system.Llistxattr(path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf := make([]byte, size)
|
||||
read, err := system.Llistxattr(path, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names := stringsfromByte(buf[:read])
|
||||
return names, nil
|
||||
}
|
||||
|
||||
func Getxattr(path, attr string) (string, error) {
|
||||
value, err := system.Lgetxattr(path, attr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(value), nil
|
||||
}
|
||||
|
||||
func Setxattr(path, xattr, value string) error {
|
||||
return system.Lsetxattr(path, xattr, []byte(value), 0)
|
||||
}
|
77
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/xattr_test.go
generated
vendored
Normal file
77
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/xattr_test.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// +build linux
|
||||
|
||||
package xattr_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libcontainer/xattr"
|
||||
)
|
||||
|
||||
func testXattr(t *testing.T) {
|
||||
tmp := "xattr_test"
|
||||
out, err := os.OpenFile(tmp, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
t.Fatal("failed")
|
||||
}
|
||||
attr := "user.test"
|
||||
out.Close()
|
||||
|
||||
if !xattr.XattrEnabled(tmp) {
|
||||
t.Log("Disabled")
|
||||
t.Fatal("failed")
|
||||
}
|
||||
t.Log("Success")
|
||||
|
||||
err = xattr.Setxattr(tmp, attr, "test")
|
||||
if err != nil {
|
||||
t.Fatal("failed")
|
||||
}
|
||||
|
||||
var value string
|
||||
value, err = xattr.Getxattr(tmp, attr)
|
||||
if err != nil {
|
||||
t.Fatal("failed")
|
||||
}
|
||||
if value != "test" {
|
||||
t.Fatal("failed")
|
||||
}
|
||||
t.Log("Success")
|
||||
|
||||
var names []string
|
||||
names, err = xattr.Listxattr(tmp)
|
||||
if err != nil {
|
||||
t.Fatal("failed")
|
||||
}
|
||||
|
||||
var found int
|
||||
for _, name := range names {
|
||||
if name == attr {
|
||||
found = 1
|
||||
}
|
||||
}
|
||||
// Listxattr doesn't return trusted.* and system.* namespace
|
||||
// attrs when run in unprevileged mode.
|
||||
if found != 1 {
|
||||
t.Fatal("failed")
|
||||
}
|
||||
t.Log("Success")
|
||||
|
||||
big := "0000000000000000000000000000000000000000000000000000000000000000000008c6419ad822dfe29283fb3ac98dcc5908810cb31f4cfe690040c42c144b7492eicompslf20dxmlpgz"
|
||||
// Test for long xattrs larger than 128 bytes
|
||||
err = xattr.Setxattr(tmp, attr, big)
|
||||
if err != nil {
|
||||
t.Fatal("failed to add long value")
|
||||
}
|
||||
value, err = xattr.Getxattr(tmp, attr)
|
||||
if err != nil {
|
||||
t.Fatal("failed to get long value")
|
||||
}
|
||||
t.Log("Success")
|
||||
|
||||
if value != big {
|
||||
t.Fatal("failed, value doesn't match")
|
||||
}
|
||||
t.Log("Success")
|
||||
}
|
15
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/xattr_unsupported.go
generated
vendored
Normal file
15
Godeps/_workspace/src/github.com/docker/libcontainer/xattr/xattr_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// +build !linux
|
||||
|
||||
package xattr
|
||||
|
||||
func Listxattr(path string) ([]string, error) {
|
||||
return nil, ErrNotSupportedPlatform
|
||||
}
|
||||
|
||||
func Getxattr(path, attr string) (string, error) {
|
||||
return "", ErrNotSupportedPlatform
|
||||
}
|
||||
|
||||
func Setxattr(path, xattr, value string) error {
|
||||
return ErrNotSupportedPlatform
|
||||
}
|
@ -111,6 +111,10 @@ func toContainerStats(libcontainerStats *libcontainer.ContainerStats) *info.Cont
|
||||
ret.DiskIo.IoServiced = DiskStatsCopy(s.BlkioStats.IoServicedRecursive)
|
||||
ret.DiskIo.IoQueued = DiskStatsCopy(s.BlkioStats.IoQueuedRecursive)
|
||||
ret.DiskIo.Sectors = DiskStatsCopy(s.BlkioStats.SectorsRecursive)
|
||||
ret.DiskIo.IoServiceTime = DiskStatsCopy(s.BlkioStats.IoServiceTimeRecursive)
|
||||
ret.DiskIo.IoWaitTime = DiskStatsCopy(s.BlkioStats.IoWaitTimeRecursive)
|
||||
ret.DiskIo.IoMerged = DiskStatsCopy(s.BlkioStats.IoMergedRecursive)
|
||||
ret.DiskIo.IoTime = DiskStatsCopy(s.BlkioStats.IoTimeRecursive)
|
||||
|
||||
ret.Memory = new(info.MemoryStats)
|
||||
ret.Memory.Usage = s.MemoryStats.Usage
|
||||
|
@ -180,10 +180,14 @@ type PerDiskStats struct {
|
||||
}
|
||||
|
||||
type DiskIoStats struct {
|
||||
IoServiceBytes []PerDiskStats `json:"io_service_bytes,omitempty"`
|
||||
IoServiced []PerDiskStats `json:"io_serviced,omitempty"`
|
||||
IoQueued []PerDiskStats `json:"io_queued,omitempty"`
|
||||
Sectors []PerDiskStats `json:"sectors,omitempty"`
|
||||
IoServiceBytes []PerDiskStats `json:"io_service_bytes,omitempty"`
|
||||
IoServiced []PerDiskStats `json:"io_serviced,omitempty"`
|
||||
IoQueued []PerDiskStats `json:"io_queued,omitempty"`
|
||||
Sectors []PerDiskStats `json:"sectors,omitempty"`
|
||||
IoServiceTime []PerDiskStats `json:"io_service_time,omitempty"`
|
||||
IoWaitTime []PerDiskStats `json:"io_wait_time,omitempty"`
|
||||
IoMerged []PerDiskStats `json:"io_merged,omitempty"`
|
||||
IoTime []PerDiskStats `json:"io_time,omitempty"`
|
||||
}
|
||||
|
||||
type MemoryStats struct {
|
||||
|
Loading…
Reference in New Issue
Block a user