Merge pull request #21931 from tiborvass/cherry-picks-1.11.0-rc5

Cherry picks 1.11.0 rc5
This commit is contained in:
Tibor Vass 2016-04-11 16:15:20 -04:00
commit 642c4a7814
37 changed files with 282 additions and 63 deletions

View file

@ -909,6 +909,7 @@ func (container *Container) FullHostname() string {
func (container *Container) RestartManager(reset bool) restartmanager.RestartManager {
if reset {
container.RestartCount = 0
container.restartManager = nil
}
if container.restartManager == nil {
container.restartManager = restartmanager.New(container.HostConfig.RestartPolicy)

View file

@ -216,7 +216,7 @@ __docker_get_log_options() {
gelf_options=("env" "gelf-address" "gelf-compression-level" "gelf-compression-type" "labels" "tag")
journald_options=("env" "labels" "tag")
json_file_options=("env" "labels" "max-file" "max-size")
syslog_options=("syslog-address" "syslog-tls-ca-cert" "syslog-tls-cert" "syslog-tls-key" "syslog-tls-skip-verify" "syslog-facility" "tag")
syslog_options=("syslog-address" "syslog-format" "syslog-tls-ca-cert" "syslog-tls-cert" "syslog-tls-key" "syslog-tls-skip-verify" "syslog-facility" "tag")
splunk_options=("env" "labels" "splunk-caname" "splunk-capath" "splunk-index" "splunk-insecureskipverify" "splunk-source" "splunk-sourcetype" "splunk-token" "splunk-url" "tag")
[[ $log_driver = (awslogs|all) ]] && _describe -t awslogs-options "awslogs options" awslogs_options "$@" && ret=0
@ -236,7 +236,15 @@ __docker_log_options() {
integer ret=1
if compset -P '*='; then
_message 'value' && ret=0
case "${${words[-1]%=*}#*=}" in
(syslog-format)
syslog_format_opts=('rfc3164' 'rfc5424')
_describe -t syslog-format-opts "Syslog format Options" syslog_format_opts && ret=0
;;
*)
_message 'value' && ret=0
;;
esac
else
__docker_get_log_options -qS "=" && ret=0
fi

View file

@ -1092,6 +1092,11 @@ func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
MaxUsage: mem.MaxUsage,
Stats: cgs.MemoryStats.Stats,
Failcnt: mem.Failcnt,
Limit: mem.Limit,
}
// if the container does not set memory limit, use the machineMemory
if mem.Limit > daemon.statsCollector.machineMemory && daemon.statsCollector.machineMemory > 0 {
s.MemoryStats.Limit = daemon.statsCollector.machineMemory
}
if cgs.PidsStats != nil {
s.PidsStats = types.PidsStats{

View file

@ -3,6 +3,7 @@ package daemon
import (
"fmt"
"runtime"
"strings"
"syscall"
"time"
@ -81,7 +82,14 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er
}
if err := daemon.kill(container, sig); err != nil {
return fmt.Errorf("Cannot kill container %s: %s", container.ID, err)
err = fmt.Errorf("Cannot kill container %s: %s", container.ID, err)
// if container or process not exists, ignore the error
if strings.Contains(err.Error(), "container not found") ||
strings.Contains(err.Error(), "no such process") {
logrus.Warnf("%s", err.Error())
} else {
return err
}
}
attributes := map[string]string{

View file

@ -77,6 +77,7 @@ func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
c.Reset(false)
return err
}
daemon.LogContainerEvent(c, "start")
case libcontainerd.StatePause:
c.Paused = true
daemon.LogContainerEvent(c, "pause")

View file

@ -131,7 +131,6 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
return err
}
defer daemon.LogContainerEvent(container, "start") // this is logged even on error
if err := daemon.containerd.Create(container.ID, *spec, libcontainerd.WithRestartManager(container.RestartManager(true))); err != nil {
// if we receive an internal error from the initial start of a container then lets
// return it instead of entering the restart loop
@ -149,6 +148,9 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
}
container.Reset(false)
// start event is logged even on error
daemon.LogContainerEvent(container, "start")
return err
}

View file

@ -14,6 +14,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
"github.com/docker/docker/pkg/pubsub"
sysinfo "github.com/docker/docker/pkg/system"
"github.com/docker/engine-api/types"
"github.com/opencontainers/runc/libcontainer/system"
)
@ -35,6 +36,11 @@ func (daemon *Daemon) newStatsCollector(interval time.Duration) *statsCollector
clockTicksPerSecond: uint64(system.GetClockTicks()),
bufReader: bufio.NewReaderSize(nil, 128),
}
meminfo, err := sysinfo.ReadMemInfo()
if err == nil && meminfo.MemTotal > 0 {
s.machineMemory = uint64(meminfo.MemTotal)
}
go s.run()
return s
}
@ -47,6 +53,7 @@ type statsCollector struct {
clockTicksPerSecond uint64
publishers map[*container.Container]*pubsub.Publisher
bufReader *bufio.Reader
machineMemory uint64
}
// collect registers the container with the collector and adds it to

