mirror of https://github.com/docker/docs.git
Merge pull request #1652 from vieux/update_events_1.10
Update events 1.10
This commit is contained in:
commit
af89c1e94a
|
@ -167,7 +167,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/samalba/dockerclient",
|
"ImportPath": "github.com/samalba/dockerclient",
|
||||||
"Rev": "f661dd4754aa5c52da85d04b5871ee0e11f4b59c"
|
"Rev": "3c5f87482db1f82cf350f62aa5214aabd6016502"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
||||||
|
|
|
@ -47,10 +47,10 @@ func (e Error) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) {
|
func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) {
|
||||||
return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout))
|
return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration) (*DockerClient, error) {
|
func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration, setUserTimeout tcpFunc) (*DockerClient, error) {
|
||||||
u, err := url.Parse(daemonUrl)
|
u, err := url.Parse(daemonUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -62,7 +62,7 @@ func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout tim
|
||||||
u.Scheme = "https"
|
u.Scheme = "https"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpClient := newHTTPClient(u, tlsConfig, timeout)
|
httpClient := newHTTPClient(u, tlsConfig, timeout, setUserTimeout)
|
||||||
return &DockerClient{u, httpClient, tlsConfig, 0, nil}, nil
|
return &DockerClient{u, httpClient, tlsConfig, 0, nil}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,8 +920,8 @@ func (client *DockerClient) ConnectNetwork(id, container string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *DockerClient) DisconnectNetwork(id, container string) error {
|
func (client *DockerClient) DisconnectNetwork(id, container string, force bool) error {
|
||||||
data, err := json.Marshal(NetworkDisconnect{Container: container})
|
data, err := json.Marshal(NetworkDisconnect{Container: container, Force: force})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,6 @@ type Client interface {
|
||||||
InspectNetwork(id string) (*NetworkResource, error)
|
InspectNetwork(id string) (*NetworkResource, error)
|
||||||
CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error)
|
CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error)
|
||||||
ConnectNetwork(id, container string) error
|
ConnectNetwork(id, container string) error
|
||||||
DisconnectNetwork(id, container string) error
|
DisconnectNetwork(id, container string, force bool) error
|
||||||
RemoveNetwork(id string) error
|
RemoveNetwork(id string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,8 +216,8 @@ func (client *MockClient) ConnectNetwork(id, container string) error {
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *MockClient) DisconnectNetwork(id, container string) error {
|
func (client *MockClient) DisconnectNetwork(id, container string, force bool) error {
|
||||||
args := client.Mock.Called(id, container)
|
args := client.Mock.Called(id, container, force)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ func (client *NopClient) ConnectNetwork(id, container string) error {
|
||||||
return ErrNoEngine
|
return ErrNoEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *NopClient) DisconnectNetwork(id, container string) error {
|
func (client *NopClient) DisconnectNetwork(id, container string, force bool) error {
|
||||||
return ErrNoEngine
|
return ErrNoEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -279,11 +279,22 @@ type Container struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Actor struct {
|
||||||
|
ID string
|
||||||
|
Attributes map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Id string
|
Status string `json:"status,omitempty"`
|
||||||
Status string
|
ID string `json:"id,omitempty"`
|
||||||
From string
|
From string `json:"from,omitempty"`
|
||||||
Time int64
|
|
||||||
|
Type string
|
||||||
|
Action string
|
||||||
|
Actor Actor
|
||||||
|
|
||||||
|
Time int64 `json:"time,omitempty"`
|
||||||
|
TimeNano int64 `json:"timeNano,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Version struct {
|
type Version struct {
|
||||||
|
@ -551,4 +562,5 @@ type NetworkConnect struct {
|
||||||
// NetworkDisconnect represents the data to be used to disconnect a container from the network
|
// NetworkDisconnect represents the data to be used to disconnect a container from the network
|
||||||
type NetworkDisconnect struct {
|
type NetworkDisconnect struct {
|
||||||
Container string
|
Container string
|
||||||
|
Force bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *http.Client {
|
type tcpFunc func(*net.TCPConn, time.Duration) error
|
||||||
|
|
||||||
|
func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration, setUserTimeout tcpFunc) *http.Client {
|
||||||
httpTransport := &http.Transport{
|
httpTransport := &http.Transport{
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
}
|
}
|
||||||
|
@ -16,7 +18,13 @@ func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *ht
|
||||||
switch u.Scheme {
|
switch u.Scheme {
|
||||||
default:
|
default:
|
||||||
httpTransport.Dial = func(proto, addr string) (net.Conn, error) {
|
httpTransport.Dial = func(proto, addr string) (net.Conn, error) {
|
||||||
return net.DialTimeout(proto, addr, timeout)
|
conn, err := net.DialTimeout(proto, addr, timeout)
|
||||||
|
if tcpConn, ok := conn.(*net.TCPConn); ok && setUserTimeout != nil {
|
||||||
|
// Sender can break TCP connection if the remote side doesn't
|
||||||
|
// acknowledge packets within timeout
|
||||||
|
setUserTimeout(tcpConn, timeout)
|
||||||
|
}
|
||||||
|
return conn, err
|
||||||
}
|
}
|
||||||
case "unix":
|
case "unix":
|
||||||
socketPath := u.Path
|
socketPath := u.Path
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -10,8 +11,6 @@ import (
|
||||||
"github.com/docker/swarm/cluster"
|
"github.com/docker/swarm/cluster"
|
||||||
)
|
)
|
||||||
|
|
||||||
const eventFmt string = "{%q:%q,%q:%q,%q:%q,%q:%d,%q:{%q:%q,%q:%q,%q:%q,%q:%q}}\n"
|
|
||||||
|
|
||||||
// EventsHandler broadcasts events to multiple client listeners.
|
// EventsHandler broadcasts events to multiple client listeners.
|
||||||
type eventsHandler struct {
|
type eventsHandler struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
@ -76,21 +75,42 @@ func (eh *eventsHandler) cleanupHandler(remoteAddr string) {
|
||||||
func (eh *eventsHandler) Handle(e *cluster.Event) error {
|
func (eh *eventsHandler) Handle(e *cluster.Event) error {
|
||||||
eh.RLock()
|
eh.RLock()
|
||||||
|
|
||||||
str := fmt.Sprintf(eventFmt,
|
// remove this hack once 1.10 is broadly adopted
|
||||||
"status", e.Status,
|
from := e.From
|
||||||
"id", e.Id,
|
e.From = e.From + " node:" + e.Engine.Name
|
||||||
"from", e.From+" node:"+e.Engine.Name,
|
|
||||||
"time", e.Time,
|
// Attributes will be nil if the event was sent by engine < 1.10
|
||||||
|
if e.Actor.Attributes == nil {
|
||||||
|
e.Actor.Attributes = make(map[string]string)
|
||||||
|
}
|
||||||
|
e.Actor.Attributes["node.name"] = e.Engine.Name
|
||||||
|
e.Actor.Attributes["node.id"] = e.Engine.ID
|
||||||
|
e.Actor.Attributes["node.addr"] = e.Engine.Addr
|
||||||
|
e.Actor.Attributes["node.ip"] = e.Engine.IP
|
||||||
|
|
||||||
|
data, err := json.Marshal(e)
|
||||||
|
e.From = from
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the node field once 1.10 is broadly adopted & interlock stop relying on it
|
||||||
|
node := fmt.Sprintf(",%q:{%q:%q,%q:%q,%q:%q,%q:%q}}",
|
||||||
"node",
|
"node",
|
||||||
"Name", e.Engine.Name,
|
"Name", e.Engine.Name,
|
||||||
"Id", e.Engine.ID,
|
"Id", e.Engine.ID,
|
||||||
"Addr", e.Engine.Addr,
|
"Addr", e.Engine.Addr,
|
||||||
"Ip", e.Engine.IP)
|
"Ip", e.Engine.IP,
|
||||||
|
)
|
||||||
|
|
||||||
|
// insert Node field
|
||||||
|
data = data[:len(data)-1]
|
||||||
|
data = append(data, []byte(node)...)
|
||||||
|
|
||||||
var failed []string
|
var failed []string
|
||||||
|
|
||||||
for key, w := range eh.ws {
|
for key, w := range eh.ws {
|
||||||
if _, err := fmt.Fprintf(w, str); err != nil {
|
if _, err := fmt.Fprintf(w, string(data)); err != nil {
|
||||||
// collect them to handle later under Lock
|
// collect them to handle later under Lock
|
||||||
failed = append(failed, key)
|
failed = append(failed, key)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -36,22 +37,33 @@ func TestHandle(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
event.Event.Status = "status"
|
event.Event.Status = "status"
|
||||||
event.Event.Id = "id"
|
event.Event.ID = "id"
|
||||||
event.Event.From = "from"
|
event.Event.From = "from"
|
||||||
event.Event.Time = 0
|
event.Event.Time = 0
|
||||||
|
event.Actor.Attributes = make(map[string]string)
|
||||||
|
event.Actor.Attributes["nodevent.name"] = event.Engine.Name
|
||||||
|
event.Actor.Attributes["nodevent.id"] = event.Engine.ID
|
||||||
|
event.Actor.Attributes["nodevent.addr"] = event.Engine.Addr
|
||||||
|
event.Actor.Attributes["nodevent.ip"] = event.Engine.IP
|
||||||
|
|
||||||
assert.NoError(t, eh.Handle(event))
|
assert.NoError(t, eh.Handle(event))
|
||||||
|
|
||||||
str := fmt.Sprintf(eventFmt,
|
event.Event.From = "from node:node_name"
|
||||||
"status", "status",
|
|
||||||
"id", "id",
|
|
||||||
"from", "from node:node_name",
|
|
||||||
"time", 0,
|
|
||||||
"node",
|
|
||||||
"Name", "node_name",
|
|
||||||
"Id", "node_id",
|
|
||||||
"Addr", "node_addr",
|
|
||||||
"Ip", "node_ip")
|
|
||||||
|
|
||||||
assert.Equal(t, str, string(fw.Tmp))
|
data, err := json.Marshal(event)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
node := fmt.Sprintf(",%q:{%q:%q,%q:%q,%q:%q,%q:%q}}",
|
||||||
|
"node",
|
||||||
|
"Name", event.Engine.Name,
|
||||||
|
"Id", event.Engine.ID,
|
||||||
|
"Addr", event.Engine.Addr,
|
||||||
|
"Ip", event.Engine.IP,
|
||||||
|
)
|
||||||
|
|
||||||
|
// insert Node field
|
||||||
|
data = data[:len(data)-1]
|
||||||
|
data = append(data, []byte(node)...)
|
||||||
|
|
||||||
|
assert.Equal(t, string(data), string(fw.Tmp))
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ type logHandler struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *logHandler) Handle(e *cluster.Event) error {
|
func (h *logHandler) Handle(e *cluster.Event) error {
|
||||||
id := e.Id
|
id := e.ID
|
||||||
// Trim IDs to 12 chars.
|
// Trim IDs to 12 chars.
|
||||||
if len(id) > 12 {
|
if len(id) > 12 {
|
||||||
id = id[:12]
|
id = id[:12]
|
||||||
|
|
|
@ -145,7 +145,7 @@ func (e *Engine) Connect(config *tls.Config) error {
|
||||||
}
|
}
|
||||||
e.IP = addr.IP.String()
|
e.IP = addr.IP.String()
|
||||||
|
|
||||||
c, err := dockerclient.NewDockerClientTimeout("tcp://"+e.Addr, config, time.Duration(requestTimeout))
|
c, err := dockerclient.NewDockerClientTimeout("tcp://"+e.Addr, config, time.Duration(requestTimeout), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -627,7 +627,13 @@ func (e *Engine) emitEvent(event string) {
|
||||||
Event: dockerclient.Event{
|
Event: dockerclient.Event{
|
||||||
Status: event,
|
Status: event,
|
||||||
From: "swarm",
|
From: "swarm",
|
||||||
|
Type: "swarm",
|
||||||
|
Action: event,
|
||||||
|
Actor: dockerclient.Actor{
|
||||||
|
Attributes: make(map[string]string),
|
||||||
|
},
|
||||||
Time: time.Now().Unix(),
|
Time: time.Now().Unix(),
|
||||||
|
TimeNano: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
Engine: e,
|
Engine: e,
|
||||||
}
|
}
|
||||||
|
@ -886,12 +892,12 @@ func (e *Engine) handler(ev *dockerclient.Event, _ chan error, args ...interface
|
||||||
case "die", "kill", "oom", "pause", "start", "stop", "unpause", "rename":
|
case "die", "kill", "oom", "pause", "start", "stop", "unpause", "rename":
|
||||||
// If the container state changes, we have to do an inspect in
|
// If the container state changes, we have to do an inspect in
|
||||||
// order to update container.Info and get the new NetworkSettings.
|
// order to update container.Info and get the new NetworkSettings.
|
||||||
e.refreshContainer(ev.Id, true)
|
e.refreshContainer(ev.ID, true)
|
||||||
e.RefreshVolumes()
|
e.RefreshVolumes()
|
||||||
e.RefreshNetworks()
|
e.RefreshNetworks()
|
||||||
default:
|
default:
|
||||||
// Otherwise, do a "soft" refresh of the container.
|
// Otherwise, do a "soft" refresh of the container.
|
||||||
e.refreshContainer(ev.Id, false)
|
e.refreshContainer(ev.ID, false)
|
||||||
e.RefreshVolumes()
|
e.RefreshVolumes()
|
||||||
e.RefreshNetworks()
|
e.RefreshNetworks()
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,7 +212,7 @@ func TestEngineState(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fake an event which will trigger a refresh. The second container will appear.
|
// Fake an event which will trigger a refresh. The second container will appear.
|
||||||
engine.handler(&dockerclient.Event{Id: "two", Status: "created"}, nil)
|
engine.handler(&dockerclient.Event{ID: "two", Status: "created"}, nil)
|
||||||
containers = engine.Containers()
|
containers = engine.Containers()
|
||||||
assert.Len(t, containers, 2)
|
assert.Len(t, containers, 2)
|
||||||
if containers[0].Id != "one" && containers[1].Id != "one" {
|
if containers[0].Id != "one" && containers[1].Id != "one" {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
// Event is exported
|
// Event is exported
|
||||||
type Event struct {
|
type Event struct {
|
||||||
dockerclient.Event
|
dockerclient.Event
|
||||||
Engine *Engine
|
Engine *Engine `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventHandler is exported
|
// EventHandler is exported
|
||||||
|
|
|
@ -26,12 +26,12 @@ function teardown() {
|
||||||
kill "$events_pid"
|
kill "$events_pid"
|
||||||
|
|
||||||
# verify size
|
# verify size
|
||||||
[[ $(wc -l < ${log_file}) == 3 ]]
|
[[ $(wc -l < ${log_file}) -ge 3 ]]
|
||||||
|
|
||||||
# verify content
|
# verify content
|
||||||
run cat "$log_file"
|
run cat "$log_file"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
[[ "${output}" == *"node:node-0"* ]]
|
[[ "${output}" == *"node-0"* ]]
|
||||||
[[ "${output}" == *"create"* ]]
|
[[ "${output}" == *"create"* ]]
|
||||||
[[ "${output}" == *"start"* ]]
|
[[ "${output}" == *"start"* ]]
|
||||||
[[ "${output}" == *"die"* ]]
|
[[ "${output}" == *"die"* ]]
|
||||||
|
|
|
@ -31,7 +31,7 @@ function teardown() {
|
||||||
# verify
|
# verify
|
||||||
run cat "$log_file"
|
run cat "$log_file"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
[[ "${output}" == *"node:node-0"* ]]
|
[[ "${output}" == *"node-0"* ]]
|
||||||
[[ "${output}" == *"create"* ]]
|
[[ "${output}" == *"create"* ]]
|
||||||
[[ "${output}" == *"start"* ]]
|
[[ "${output}" == *"start"* ]]
|
||||||
[[ "${output}" == *"die"* ]]
|
[[ "${output}" == *"die"* ]]
|
||||||
|
|
Loading…
Reference in New Issue