View file

@ -149,7 +149,7 @@ should implement the following two methods:
"User": "The user identification",
"UserAuthNMethod": "The authentication method used",
"RequestMethod": "The HTTP method",
"RequestUri": "The HTTP request URI",
"RequestURI": "The HTTP request URI",
"RequestBody": "Byte array containing the raw HTTP request body",
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string ",
"RequestStatusCode": "Request status code"
@ -174,7 +174,7 @@ should implement the following two methods:
"User": "The user identification",
"UserAuthNMethod": "The authentication method used",
"RequestMethod": "The HTTP method",
"RequestUri": "The HTTP request URI",
"RequestURI": "The HTTP request URI",
"RequestBody": "Byte array containing the raw HTTP request body",
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string",
"RequestStatusCode": "Request status code",

View file

@ -151,7 +151,7 @@ Create a container
"ExposedPorts": {
"22/tcp": {}
},
"SecurityOpts": [""],
"SecurityOpts": [],
"HostConfig": {
"Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"],

View file

@ -151,7 +151,7 @@ Create a container
"ExposedPorts": {
"22/tcp": {}
},
"SecurityOpts": [""],
"SecurityOpts": [],
"HostConfig": {
"Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"],

View file

@ -168,7 +168,7 @@ Create a container
"RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
"NetworkMode": "bridge",
"Devices": [],
"SecurityOpt": [""]
"SecurityOpt": []
}
}

View file

@ -184,7 +184,7 @@ Create a container
"Devices": [],
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", Config: {} },
"SecurityOpt": [""],
"SecurityOpt": [],
"CgroupParent": ""
}
}

View file

@ -191,7 +191,7 @@ Create a container
"Devices": [],
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", "Config": {} },
"SecurityOpt": [""],
"SecurityOpt": [],
"CgroupParent": ""
}
}

View file

@ -156,7 +156,7 @@ Create a container
},
"Volumes": {
"/volumes/data": {}
}
},
"WorkingDir": "",
"NetworkDisabled": false,
"MacAddress": "12:34:56:78:9a:bc",
@ -193,7 +193,7 @@ Create a container
"Devices": [],
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", "Config": {} },
"SecurityOpt": [""],
"SecurityOpt": [],
"CgroupParent": ""
}
}

View file

@ -160,7 +160,7 @@ Create a container
},
"Volumes": {
"/volumes/data": {}
}
},
"WorkingDir": "",
"NetworkDisabled": false,
"MacAddress": "12:34:56:78:9a:bc",
@ -201,7 +201,7 @@ Create a container
"Devices": [],
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", "Config": {} },
"SecurityOpt": [""],
"SecurityOpt": [],
"CgroupParent": "",
"VolumeDriver": ""
}

View file

@ -248,7 +248,7 @@ Create a container
},
"Volumes": {
"/volumes/data": {}
}
},
"WorkingDir": "",
"NetworkDisabled": false,
"MacAddress": "12:34:56:78:9a:bc",
@ -294,7 +294,7 @@ Create a container
"Devices": [],
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", "Config": {} },
"SecurityOpt": [""],
"SecurityOpt": [],
"CgroupParent": "",
"VolumeDriver": "",
"ShmSize": 67108864

View file

@ -267,7 +267,7 @@ Create a container
},
"Volumes": {
"/volumes/data": {}
}
},
"WorkingDir": "",
"NetworkDisabled": false,
"MacAddress": "12:34:56:78:9a:bc",
@ -313,7 +313,7 @@ Create a container
"Devices": [],
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", "Config": {} },
"SecurityOpt": [""],
"SecurityOpt": [],
"CgroupParent": "",
"VolumeDriver": "",
"ShmSize": 67108864

View file

@ -85,16 +85,16 @@ If nothing matches `REPOSITORY[:TAG]`, the list is empty.
## Listing the full length image IDs
$ docker images --no-trunc
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182 19 hours ago 1.089 GB
committest latest b6fa739cedf5ea12a620a439402b6004d057da800f91c7524b5086a5e4749c9f 19 hours ago 1.089 GB
<none> <none> 78a85c484f71509adeaace20e72e941f6bdd2b25b4c75da8693efd9f61a37921 19 hours ago 1.089 GB
docker latest 30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4 20 hours ago 1.089 GB
<none> <none> 0124422dd9f9cf7ef15c0617cda3931ee68346455441d66ab8bdc5b05e9fdce5 20 hours ago 1.089 GB
<none> <none> 18ad6fad340262ac2a636efd98a6d1f0ea775ae3d45240d3418466495a19a81b 22 hours ago 1.082 GB
<none> <none> f9f1e26352f0a3ba6a0ff68167559f64f3e21ff7ada60366e2d44a04befd1d3a 23 hours ago 1.089 GB
tryout latest 2629d1fa0b81b222fca63371ca16cbf6a0772d07759ff80e8d1369b926940074 23 hours ago 131.5 MB
<none> <none> 5ed6274db6ceb2397844896966ea239290555e74ef307030ebb01ff91b1914df 24 hours ago 1.089 GB
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> sha256:77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182 19 hours ago 1.089 GB
committest latest sha256:b6fa739cedf5ea12a620a439402b6004d057da800f91c7524b5086a5e4749c9f 19 hours ago 1.089 GB
<none> <none> sha256:78a85c484f71509adeaace20e72e941f6bdd2b25b4c75da8693efd9f61a37921 19 hours ago 1.089 GB
docker latest sha256:30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4 20 hours ago 1.089 GB
<none> <none> sha256:0124422dd9f9cf7ef15c0617cda3931ee68346455441d66ab8bdc5b05e9fdce5 20 hours ago 1.089 GB
<none> <none> sha256:18ad6fad340262ac2a636efd98a6d1f0ea775ae3d45240d3418466495a19a81b 22 hours ago 1.082 GB
<none> <none> sha256:f9f1e26352f0a3ba6a0ff68167559f64f3e21ff7ada60366e2d44a04befd1d3a 23 hours ago 1.089 GB
tryout latest sha256:2629d1fa0b81b222fca63371ca16cbf6a0772d07759ff80e8d1369b926940074 23 hours ago 131.5 MB
<none> <none> sha256:5ed6274db6ceb2397844896966ea239290555e74ef307030ebb01ff91b1914df 24 hours ago 1.089 GB
## Listing image digests

View file

@ -608,8 +608,8 @@ with the same logic -- if the original volume was specified with a name it will
to the container
--security-opt="no-new-privileges" : Disable container processes from gaining
new privileges
--security-opt="seccomp:unconfined": Turn off seccomp confinement for the container
--security-opt="seccomp:profile.json: White listed syscalls seccomp Json file to be used as a seccomp filter
--security-opt="seccomp=unconfined": Turn off seccomp confinement for the container
--security-opt="seccomp=profile.json: White listed syscalls seccomp Json file to be used as a seccomp filter
You can override the default labeling scheme for each container by specifying

View file

@ -35,7 +35,7 @@ You name your container by using the `--name` flag, for example launch a new con
$ docker run -d -P --name web training/webapp python app.py
Use the `docker ps` command to see check the name:
Use the `docker ps` command to check the name:
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

View file

@ -20,7 +20,8 @@ clone git github.com/mattn/go-sqlite3 v1.1.0
clone git github.com/mistifyio/go-zfs v2.1.1
clone git github.com/tchap/go-patricia v2.1.0
clone git github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://github.com/golang/net.git
# forked golang.org/x/net package includes a patch for lazy loading trace templates
clone git golang.org/x/net 78cb2c067747f08b343f20614155233ab4ea2ad3 https://github.com/tonistiigi/net.git
clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
clone git github.com/docker/go-connections v0.2.0
@ -29,7 +30,7 @@ clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
clone git github.com/imdario/mergo 0.2.1
#get libnetwork packages
clone git github.com/docker/libnetwork v0.7.0-rc.4
clone git github.com/docker/libnetwork v0.7.0-rc.6
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

View file

@ -227,3 +227,31 @@ func (s *DockerSuite) TestApiStatsContainerNotFound(c *check.C) {
c.Assert(err, checker.IsNil)
c.Assert(status, checker.Equals, http.StatusNotFound)
}
func (s *DockerSuite) TestApiStatsContainerGetMemoryLimit(c *check.C) {
testRequires(c, DaemonIsLinux)
resp, body, err := sockRequestRaw("GET", "/info", nil, "application/json")
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
var info types.Info
err = json.NewDecoder(body).Decode(&info)
c.Assert(err, checker.IsNil)
body.Close()
// don't set a memory limit, the memory limit should be system memory
conName := "foo"
dockerCmd(c, "run", "-d", "--name", conName, "busybox", "top")
c.Assert(waitRun(conName), checker.IsNil)
resp, body, err = sockRequestRaw("GET", fmt.Sprintf("/containers/%s/stats?stream=false", conName), nil, "")
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
c.Assert(resp.Header.Get("Content-Type"), checker.Equals, "application/json")
var v *types.Stats
err = json.NewDecoder(body).Decode(&v)
c.Assert(err, checker.IsNil)
body.Close()
c.Assert(fmt.Sprintf("%d", v.MemoryStats.Limit), checker.Equals, fmt.Sprintf("%d", info.MemTotal))
}

View file

@ -604,3 +604,44 @@ func (s *DockerSuite) TestEventsFilterImageInContainerAction(c *check.C) {
events := strings.Split(strings.TrimSpace(out), "\n")
c.Assert(len(events), checker.GreaterThan, 1, check.Commentf(out))
}
func (s *DockerSuite) TestEventsContainerRestart(c *check.C) {
dockerCmd(c, "run", "-d", "--name=testEvent", "--restart=on-failure:3", "busybox", "false")
// wait until test2 is auto removed.
waitTime := 10 * time.Second
if daemonPlatform == "windows" {
// nslookup isn't present in Windows busybox. Is built-in.
waitTime = 90 * time.Second
}
err := waitInspect("testEvent", "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTime)
c.Assert(err, checker.IsNil)
var (
createCount int
startCount int
dieCount int
)
out, _ := dockerCmd(c, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "-f", "container=testEvent")
events := strings.Split(strings.TrimSpace(out), "\n")
nEvents := len(events)
c.Assert(nEvents, checker.GreaterOrEqualThan, 1) //Missing expected event
actions := eventActionsByIDAndType(c, events, "testEvent", "container")
for _, a := range actions {
switch a {
case "create":
createCount++
case "start":
startCount++
case "die":
dieCount++
}
}
c.Assert(createCount, checker.Equals, 1, check.Commentf("testEvent should be created 1 times: %v", actions))
c.Assert(startCount, checker.Equals, 4, check.Commentf("testEvent should start 4 times: %v", actions))
c.Assert(dieCount, checker.Equals, 4, check.Commentf("testEvent should die 4 times: %v", actions))
}

View file

@ -188,3 +188,62 @@ func (s *DockerSuite) TestRestartWithPolicyUserDefinedNetwork(c *check.C) {
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestRestartPolicyAfterRestart(c *check.C) {
testRequires(c, SameHostDaemon)
out, _ := runSleepingContainer(c, "-d", "--restart=always")
id := strings.TrimSpace(out)
c.Assert(waitRun(id), check.IsNil)
dockerCmd(c, "restart", id)
c.Assert(waitRun(id), check.IsNil)
pidStr := inspectField(c, id, "State.Pid")
pid, err := strconv.Atoi(pidStr)
c.Assert(err, check.IsNil)
p, err := os.FindProcess(pid)
c.Assert(err, check.IsNil)
c.Assert(p, check.NotNil)
err = p.Kill()
c.Assert(err, check.IsNil)
err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second)
c.Assert(err, check.IsNil)
err = waitInspect(id, "{{.State.Status}}", "running", 30*time.Second)
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestRestartContainerwithRestartPolicy(c *check.C) {
out1, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "false")
out2, _ := dockerCmd(c, "run", "-d", "--restart=always", "busybox", "false")
id1 := strings.TrimSpace(string(out1))
id2 := strings.TrimSpace(string(out2))
err := waitInspect(id1, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 30*time.Second)
c.Assert(err, checker.IsNil)
// TODO: fix racey problem during restart:
// https://jenkins.dockerproject.org/job/Docker-PRs-Win2Lin/24665/console
// Error response from daemon: Cannot restart container 6655f620d90b390527db23c0a15b3e46d86a58ecec20a5697ab228d860174251: remove /var/run/docker/libcontainerd/6655f620d90b390527db23c0a15b3e46d86a58ecec20a5697ab228d860174251/rootfs: device or resource busy
if _, _, err := dockerCmdWithError("restart", id1); err != nil {
// if restart met racey problem, try again
time.Sleep(500 * time.Millisecond)
dockerCmd(c, "restart", id1)
}
if _, _, err := dockerCmdWithError("restart", id2); err != nil {
// if restart met racey problem, try again
time.Sleep(500 * time.Millisecond)
dockerCmd(c, "restart", id2)
}
dockerCmd(c, "stop", id1)
dockerCmd(c, "stop", id2)
dockerCmd(c, "start", id1)
dockerCmd(c, "start", id2)
}

View file

@ -134,7 +134,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
defer clnt.unlock(containerID)
if ctr, err := clnt.getContainer(containerID); err == nil {
if ctr.restarting { // docker doesn't actually call start if restart is on atm, but probably should in the future
if ctr.restarting {
ctr.restartManager.Cancel()
ctr.clean()
} else {

View file

@ -121,6 +121,7 @@ func (ctr *container) handleEvent(e *containerd.Event) error {
} else if restart {
st.State = StateRestart
ctr.restarting = true
ctr.client.deleteContainer(e.Id)
go func() {
err := <-wait
ctr.restarting = false

View file

@ -49,6 +49,7 @@ func (bp *BytesPipe) Write(p []byte) (int, error) {
bp.mu.Lock()
defer bp.mu.Unlock()
written := 0
loop0:
for {
if bp.closeErr != nil {
return written, ErrClosed
@ -75,6 +76,9 @@ func (bp *BytesPipe) Write(p []byte) (int, error) {
// block if too much data is still in the buffer
for bp.bufLen >= blockThreshold {
bp.wait.Wait()
if bp.closeErr != nil {
continue loop0
}
}
// allocate slice that has twice the size of the last unless maximum reached

View file

@ -51,7 +51,7 @@ func (rm *restartManager) ShouldRestart(exitCode uint32) (bool, chan error, erro
}()
if rm.canceled {
return false, nil, nil
return false, nil, fmt.Errorf("restartmanager canceled")
}
if rm.active {

View file

@ -1,5 +1,15 @@
# Changelog
## 0.7.0-rc.6 (2016-04-10)
- Flush cached resolver socket on default gateway change
## 0.7.0-rc.5 (2016-04-08)
- Persist ipam driver options
- Fixes https://github.com/docker/libnetwork/issues/1087
- Use go vet from go tool
- Godep update to pick up latest docker/docker packages
- Validate remote driver response using docker plugins package method.
## 0.7.0-rc.4 (2016-04-06)
- Fix the handling for default gateway Endpoint join/leave.

View file

@ -3,6 +3,5 @@ RUN apt-get update && apt-get -y install iptables
RUN go get github.com/tools/godep \
github.com/golang/lint/golint \
golang.org/x/tools/cmd/vet \
golang.org/x/tools/cmd/cover\
github.com/mattn/goveralls

View file

@ -3,7 +3,6 @@ package remote
import (
"fmt"
"net"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
@ -14,10 +13,6 @@ import (
"github.com/docker/libnetwork/types"
)
const (
missingMethod = "404 page not found"
)
type driver struct {
endpoint *plugins.Client
networkType string
@ -260,7 +255,7 @@ func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string
Options: options,
}
err := d.call("ProgramExternalConnectivity", data, &api.ProgramExternalConnectivityResponse{})
if err != nil && strings.Contains(err.Error(), missingMethod) {
if err != nil && plugins.IsNotFound(err) {
// It is not mandatory yet to support this method
return nil
}
@ -274,7 +269,7 @@ func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
EndpointID: eid,
}
err := d.call("RevokeExternalConnectivity", data, &api.RevokeExternalConnectivityResponse{})
if err != nil && strings.Contains(err.Error(), missingMethod) {
if err != nil && plugins.IsNotFound(err) {
// It is not mandatory yet to support this method
return nil
}

View file

@ -477,6 +477,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
ep.Name(), ep.ID(), err)
}
}
if sb.resolver != nil {
sb.resolver.FlushExtServers()
}
}
if !sb.needDefaultGW() {

View file

@ -320,6 +320,13 @@ func (n *network) CopyTo(o datastore.KVObject) error {
dstN.labels[k] = v
}
if n.ipamOptions != nil {
dstN.ipamOptions = make(map[string]string, len(n.ipamOptions))
for k, v := range n.ipamOptions {
dstN.ipamOptions[k] = v
}
}
for _, v4conf := range n.ipamV4Config {
dstV4Conf := &IpamConf{}
v4conf.CopyTo(dstV4Conf)
@ -372,6 +379,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
netMap["scope"] = n.scope
netMap["labels"] = n.labels
netMap["ipamType"] = n.ipamType
netMap["ipamOptions"] = n.ipamOptions
netMap["addrSpace"] = n.addrSpace
netMap["enableIPv6"] = n.enableIPv6
if n.generic != nil {
@ -432,6 +440,15 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
}
}
if v, ok := netMap["ipamOptions"]; ok {
if iOpts, ok := v.(map[string]interface{}); ok {
n.ipamOptions = make(map[string]string, len(iOpts))
for k, v := range iOpts {
n.ipamOptions[k] = v.(string)
}
}
}
if v, ok := netMap["generic"]; ok {
n.generic = v.(map[string]interface{})
// Restore opts in their map[string]string form

View file

@ -45,7 +45,7 @@ const (
ptrIPv6domain = ".ip6.arpa."
respTTL = 600
maxExtDNS = 3 //max number of external servers to try
extIOTimeout = 3 * time.Second
extIOTimeout = 4 * time.Second
defaultRespSize = 512
maxConcurrent = 50
logInterval = 2 * time.Second
@ -158,6 +158,10 @@ func (r *resolver) Start() error {
func (r *resolver) FlushExtServers() {
for i := 0; i < maxExtDNS; i++ {
if r.extDNSList[i].extConn != nil {
r.extDNSList[i].extConn.Close()
}
r.extDNSList[i].extConn = nil
r.extDNSList[i].extOnce = sync.Once{}
}
@ -344,9 +348,6 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
if extDNS.ipStr == "" {
break
}
log.Debugf("Query %s[%d] from %s, forwarding to %s:%s", name, query.Question[0].Qtype,
w.LocalAddr().String(), proto, extDNS.ipStr)
extConnect := func() {
addr := fmt.Sprintf("%s:%d", extDNS.ipStr, 53)
extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
@ -378,6 +379,8 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
if extConn == nil {
continue
}
log.Debugf("Query %s[%d] from %s, forwarding to %s:%s", name, query.Question[0].Qtype,
extConn.LocalAddr().String(), proto, extDNS.ipStr)
// Timeout has to be set for every IO operation.
extConn.SetDeadline(time.Now().Add(extIOTimeout))
@ -424,7 +427,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
break
}
if resp == nil {
if resp == nil || w == nil {
return
}
}

View file

@ -21,11 +21,6 @@ import (
"time"
)
var eventsTmpl = template.Must(template.New("events").Funcs(template.FuncMap{
"elapsed": elapsed,
"trimSpace": strings.TrimSpace,
}).Parse(eventsHTML))
const maxEventsPerLog = 100
type bucket struct {
@ -101,7 +96,7 @@ func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) {
famMu.RLock()
defer famMu.RUnlock()
if err := eventsTmpl.Execute(w, data); err != nil {
if err := eventsTmpl().Execute(w, data); err != nil {
log.Printf("net/trace: Failed executing template: %v", err)
}
}
@ -421,6 +416,19 @@ func freeEventLog(el *eventLog) {
}
}
var eventsTmplCache *template.Template
var eventsTmplOnce sync.Once
func eventsTmpl() *template.Template {
eventsTmplOnce.Do(func() {
eventsTmplCache = template.Must(template.New("events").Funcs(template.FuncMap{
"elapsed": elapsed,
"trimSpace": strings.TrimSpace,
}).Parse(eventsHTML))
})
return eventsTmplCache
}
const eventsHTML = `
<html>
<head>

View file

@ -12,6 +12,7 @@ import (
"html/template"
"log"
"math"
"sync"
"golang.org/x/net/internal/timeseries"
)
@ -320,15 +321,20 @@ func (h *histogram) newData() *data {
func (h *histogram) html() template.HTML {
buf := new(bytes.Buffer)
if err := distTmpl.Execute(buf, h.newData()); err != nil {
if err := distTmpl().Execute(buf, h.newData()); err != nil {
buf.Reset()
log.Printf("net/trace: couldn't execute template: %v", err)
}
return template.HTML(buf.String())
}
// Input: data
var distTmpl = template.Must(template.New("distTmpl").Parse(`
var distTmplCache *template.Template
var distTmplOnce sync.Once
func distTmpl() *template.Template {
distTmplOnce.Do(func() {
// Input: data
distTmplCache = template.Must(template.New("distTmpl").Parse(`
<table>
<tr>
<td style="padding:0.25em">Count: {{.Count}}</td>
@ -354,3 +360,6 @@ var distTmpl = template.Must(template.New("distTmpl").Parse(`
{{end}}
</table>
`))
})
return distTmplCache
}

View file

@ -232,7 +232,7 @@ func Render(w io.Writer, req *http.Request, sensitive bool) {
completedMu.RLock()
defer completedMu.RUnlock()
if err := pageTmpl.ExecuteTemplate(w, "Page", data); err != nil {
if err := pageTmpl().ExecuteTemplate(w, "Page", data); err != nil {
log.Printf("net/trace: Failed executing template: %v", err)
}
}
@ -888,10 +888,18 @@ func elapsed(d time.Duration) string {
return string(b)
}
var pageTmpl = template.Must(template.New("Page").Funcs(template.FuncMap{
"elapsed": elapsed,
"add": func(a, b int) int { return a + b },
}).Parse(pageHTML))
var pageTmplCache *template.Template
var pageTmplOnce sync.Once
func pageTmpl() *template.Template {
pageTmplOnce.Do(func() {
pageTmplCache = template.Must(template.New("Page").Funcs(template.FuncMap{
"elapsed": elapsed,
"add": func(a, b int) int { return a + b },
}).Parse(pageHTML))
})
return pageTmplCache
}
const pageHTML = `
{{template "Prolog" .}}