Преглед изворни кода

Merge pull request #264 from mavenugo/mh-ln

datastore support for endpoint, GetObject, DeleteObject and swarm store API upgrade
Jana Radhakrishnan пре 10 година
родитељ
комит
fb06bd5a1a
86 измењених фајлова са 14914 додато и 916 уклоњено
  1. 4 4
      libnetwork/Godeps/Godeps.json
  2. 4 4
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/README.md
  3. 79 19
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery.go
  4. 72 6
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery_test.go
  5. 49 11
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file.go
  6. 64 4
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file_test.go
  7. 93 45
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv.go
  8. 80 6
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv_test.go
  9. 16 8
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes.go
  10. 29 17
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes_test.go
  11. 50 11
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token.go
  12. 22 10
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token_test.go
  13. 25 21
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/README.md
  14. 264 162
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul.go
  15. 69 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul_test.go
  16. 288 108
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd.go
  17. 30 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd_test.go
  18. 15 20
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/helpers.go
  19. 109 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/mock.go
  20. 107 45
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store.go
  21. 401 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store_test.go
  22. 0 60
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/structs.go
  23. 192 94
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper.go
  24. 30 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper_test.go
  25. 22 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/.gitignore
  26. 23 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/LICENSE.md
  27. 3 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/README.md
  28. 179 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors.go
  29. 145 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors_test.go
  30. 14 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/array-access.txt
  31. 86 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/index.html
  32. 286 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/template.txt
  33. 20 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/types_list.txt
  34. 13 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/constants.go
  35. 117 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions.go
  36. 94 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions_test.go
  37. 72 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/doc.go
  38. 98 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/fixture_test.go
  39. 222 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map.go
  40. 10 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_for_test.go
  41. 147 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_test.go
  42. 81 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations.go
  43. 77 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations_test.go
  44. 14 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security.go
  45. 12 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security_test.go
  46. 41 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/simple_example_test.go
  47. 17 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests.go
  48. 24 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests_test.go
  49. 2881 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen.go
  50. 2867 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen_test.go
  51. 13 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value.go
  52. 1 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value_test.go
  53. 853 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go
  54. 791 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions_test.go
  55. 154 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/doc.go
  56. 10 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/errors.go
  57. 265 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go
  58. 511 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions_test.go
  59. 157 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go
  60. 86 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions_test.go
  61. 43 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go
  62. 566 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go
  63. 843 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock_test.go
  64. 5 0
      libnetwork/cmd/dnet/dnet.go
  65. 2 2
      libnetwork/cmd/test/libnetwork.toml
  66. 21 5
      libnetwork/cmd/test/main.go
  67. 59 100
      libnetwork/controller.go
  68. 69 19
      libnetwork/datastore/datastore.go
  69. 30 5
      libnetwork/datastore/datastore_test.go
  70. 35 47
      libnetwork/datastore/mock_store.go
  71. 16 1
      libnetwork/driverapi/driverapi.go
  72. 4 2
      libnetwork/drivers/bridge/bridge.go
  73. 4 1
      libnetwork/drivers/host/host.go
  74. 4 1
      libnetwork/drivers/null/null.go
  75. 4 1
      libnetwork/drivers/remote/driver.go
  76. 4 1
      libnetwork/drivers/windows/windows.go
  77. 0 2
      libnetwork/drivers_freebsd.go
  78. 0 2
      libnetwork/drivers_linux.go
  79. 0 2
      libnetwork/drivers_windows.go
  80. 190 5
      libnetwork/endpoint.go
  81. 65 11
      libnetwork/endpoint_info.go
  82. 29 25
      libnetwork/hostdiscovery/hostdiscovery.go
  83. 2 2
      libnetwork/hostdiscovery/hostdiscovery_test.go
  84. 2 2
      libnetwork/libnetwork_internal_test.go
  85. 127 25
      libnetwork/network.go
  86. 292 0
      libnetwork/store.go

+ 4 - 4
libnetwork/Godeps/Godeps.json

@@ -77,13 +77,13 @@
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/docker/swarm/discovery",
 			"ImportPath": "github.com/docker/swarm/discovery",
-			"Comment": "v0.2.0-333-g54dfabd",
-			"Rev": "54dfabd2521314de1c5b036f6c609efbe09df4ea"
+			"Comment": "v0.3.0-rc2",
+			"Rev": "a5b2e57496762cb6971eb65809b2e428cb179719"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/docker/swarm/pkg/store",
 			"ImportPath": "github.com/docker/swarm/pkg/store",
-			"Comment": "v0.2.0-333-g54dfabd",
-			"Rev": "54dfabd2521314de1c5b036f6c609efbe09df4ea"
+			"Comment": "v0.3.0-rc2",
+			"Rev": "a5b2e57496762cb6971eb65809b2e428cb179719"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/godbus/dbus",
 			"ImportPath": "github.com/godbus/dbus",

+ 4 - 4
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/README.md

@@ -26,7 +26,7 @@ Then we create each node and join them to the cluster.
 # on each of your nodes, start the swarm agent
 # on each of your nodes, start the swarm agent
 #  <node_ip> doesn't have to be public (eg. 192.168.0.X),
 #  <node_ip> doesn't have to be public (eg. 192.168.0.X),
 #  as long as the swarm manager can access it.
 #  as long as the swarm manager can access it.
-$ swarm join --addr=<node_ip:2375> token://<cluster_id>
+$ swarm join --advertise=<node_ip:2375> token://<cluster_id>
 ```
 ```
 
 
 Finally, we start the Swarm manager. This can be on any machine or even
 Finally, we start the Swarm manager. This can be on any machine or even
@@ -95,7 +95,7 @@ On each of your nodes, start the Swarm agent. The node IP address
 doesn't have to be public as long as the swarm manager can access it.
 doesn't have to be public as long as the swarm manager can access it.
 
 
 ```bash
 ```bash
-swarm join --addr=<node_ip:2375> etcd://<etcd_ip>/<path>
+swarm join --advertise=<node_ip:2375> etcd://<etcd_ip>/<path>
 ```
 ```
 
 
 Start the manager on any machine or your laptop.
 Start the manager on any machine or your laptop.
@@ -127,7 +127,7 @@ On each of your nodes, start the Swarm agent. The node IP address
 doesn't need to be public as long as the Swarm manager can access it.
 doesn't need to be public as long as the Swarm manager can access it.
 
 
 ```bash
 ```bash
-swarm join --addr=<node_ip:2375> consul://<consul_addr>/<path>
+swarm join --advertise=<node_ip:2375> consul://<consul_addr>/<path>
 ```
 ```
 
 
 Start the manager on any machine or your laptop.
 Start the manager on any machine or your laptop.
@@ -159,7 +159,7 @@ On each of your nodes, start the Swarm agent. The node IP doesn't have
 to be public as long as the swarm manager can access it.
 to be public as long as the swarm manager can access it.
 
 
 ```bash
 ```bash
-swarm join --addr=<node_ip:2375> zk://<zookeeper_addr1>,<zookeeper_addr2>/<path>
+swarm join --advertise=<node_ip:2375> zk://<zookeeper_addr1>,<zookeeper_addr2>/<path>
 ```
 ```
 
 
 Start the manager on any machine or your laptop.
 Start the manager on any machine or your laptop.

+ 79 - 19
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery.go

@@ -5,17 +5,18 @@ import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
 	"strings"
 	"strings"
+	"time"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
 )
 )
 
 
-// Entry is exported
+// An Entry represents a swarm host.
 type Entry struct {
 type Entry struct {
 	Host string
 	Host string
 	Port string
 	Port string
 }
 }
 
 
-// NewEntry is exported
+// NewEntry creates a new entry.
 func NewEntry(url string) (*Entry, error) {
 func NewEntry(url string) (*Entry, error) {
 	host, port, err := net.SplitHostPort(url)
 	host, port, err := net.SplitHostPort(url)
 	if err != nil {
 	if err != nil {
@@ -24,26 +25,83 @@ func NewEntry(url string) (*Entry, error) {
 	return &Entry{host, port}, nil
 	return &Entry{host, port}, nil
 }
 }
 
 
-func (m Entry) String() string {
-	return fmt.Sprintf("%s:%s", m.Host, m.Port)
+// String returns the string form of an entry.
+func (e *Entry) String() string {
+	return fmt.Sprintf("%s:%s", e.Host, e.Port)
 }
 }
 
 
-// WatchCallback is exported
-type WatchCallback func(entries []*Entry)
+// Equals returns true if cmp contains the same data.
+func (e *Entry) Equals(cmp *Entry) bool {
+	return e.Host == cmp.Host && e.Port == cmp.Port
+}
+
+// Entries is a list of *Entry with some helpers.
+type Entries []*Entry
+
+// Equals returns true if cmp contains the same data.
+func (e Entries) Equals(cmp Entries) bool {
+	// Check if the file has really changed.
+	if len(e) != len(cmp) {
+		return false
+	}
+	for i := range e {
+		if !e[i].Equals(cmp[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// Contains returns true if the Entries contain a given Entry.
+func (e Entries) Contains(entry *Entry) bool {
+	for _, curr := range e {
+		if curr.Equals(entry) {
+			return true
+		}
+	}
+	return false
+}
 
 
-// Discovery is exported
+// Diff compares two entries and returns the added and removed entries.
+func (e Entries) Diff(cmp Entries) (Entries, Entries) {
+	added := Entries{}
+	for _, entry := range cmp {
+		if !e.Contains(entry) {
+			added = append(added, entry)
+		}
+	}
+
+	removed := Entries{}
+	for _, entry := range e {
+		if !cmp.Contains(entry) {
+			removed = append(removed, entry)
+		}
+	}
+
+	return added, removed
+}
+
+// The Discovery interface is implemented by Discovery backends which
+// manage swarm host entries.
 type Discovery interface {
 type Discovery interface {
-	Initialize(string, uint64) error
-	Fetch() ([]*Entry, error)
-	Watch(WatchCallback)
+	// Initialize the discovery with URIs, a heartbeat and a ttl.
+	Initialize(string, time.Duration, time.Duration) error
+
+	// Watch the discovery for entry changes.
+	// Returns a channel that will receive changes or an error.
+	// Providing a non-nil stopCh can be used to stop watching.
+	Watch(stopCh <-chan struct{}) (<-chan Entries, <-chan error)
+
+	// Register to the discovery
 	Register(string) error
 	Register(string) error
 }
 }
 
 
 var (
 var (
 	discoveries map[string]Discovery
 	discoveries map[string]Discovery
-	// ErrNotSupported is exported
+	// ErrNotSupported is returned when a discovery service is not supported.
 	ErrNotSupported = errors.New("discovery service not supported")
 	ErrNotSupported = errors.New("discovery service not supported")
-	// ErrNotImplemented is exported
+	// ErrNotImplemented is returned when discovery feature is not implemented
+	// by discovery backend.
 	ErrNotImplemented = errors.New("not implemented in this discovery service")
 	ErrNotImplemented = errors.New("not implemented in this discovery service")
 )
 )
 
 
@@ -51,7 +109,8 @@ func init() {
 	discoveries = make(map[string]Discovery)
 	discoveries = make(map[string]Discovery)
 }
 }
 
 
-// Register is exported
+// Register makes a discovery backend available by the provided scheme.
+// If Register is called twice with the same scheme an error is returned.
 func Register(scheme string, d Discovery) error {
 func Register(scheme string, d Discovery) error {
 	if _, exists := discoveries[scheme]; exists {
 	if _, exists := discoveries[scheme]; exists {
 		return fmt.Errorf("scheme already registered %s", scheme)
 		return fmt.Errorf("scheme already registered %s", scheme)
@@ -72,22 +131,23 @@ func parse(rawurl string) (string, string) {
 	return parts[0], parts[1]
 	return parts[0], parts[1]
 }
 }
 
 
-// New is exported
-func New(rawurl string, heartbeat uint64) (Discovery, error) {
+// New returns a new Discovery given a URL, heartbeat and ttl settings.
+// Returns an error if the URL scheme is not supported.
+func New(rawurl string, heartbeat time.Duration, ttl time.Duration) (Discovery, error) {
 	scheme, uri := parse(rawurl)
 	scheme, uri := parse(rawurl)
 
 
 	if discovery, exists := discoveries[scheme]; exists {
 	if discovery, exists := discoveries[scheme]; exists {
 		log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service")
 		log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service")
-		err := discovery.Initialize(uri, heartbeat)
+		err := discovery.Initialize(uri, heartbeat, ttl)
 		return discovery, err
 		return discovery, err
 	}
 	}
 
 
 	return nil, ErrNotSupported
 	return nil, ErrNotSupported
 }
 }
 
 
-// CreateEntries is exported
-func CreateEntries(addrs []string) ([]*Entry, error) {
-	entries := []*Entry{}
+// CreateEntries returns an array of entries based on the given addresses.
+func CreateEntries(addrs []string) (Entries, error) {
+	entries := Entries{}
 	if addrs == nil {
 	if addrs == nil {
 		return entries, nil
 		return entries, nil
 	}
 	}

+ 72 - 6
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery_test.go

@@ -8,9 +8,9 @@ import (
 
 
 func TestNewEntry(t *testing.T) {
 func TestNewEntry(t *testing.T) {
 	entry, err := NewEntry("127.0.0.1:2375")
 	entry, err := NewEntry("127.0.0.1:2375")
-	assert.Equal(t, entry.Host, "127.0.0.1")
-	assert.Equal(t, entry.Port, "2375")
 	assert.NoError(t, err)
 	assert.NoError(t, err)
+	assert.True(t, entry.Equals(&Entry{Host: "127.0.0.1", Port: "2375"}))
+	assert.Equal(t, entry.String(), "127.0.0.1:2375")
 
 
 	_, err = NewEntry("127.0.0.1")
 	_, err = NewEntry("127.0.0.1")
 	assert.Error(t, err)
 	assert.Error(t, err)
@@ -40,15 +40,81 @@ func TestParse(t *testing.T) {
 
 
 func TestCreateEntries(t *testing.T) {
 func TestCreateEntries(t *testing.T) {
 	entries, err := CreateEntries(nil)
 	entries, err := CreateEntries(nil)
-	assert.Equal(t, entries, []*Entry{})
+	assert.Equal(t, entries, Entries{})
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
 	entries, err = CreateEntries([]string{"127.0.0.1:2375", "127.0.0.2:2375", ""})
 	entries, err = CreateEntries([]string{"127.0.0.1:2375", "127.0.0.2:2375", ""})
-	assert.Equal(t, len(entries), 2)
-	assert.Equal(t, entries[0].String(), "127.0.0.1:2375")
-	assert.Equal(t, entries[1].String(), "127.0.0.2:2375")
 	assert.NoError(t, err)
 	assert.NoError(t, err)
+	expected := Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+	}
+	assert.True(t, entries.Equals(expected))
 
 
 	_, err = CreateEntries([]string{"127.0.0.1", "127.0.0.2"})
 	_, err = CreateEntries([]string{"127.0.0.1", "127.0.0.2"})
 	assert.Error(t, err)
 	assert.Error(t, err)
 }
 }
+
+func TestContainsEntry(t *testing.T) {
+	entries, err := CreateEntries([]string{"127.0.0.1:2375", "127.0.0.2:2375", ""})
+	assert.NoError(t, err)
+	assert.True(t, entries.Contains(&Entry{Host: "127.0.0.1", Port: "2375"}))
+	assert.False(t, entries.Contains(&Entry{Host: "127.0.0.3", Port: "2375"}))
+}
+
+func TestEntriesEquality(t *testing.T) {
+	entries := Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+	}
+
+	// Same
+	assert.True(t, entries.Equals(Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+	}))
+
+	// Different size
+	assert.False(t, entries.Equals(Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+		&Entry{Host: "127.0.0.3", Port: "2375"},
+	}))
+
+	// Different content
+	assert.False(t, entries.Equals(Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.42", Port: "2375"},
+	}))
+}
+
+func TestEntriesDiff(t *testing.T) {
+	entry1 := &Entry{Host: "1.1.1.1", Port: "1111"}
+	entry2 := &Entry{Host: "2.2.2.2", Port: "2222"}
+	entry3 := &Entry{Host: "3.3.3.3", Port: "3333"}
+	entries := Entries{entry1, entry2}
+
+	// No diff
+	added, removed := entries.Diff(Entries{entry2, entry1})
+	assert.Empty(t, added)
+	assert.Empty(t, removed)
+
+	// Add
+	added, removed = entries.Diff(Entries{entry2, entry3, entry1})
+	assert.Len(t, added, 1)
+	assert.True(t, added.Contains(entry3))
+	assert.Empty(t, removed)
+
+	// Remove
+	added, removed = entries.Diff(Entries{entry2})
+	assert.Empty(t, added)
+	assert.Len(t, removed, 1)
+	assert.True(t, removed.Contains(entry1))
+
+	// Add and remove
+	added, removed = entries.Diff(Entries{entry1, entry3})
+	assert.Len(t, added, 1)
+	assert.True(t, added.Contains(entry3))
+	assert.Len(t, removed, 1)
+	assert.True(t, removed.Contains(entry2))
+}

+ 49 - 11
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file.go

@@ -1,6 +1,7 @@
 package file
 package file
 
 
 import (
 import (
+	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"strings"
 	"strings"
 	"time"
 	"time"
@@ -10,16 +11,21 @@ import (
 
 
 // Discovery is exported
 // Discovery is exported
 type Discovery struct {
 type Discovery struct {
-	heartbeat uint64
+	heartbeat time.Duration
 	path      string
 	path      string
 }
 }
 
 
 func init() {
 func init() {
+	Init()
+}
+
+// Init is exported
+func Init() {
 	discovery.Register("file", &Discovery{})
 	discovery.Register("file", &Discovery{})
 }
 }
 
 
 // Initialize is exported
 // Initialize is exported
-func (s *Discovery) Initialize(path string, heartbeat uint64) error {
+func (s *Discovery) Initialize(path string, heartbeat time.Duration, ttl time.Duration) error {
 	s.path = path
 	s.path = path
 	s.heartbeat = heartbeat
 	s.heartbeat = heartbeat
 	return nil
 	return nil
@@ -46,23 +52,55 @@ func parseFileContent(content []byte) []string {
 	return result
 	return result
 }
 }
 
 
-// Fetch is exported
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
+func (s *Discovery) fetch() (discovery.Entries, error) {
 	fileContent, err := ioutil.ReadFile(s.path)
 	fileContent, err := ioutil.ReadFile(s.path)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to read '%s': %v", s.path, err)
 	}
 	}
 	return discovery.CreateEntries(parseFileContent(fileContent))
 	return discovery.CreateEntries(parseFileContent(fileContent))
 }
 }
 
 
 // Watch is exported
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
-	for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
-		entries, err := s.Fetch()
-		if err == nil {
-			callback(entries)
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	errCh := make(chan error)
+	ticker := time.NewTicker(s.heartbeat)
+
+	go func() {
+		defer close(errCh)
+		defer close(ch)
+
+		// Send the initial entries if available.
+		currentEntries, err := s.fetch()
+		if err != nil {
+			errCh <- err
+		} else {
+			ch <- currentEntries
 		}
 		}
-	}
+
+		// Periodically send updates.
+		for {
+			select {
+			case <-ticker.C:
+				newEntries, err := s.fetch()
+				if err != nil {
+					errCh <- err
+					continue
+				}
+
+				// Check if the file has really changed.
+				if !newEntries.Equals(currentEntries) {
+					ch <- newEntries
+				}
+				currentEntries = newEntries
+			case <-stopCh:
+				ticker.Stop()
+				return
+			}
+		}
+	}()
+
+	return ch, errCh
 }
 }
 
 
 // Register is exported
 // Register is exported

+ 64 - 4
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file_test.go

@@ -1,15 +1,24 @@
 package file
 package file
 
 
 import (
 import (
+	"io/ioutil"
+	"os"
 	"testing"
 	"testing"
 
 
+	"github.com/docker/swarm/discovery"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 )
 )
 
 
 func TestInitialize(t *testing.T) {
 func TestInitialize(t *testing.T) {
-	discovery := &Discovery{}
-	discovery.Initialize("/path/to/file", 0)
-	assert.Equal(t, discovery.path, "/path/to/file")
+	d := &Discovery{}
+	d.Initialize("/path/to/file", 1000, 0)
+	assert.Equal(t, d.path, "/path/to/file")
+}
+
+func TestNew(t *testing.T) {
+	d, err := discovery.New("file:///path/to/file", 0, 0)
+	assert.NoError(t, err)
+	assert.Equal(t, d.(*Discovery).path, "/path/to/file")
 }
 }
 
 
 func TestContent(t *testing.T) {
 func TestContent(t *testing.T) {
@@ -18,6 +27,7 @@ func TestContent(t *testing.T) {
 2.2.2.[2:4]:2222
 2.2.2.[2:4]:2222
 `
 `
 	ips := parseFileContent([]byte(data))
 	ips := parseFileContent([]byte(data))
+	assert.Len(t, ips, 5)
 	assert.Equal(t, ips[0], "1.1.1.1:1111")
 	assert.Equal(t, ips[0], "1.1.1.1:1111")
 	assert.Equal(t, ips[1], "1.1.1.2:1111")
 	assert.Equal(t, ips[1], "1.1.1.2:1111")
 	assert.Equal(t, ips[2], "2.2.2.2:2222")
 	assert.Equal(t, ips[2], "2.2.2.2:2222")
@@ -40,7 +50,57 @@ func TestParsingContentsWithComments(t *testing.T) {
 ### test ###
 ### test ###
 `
 `
 	ips := parseFileContent([]byte(data))
 	ips := parseFileContent([]byte(data))
-	assert.Equal(t, 2, len(ips))
+	assert.Len(t, ips, 2)
 	assert.Equal(t, "1.1.1.1:1111", ips[0])
 	assert.Equal(t, "1.1.1.1:1111", ips[0])
 	assert.Equal(t, "3.3.3.3:3333", ips[1])
 	assert.Equal(t, "3.3.3.3:3333", ips[1])
 }
 }
+
+func TestWatch(t *testing.T) {
+	data := `
+1.1.1.1:1111
+2.2.2.2:2222
+`
+	expected := discovery.Entries{
+		&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
+		&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
+	}
+
+	// Create a temporary file and remove it.
+	tmp, err := ioutil.TempFile(os.TempDir(), "discovery-file-test")
+	assert.NoError(t, err)
+	assert.NoError(t, tmp.Close())
+	assert.NoError(t, os.Remove(tmp.Name()))
+
+	// Set up file discovery.
+	d := &Discovery{}
+	d.Initialize(tmp.Name(), 1000, 0)
+	stopCh := make(chan struct{})
+	ch, errCh := d.Watch(stopCh)
+
+	// Make sure it fires errors since the file doesn't exist.
+	assert.Error(t, <-errCh)
+	// We have to drain the error channel otherwise Watch will get stuck.
+	go func() {
+		for _ = range errCh {
+		}
+	}()
+
+	// Write the file and make sure we get the expected value back.
+	assert.NoError(t, ioutil.WriteFile(tmp.Name(), []byte(data), 0600))
+	assert.Equal(t, expected, <-ch)
+
+	// Add a new entry and look it up.
+	expected = append(expected, &discovery.Entry{Host: "3.3.3.3", Port: "3333"})
+	f, err := os.OpenFile(tmp.Name(), os.O_APPEND|os.O_WRONLY, 0600)
+	assert.NoError(t, err)
+	assert.NotNil(t, f)
+	_, err = f.WriteString("\n3.3.3.3:3333\n")
+	assert.NoError(t, err)
+	f.Close()
+	assert.Equal(t, expected, <-ch)
+
+	// Stop and make sure it closes all channels.
+	close(stopCh)
+	assert.Nil(t, <-ch)
+	assert.Nil(t, <-errCh)
+}

+ 93 - 45
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv.go

@@ -6,87 +6,135 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/swarm/discovery"
 	"github.com/docker/swarm/discovery"
 	"github.com/docker/swarm/pkg/store"
 	"github.com/docker/swarm/pkg/store"
 )
 )
 
 
+const (
+	discoveryPath = "docker/swarm/nodes"
+)
+
 // Discovery is exported
 // Discovery is exported
 type Discovery struct {
 type Discovery struct {
+	backend   store.Backend
 	store     store.Store
 	store     store.Store
-	name      string
 	heartbeat time.Duration
 	heartbeat time.Duration
-	prefix    string
+	ttl       time.Duration
+	path      string
 }
 }
 
 
 func init() {
 func init() {
-	discovery.Register("zk", &Discovery{name: "zk"})
-	discovery.Register("consul", &Discovery{name: "consul"})
-	discovery.Register("etcd", &Discovery{name: "etcd"})
+	Init()
+}
+
+// Init is exported
+func Init() {
+	discovery.Register("zk", &Discovery{backend: store.ZK})
+	discovery.Register("consul", &Discovery{backend: store.CONSUL})
+	discovery.Register("etcd", &Discovery{backend: store.ETCD})
 }
 }
 
 
 // Initialize is exported
 // Initialize is exported
-func (s *Discovery) Initialize(uris string, heartbeat uint64) error {
+func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration) error {
 	var (
 	var (
-		parts = strings.SplitN(uris, "/", 2)
-		ips   = strings.Split(parts[0], ",")
-		addrs []string
-		err   error
+		parts  = strings.SplitN(uris, "/", 2)
+		addrs  = strings.Split(parts[0], ",")
+		prefix = ""
+		err    error
 	)
 	)
 
 
-	if len(parts) != 2 {
-		return fmt.Errorf("invalid format %q, missing <path>", uris)
+	// A custom prefix to the path can be optionally used.
+	if len(parts) == 2 {
+		prefix = parts[1]
 	}
 	}
 
 
-	for _, ip := range ips {
-		addrs = append(addrs, ip)
-	}
-
-	s.heartbeat = time.Duration(heartbeat) * time.Second
-	s.prefix = parts[1]
+	s.heartbeat = heartbeat
+	s.ttl = ttl
+	s.path = path.Join(prefix, discoveryPath)
 
 
 	// Creates a new store, will ignore options given
 	// Creates a new store, will ignore options given
 	// if not supported by the chosen store
 	// if not supported by the chosen store
-	s.store, err = store.CreateStore(
-		s.name, // name of the store
+	s.store, err = store.NewStore(
+		s.backend,
 		addrs,
 		addrs,
-		store.Config{
-			Timeout: s.heartbeat,
+		&store.Config{
+			EphemeralTTL: s.ttl,
 		},
 		},
 	)
 	)
-	if err != nil {
-		return err
-	}
 
 
-	return nil
+	return err
 }
 }
 
 
-// Fetch is exported
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
-	addrs, err := s.store.GetRange(s.prefix)
-	if err != nil {
-		return nil, err
+// Watch the store until either there's a store error or we receive a stop request.
+// Returns false if we shouldn't attempt watching the store anymore (stop request received).
+func (s *Discovery) watchOnce(stopCh <-chan struct{}, watchCh <-chan []*store.KVPair, discoveryCh chan discovery.Entries, errCh chan error) bool {
+	for {
+		select {
+		case pairs := <-watchCh:
+			if pairs == nil {
+				return true
+			}
+
+			log.WithField("discovery", s.backend).Debugf("Watch triggered with %d nodes", len(pairs))
+
+			// Convert `KVPair` into `discovery.Entry`.
+			addrs := make([]string, len(pairs))
+			for _, pair := range pairs {
+				addrs = append(addrs, string(pair.Value))
+			}
+
+			entries, err := discovery.CreateEntries(addrs)
+			if err != nil {
+				errCh <- err
+			} else {
+				discoveryCh <- entries
+			}
+		case <-stopCh:
+			// We were requested to stop watching.
+			return false
+		}
 	}
 	}
-	return discovery.CreateEntries(convertToStringArray(addrs))
 }
 }
 
 
 // Watch is exported
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
-	s.store.WatchRange(s.prefix, "", s.heartbeat, func(kvalues []store.KVEntry) {
-		// Traduce byte array entries to discovery.Entry
-		entries, _ := discovery.CreateEntries(convertToStringArray(kvalues))
-		callback(entries)
-	})
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	errCh := make(chan error)
+
+	go func() {
+		defer close(ch)
+		defer close(errCh)
+
+		// Forever: Create a store watch, watch until we get an error and then try again.
+		// Will only stop if we receive a stopCh request.
+		for {
+			// Set up a watch.
+			watchCh, err := s.store.WatchTree(s.path, stopCh)
+			if err != nil {
+				errCh <- err
+			} else {
+				if !s.watchOnce(stopCh, watchCh, ch, errCh) {
+					return
+				}
+			}
+
+			// If we get here it means the store watch channel was closed. This
+			// is unexpected so let's retry later.
+			errCh <- fmt.Errorf("Unexpected watch error")
+			time.Sleep(s.heartbeat)
+		}
+	}()
+	return ch, errCh
 }
 }
 
 
 // Register is exported
 // Register is exported
 func (s *Discovery) Register(addr string) error {
 func (s *Discovery) Register(addr string) error {
-	err := s.store.Put(path.Join(s.prefix, addr), []byte(addr))
-	return err
+	opts := &store.WriteOptions{Ephemeral: true, Heartbeat: s.heartbeat}
+	return s.store.Put(path.Join(s.path, addr), []byte(addr), opts)
 }
 }
 
 
-func convertToStringArray(entries []store.KVEntry) (addrs []string) {
-	for _, entry := range entries {
-		addrs = append(addrs, string(entry.Value()))
-	}
-	return addrs
+// Store returns the underlying store used by KV discovery.
+func (s *Discovery) Store() store.Store {
+	return s.store
 }
 }

+ 80 - 6
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv_test.go

@@ -1,20 +1,94 @@
 package kv
 package kv
 
 
 import (
 import (
+	"errors"
+	"path"
 	"testing"
 	"testing"
+	"time"
 
 
+	"github.com/docker/swarm/discovery"
+	"github.com/docker/swarm/pkg/store"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 )
 )
 
 
 func TestInitialize(t *testing.T) {
 func TestInitialize(t *testing.T) {
-	discoveryService := &Discovery{}
+	d := &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1", 0, 0))
+	s := d.store.(*store.Mock)
+	assert.Len(t, s.Endpoints, 1)
+	assert.Equal(t, s.Endpoints[0], "127.0.0.1")
+	assert.Equal(t, d.path, discoveryPath)
 
 
-	assert.Equal(t, discoveryService.Initialize("127.0.0.1", 0).Error(), "invalid format \"127.0.0.1\", missing <path>")
+	d = &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1:1234/path", 0, 0))
+	s = d.store.(*store.Mock)
+	assert.Len(t, s.Endpoints, 1)
+	assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234")
+	assert.Equal(t, d.path, "path/"+discoveryPath)
 
 
-	assert.Error(t, discoveryService.Initialize("127.0.0.1/path", 0))
-	assert.Equal(t, discoveryService.prefix, "path")
+	d = &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0))
+	s = d.store.(*store.Mock)
+	assert.Len(t, s.Endpoints, 3)
+	assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234")
+	assert.Equal(t, s.Endpoints[1], "127.0.0.2:1234")
+	assert.Equal(t, s.Endpoints[2], "127.0.0.3:1234")
+	assert.Equal(t, d.path, "path/"+discoveryPath)
+}
+
+func TestWatch(t *testing.T) {
+	d := &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1:1234/path", 0, 0))
+	s := d.store.(*store.Mock)
+
+	mockCh := make(chan []*store.KVPair)
+
+	// The first watch will fail.
+	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, errors.New("test error")).Once()
+	// The second one will succeed.
+	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, nil).Once()
+	expected := discovery.Entries{
+		&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
+		&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
+	}
+	kvs := []*store.KVPair{
+		{Key: path.Join("path", discoveryPath, "1.1.1.1"), Value: []byte("1.1.1.1:1111")},
+		{Key: path.Join("path", discoveryPath, "2.2.2.2"), Value: []byte("2.2.2.2:2222")},
+	}
+
+	stopCh := make(chan struct{})
+	ch, errCh := d.Watch(stopCh)
+
+	// It should fire an error since the first WatchRange call failed.
+	assert.EqualError(t, <-errCh, "test error")
+	// We have to drain the error channel otherwise Watch will get stuck.
+	go func() {
+		for _ = range errCh {
+		}
+	}()
+
+	// Push the entries into the store channel and make sure discovery emits.
+	mockCh <- kvs
+	assert.Equal(t, <-ch, expected)
+
+	// Add a new entry.
+	expected = append(expected, &discovery.Entry{Host: "3.3.3.3", Port: "3333"})
+	kvs = append(kvs, &store.KVPair{Key: path.Join("path", discoveryPath, "3.3.3.3"), Value: []byte("3.3.3.3:3333")})
+	mockCh <- kvs
+	assert.Equal(t, <-ch, expected)
+
+	// Make sure that if an error occurs it retries.
+	// This third call to WatchTree will be checked later by AssertExpectations.
+	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, nil)
+	close(mockCh)
+	// Give it enough time to call WatchTree.
+	time.Sleep(3)
 
 
-	assert.Error(t, discoveryService.Initialize("127.0.0.1,127.0.0.2,127.0.0.3/path", 0))
-	assert.Equal(t, discoveryService.prefix, "path")
+	// Stop and make sure it closes all channels.
+	close(stopCh)
+	assert.Nil(t, <-ch)
+	assert.Nil(t, <-errCh)
 
 
+	s.AssertExpectations(t)
 }
 }

+ 16 - 8
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes.go

@@ -2,21 +2,27 @@ package nodes
 
 
 import (
 import (
 	"strings"
 	"strings"
+	"time"
 
 
 	"github.com/docker/swarm/discovery"
 	"github.com/docker/swarm/discovery"
 )
 )
 
 
 // Discovery is exported
 // Discovery is exported
 type Discovery struct {
 type Discovery struct {
-	entries []*discovery.Entry
+	entries discovery.Entries
 }
 }
 
 
 func init() {
 func init() {
+	Init()
+}
+
+// Init is exported
+func Init() {
 	discovery.Register("nodes", &Discovery{})
 	discovery.Register("nodes", &Discovery{})
 }
 }
 
 
 // Initialize is exported
 // Initialize is exported
-func (s *Discovery) Initialize(uris string, _ uint64) error {
+func (s *Discovery) Initialize(uris string, _ time.Duration, _ time.Duration) error {
 	for _, input := range strings.Split(uris, ",") {
 	for _, input := range strings.Split(uris, ",") {
 		for _, ip := range discovery.Generate(input) {
 		for _, ip := range discovery.Generate(input) {
 			entry, err := discovery.NewEntry(ip)
 			entry, err := discovery.NewEntry(ip)
@@ -30,13 +36,15 @@ func (s *Discovery) Initialize(uris string, _ uint64) error {
 	return nil
 	return nil
 }
 }
 
 
-// Fetch is exported
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
-	return s.entries, nil
-}
-
 // Watch is exported
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	go func() {
+		defer close(ch)
+		ch <- s.entries
+		<-stopCh
+	}()
+	return ch, nil
 }
 }
 
 
 // Register is exported
 // Register is exported

+ 29 - 17
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes_test.go

@@ -3,29 +3,41 @@ package nodes
 import (
 import (
 	"testing"
 	"testing"
 
 
+	"github.com/docker/swarm/discovery"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 )
 )
 
 
-func TestInitialise(t *testing.T) {
-	discovery := &Discovery{}
-	discovery.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0)
-	assert.Equal(t, len(discovery.entries), 2)
-	assert.Equal(t, discovery.entries[0].String(), "1.1.1.1:1111")
-	assert.Equal(t, discovery.entries[1].String(), "2.2.2.2:2222")
+func TestInitialize(t *testing.T) {
+	d := &Discovery{}
+	d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0)
+	assert.Equal(t, len(d.entries), 2)
+	assert.Equal(t, d.entries[0].String(), "1.1.1.1:1111")
+	assert.Equal(t, d.entries[1].String(), "2.2.2.2:2222")
 }
 }
 
 
-func TestInitialiseWithPattern(t *testing.T) {
-	discovery := &Discovery{}
-	discovery.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0)
-	assert.Equal(t, len(discovery.entries), 5)
-	assert.Equal(t, discovery.entries[0].String(), "1.1.1.1:1111")
-	assert.Equal(t, discovery.entries[1].String(), "1.1.1.2:1111")
-	assert.Equal(t, discovery.entries[2].String(), "2.2.2.2:2222")
-	assert.Equal(t, discovery.entries[3].String(), "2.2.2.3:2222")
-	assert.Equal(t, discovery.entries[4].String(), "2.2.2.4:2222")
+func TestInitializeWithPattern(t *testing.T) {
+	d := &Discovery{}
+	d.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0, 0)
+	assert.Equal(t, len(d.entries), 5)
+	assert.Equal(t, d.entries[0].String(), "1.1.1.1:1111")
+	assert.Equal(t, d.entries[1].String(), "1.1.1.2:1111")
+	assert.Equal(t, d.entries[2].String(), "2.2.2.2:2222")
+	assert.Equal(t, d.entries[3].String(), "2.2.2.3:2222")
+	assert.Equal(t, d.entries[4].String(), "2.2.2.4:2222")
+}
+
+func TestWatch(t *testing.T) {
+	d := &Discovery{}
+	d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0)
+	expected := discovery.Entries{
+		&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
+		&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
+	}
+	ch, _ := d.Watch(nil)
+	assert.True(t, expected.Equals(<-ch))
 }
 }
 
 
 func TestRegister(t *testing.T) {
 func TestRegister(t *testing.T) {
-	discovery := &Discovery{}
-	assert.Error(t, discovery.Register("0.0.0.0"))
+	d := &Discovery{}
+	assert.Error(t, d.Register("0.0.0.0"))
 }
 }

+ 50 - 11
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token.go

@@ -17,17 +17,23 @@ const DiscoveryURL = "https://discovery-stage.hub.docker.com/v1"
 
 
 // Discovery is exported
 // Discovery is exported
 type Discovery struct {
 type Discovery struct {
-	heartbeat uint64
+	heartbeat time.Duration
+	ttl       time.Duration
 	url       string
 	url       string
 	token     string
 	token     string
 }
 }
 
 
 func init() {
 func init() {
+	Init()
+}
+
+// Init is exported
+func Init() {
 	discovery.Register("token", &Discovery{})
 	discovery.Register("token", &Discovery{})
 }
 }
 
 
 // Initialize is exported
 // Initialize is exported
-func (s *Discovery) Initialize(urltoken string, heartbeat uint64) error {
+func (s *Discovery) Initialize(urltoken string, heartbeat time.Duration, ttl time.Duration) error {
 	if i := strings.LastIndex(urltoken, "/"); i != -1 {
 	if i := strings.LastIndex(urltoken, "/"); i != -1 {
 		s.url = "https://" + urltoken[:i]
 		s.url = "https://" + urltoken[:i]
 		s.token = urltoken[i+1:]
 		s.token = urltoken[i+1:]
@@ -40,13 +46,13 @@ func (s *Discovery) Initialize(urltoken string, heartbeat uint64) error {
 		return errors.New("token is empty")
 		return errors.New("token is empty")
 	}
 	}
 	s.heartbeat = heartbeat
 	s.heartbeat = heartbeat
+	s.ttl = ttl
 
 
 	return nil
 	return nil
 }
 }
 
 
 // Fetch returns the list of entries for the discovery service at the specified endpoint
 // Fetch returns the list of entries for the discovery service at the specified endpoint
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
-
+func (s *Discovery) fetch() (discovery.Entries, error) {
 	resp, err := http.Get(fmt.Sprintf("%s/%s/%s", s.url, "clusters", s.token))
 	resp, err := http.Get(fmt.Sprintf("%s/%s/%s", s.url, "clusters", s.token))
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -57,7 +63,7 @@ func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
 	var addrs []string
 	var addrs []string
 	if resp.StatusCode == http.StatusOK {
 	if resp.StatusCode == http.StatusOK {
 		if err := json.NewDecoder(resp.Body).Decode(&addrs); err != nil {
 		if err := json.NewDecoder(resp.Body).Decode(&addrs); err != nil {
-			return nil, err
+			return nil, fmt.Errorf("Failed to decode response: %v", err)
 		}
 		}
 	} else {
 	} else {
 		return nil, fmt.Errorf("Failed to fetch entries, Discovery service returned %d HTTP status code", resp.StatusCode)
 		return nil, fmt.Errorf("Failed to fetch entries, Discovery service returned %d HTTP status code", resp.StatusCode)
@@ -67,13 +73,46 @@ func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
 }
 }
 
 
 // Watch is exported
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
-	for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
-		entries, err := s.Fetch()
-		if err == nil {
-			callback(entries)
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	ticker := time.NewTicker(s.heartbeat)
+	errCh := make(chan error)
+
+	go func() {
+		defer close(ch)
+		defer close(errCh)
+
+		// Send the initial entries if available.
+		currentEntries, err := s.fetch()
+		if err != nil {
+			errCh <- err
+		} else {
+			ch <- currentEntries
 		}
 		}
-	}
+
+		// Periodically send updates.
+		for {
+			select {
+			case <-ticker.C:
+				newEntries, err := s.fetch()
+				if err != nil {
+					errCh <- err
+					continue
+				}
+
+				// Check if the file has really changed.
+				if !newEntries.Equals(currentEntries) {
+					ch <- newEntries
+				}
+				currentEntries = newEntries
+			case <-stopCh:
+				ticker.Stop()
+				return
+			}
+		}
+	}()
+
+	return ch, nil
 }
 }
 
 
 // Register adds a new entry identified by the into the discovery service
 // Register adds a new entry identified by the into the discovery service

+ 22 - 10
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token_test.go

@@ -2,35 +2,47 @@ package token
 
 
 import (
 import (
 	"testing"
 	"testing"
+	"time"
 
 
+	"github.com/docker/swarm/discovery"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 )
 )
 
 
 func TestInitialize(t *testing.T) {
 func TestInitialize(t *testing.T) {
 	discovery := &Discovery{}
 	discovery := &Discovery{}
-	err := discovery.Initialize("token", 0)
+	err := discovery.Initialize("token", 0, 0)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	assert.Equal(t, discovery.token, "token")
 	assert.Equal(t, discovery.token, "token")
 	assert.Equal(t, discovery.url, DiscoveryURL)
 	assert.Equal(t, discovery.url, DiscoveryURL)
 
 
-	err = discovery.Initialize("custom/path/token", 0)
+	err = discovery.Initialize("custom/path/token", 0, 0)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	assert.Equal(t, discovery.token, "token")
 	assert.Equal(t, discovery.token, "token")
 	assert.Equal(t, discovery.url, "https://custom/path")
 	assert.Equal(t, discovery.url, "https://custom/path")
 
 
-	err = discovery.Initialize("", 0)
+	err = discovery.Initialize("", 0, 0)
 	assert.Error(t, err)
 	assert.Error(t, err)
 }
 }
 
 
 func TestRegister(t *testing.T) {
 func TestRegister(t *testing.T) {
-	discovery := &Discovery{token: "TEST_TOKEN", url: DiscoveryURL}
+	d := &Discovery{token: "TEST_TOKEN", url: DiscoveryURL, heartbeat: 1}
 	expected := "127.0.0.1:2675"
 	expected := "127.0.0.1:2675"
-	assert.NoError(t, discovery.Register(expected))
-
-	addrs, err := discovery.Fetch()
+	expectedEntries, err := discovery.CreateEntries([]string{expected})
 	assert.NoError(t, err)
 	assert.NoError(t, err)
-	assert.Equal(t, len(addrs), 1)
-	assert.Equal(t, addrs[0].String(), expected)
 
 
-	assert.NoError(t, discovery.Register(expected))
+	// Register
+	assert.NoError(t, d.Register(expected))
+
+	// Watch
+	ch, errCh := d.Watch(nil)
+	select {
+	case entries := <-ch:
+		assert.True(t, entries.Equals(expectedEntries))
+	case err := <-errCh:
+		t.Fatal(err)
+	case <-time.After(5 * time.Second):
+		t.Fatal("Timed out")
+	}
+
+	assert.NoError(t, d.Register(expected))
 }
 }

+ 25 - 21
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/README.md

@@ -1,6 +1,10 @@
 # Storage
 # Storage
 
 
-This package is used by the discovery service to register machines inside the cluster. It is also used to store cluster's metadata.
+The goal of `pkg/store` is to abstract common store operations for multiple Key/Value backends.
+
+For example, you can use it to store your metadata or for service discovery to register machines and endpoints inside your cluster.
+
+As of now, `pkg/store` offers support for `Consul`, `Etcd` and `Zookeeper`.
 
 
 ## Example of usage
 ## Example of usage
 
 
@@ -19,15 +23,16 @@ import (
 
 
 func main() {
 func main() {
 	var (
 	var (
+		// Consul local address
 		client = "localhost:8500"
 		client = "localhost:8500"
 	)
 	)
 
 
 	// Initialize a new store with consul
 	// Initialize a new store with consul
-	kv, err := store.CreateStore(
-		store.Consul,
+	kv, err = store.NewStore(
+		store.CONSUL, // or "consul"
 		[]string{client},
 		[]string{client},
-		store.Config{
-		    Timeout: 10*time.Second
+		&store.Config{
+			Timeout: 10*time.Second,
 		},
 		},
 	)
 	)
 	if err != nil {
 	if err != nil {
@@ -35,17 +40,17 @@ func main() {
 	}
 	}
 
 
 	key := "foo"
 	key := "foo"
-	err = kv.Put(key, []byte("bar"))
+	err = kv.Put(key, []byte("bar"), nil)
 	if err != nil {
 	if err != nil {
 		log.Error("Error trying to put value at key `", key, "`")
 		log.Error("Error trying to put value at key `", key, "`")
 	}
 	}
 
 
-	value, _, err := kv.Get(key)
+	pair, err := kv.Get(key)
 	if err != nil {
 	if err != nil {
 		log.Error("Error trying accessing value at key `", key, "`")
 		log.Error("Error trying accessing value at key `", key, "`")
 	}
 	}
 
 
-	log.Info("value: ", string(value))
+	log.Info("value: ", string(pair.Value))
 }
 }
 ```
 ```
 
 
@@ -57,23 +62,22 @@ A new **storage backend** should include those calls:
 
 
 ```go
 ```go
 type Store interface {
 type Store interface {
-	Put(key string, value []byte) error
-	Get(key string) (value []byte, lastIndex uint64, err error)
+	Put(key string, value []byte, options *WriteOptions) error
+	Get(key string) (*KVPair, error)
 	Delete(key string) error
 	Delete(key string) error
 	Exists(key string) (bool, error)
 	Exists(key string) (bool, error)
-	Watch(key string, ttl uint64, callback WatchCallback) error
-	CancelWatch(key string) error
-	Acquire(key string, value []byte) (string, error)
-	Release(session string) error
-	GetRange(prefix string) (value [][]byte, err error)
-	DeleteRange(prefix string) error
-	WatchRange(prefix string, filter string, heartbeat uint64, callback WatchCallback) error
-	CancelWatchRange(prefix string) error
-	AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error)
-	AtomicDelete(key string, oldValue []byte, index uint64) (bool, error)
+	Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error)
+	WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error)
+	NewLock(key string, options *LockOptions) (Locker, error)
+	List(prefix string) ([]*KVPair, error)
+	DeleteTree(prefix string) error
+	AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
+	AtomicDelete(key string, previous *KVPair) (bool, error)
 }
 }
 ```
 ```
 
 
-To be elligible as a **discovery backend** only, a K/V store implementation should at least offer `Get`, `Put`, `WatchRange`, `GetRange`.
+In the case of Swarm and to be eligible as a **discovery backend** only, a K/V store implementation should at least offer `Get`, `Put`, `WatchTree` and `List`.
+
+`Put` should support usage of `ttl` to be able to remove entries in case of a node failure.
 
 
 You can get inspiration from existing backends to create a new one. This interface could be subject to changes to improve the experience of using the library and contributing to a new backend.
 You can get inspiration from existing backends to create a new one. This interface could be subject to changes to improve the experience of using the library and contributing to a new backend.

+ 264 - 162
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul.go

@@ -2,40 +2,39 @@ package store
 
 
 import (
 import (
 	"crypto/tls"
 	"crypto/tls"
-	"errors"
 	"net/http"
 	"net/http"
+	"strings"
+	"sync"
 	"time"
 	"time"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
 	api "github.com/hashicorp/consul/api"
 	api "github.com/hashicorp/consul/api"
 )
 )
 
 
-var (
-	// ErrSessionUndefined is exported
-	ErrSessionUndefined = errors.New("Session does not exist")
+const (
+	// DefaultWatchWaitTime is how long we block for at a time to check if the
+	// watched key has changed.  This affects the minimum time it takes to
+	// cancel a watch.
+	DefaultWatchWaitTime = 15 * time.Second
 )
 )
 
 
-// Consul embeds the client and watches/lock sessions
+// Consul embeds the client and watches
 type Consul struct {
 type Consul struct {
-	config   *api.Config
-	client   *api.Client
-	sessions map[string]*api.Session
-	watches  map[string]*Watch
+	sync.Mutex
+	config           *api.Config
+	client           *api.Client
+	ephemeralTTL     time.Duration
+	ephemeralSession string
 }
 }
 
 
-// Watch embeds the event channel and the
-// refresh interval
-type Watch struct {
-	LastIndex uint64
-	Interval  time.Duration
+type consulLock struct {
+	lock *api.Lock
 }
 }
 
 
 // InitializeConsul creates a new Consul client given
 // InitializeConsul creates a new Consul client given
 // a list of endpoints and optional tls config
 // a list of endpoints and optional tls config
-func InitializeConsul(endpoints []string, options Config) (Store, error) {
+func InitializeConsul(endpoints []string, options *Config) (Store, error) {
 	s := &Consul{}
 	s := &Consul{}
-	s.sessions = make(map[string]*api.Session)
-	s.watches = make(map[string]*Watch)
 
 
 	// Create Consul client
 	// Create Consul client
 	config := api.DefaultConfig()
 	config := api.DefaultConfig()
@@ -44,12 +43,17 @@ func InitializeConsul(endpoints []string, options Config) (Store, error) {
 	config.Address = endpoints[0]
 	config.Address = endpoints[0]
 	config.Scheme = "http"
 	config.Scheme = "http"
 
 
-	if options.TLS != nil {
-		s.setTLS(options.TLS)
-	}
-
-	if options.Timeout != 0 {
-		s.setTimeout(options.Timeout)
+	// Set options
+	if options != nil {
+		if options.TLS != nil {
+			s.setTLS(options.TLS)
+		}
+		if options.ConnectionTimeout != 0 {
+			s.setTimeout(options.ConnectionTimeout)
+		}
+		if options.EphemeralTTL != 0 {
+			s.setEphemeralTTL(options.EphemeralTTL)
+		}
 	}
 	}
 
 
 	// Creates a new client
 	// Creates a new client
@@ -76,222 +80,315 @@ func (s *Consul) setTimeout(time time.Duration) {
 	s.config.WaitTime = time
 	s.config.WaitTime = time
 }
 }
 
 
+// SetEphemeralTTL sets the ttl for ephemeral nodes
+func (s *Consul) setEphemeralTTL(ttl time.Duration) {
+	s.ephemeralTTL = ttl
+}
+
+// createEphemeralSession creates the global session
+// once that is used to delete keys at node failure
+func (s *Consul) createEphemeralSession() error {
+	s.Lock()
+	defer s.Unlock()
+
+	// Create new session
+	if s.ephemeralSession == "" {
+		entry := &api.SessionEntry{
+			Behavior: api.SessionBehaviorDelete,
+			TTL:      s.ephemeralTTL.String(),
+		}
+		// Create global ephemeral keys session
+		session, _, err := s.client.Session().Create(entry, nil)
+		if err != nil {
+			return err
+		}
+		s.ephemeralSession = session
+	}
+	return nil
+}
+
+// checkActiveSession checks if the key already has a session attached
+func (s *Consul) checkActiveSession(key string) (string, error) {
+	pair, _, err := s.client.KV().Get(key, nil)
+	if err != nil {
+		return "", err
+	}
+	if pair != nil && pair.Session != "" {
+		return pair.Session, nil
+	}
+	return "", nil
+}
+
+// Normalize the key for usage in Consul
+func (s *Consul) normalize(key string) string {
+	key = normalize(key)
+	return strings.TrimPrefix(key, "/")
+}
+
 // Get the value at "key", returns the last modified index
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
 // to use in conjunction to CAS calls
-func (s *Consul) Get(key string) (value []byte, lastIndex uint64, err error) {
-	pair, meta, err := s.client.KV().Get(partialFormat(key), nil)
+func (s *Consul) Get(key string) (*KVPair, error) {
+	options := &api.QueryOptions{
+		AllowStale:        false,
+		RequireConsistent: true,
+	}
+	pair, meta, err := s.client.KV().Get(s.normalize(key), options)
 	if err != nil {
 	if err != nil {
-		return nil, 0, err
+		return nil, err
 	}
 	}
 	if pair == nil {
 	if pair == nil {
-		return nil, 0, ErrKeyNotFound
+		return nil, ErrKeyNotFound
 	}
 	}
-	return pair.Value, meta.LastIndex, nil
+	return &KVPair{pair.Key, pair.Value, meta.LastIndex}, nil
 }
 }
 
 
 // Put a value at "key"
 // Put a value at "key"
-func (s *Consul) Put(key string, value []byte) error {
-	p := &api.KVPair{Key: partialFormat(key), Value: value}
-	if s.client == nil {
-		log.Error("Error initializing client")
+func (s *Consul) Put(key string, value []byte, opts *WriteOptions) error {
+
+	key = s.normalize(key)
+
+	p := &api.KVPair{
+		Key:   key,
+		Value: value,
 	}
 	}
+
+	if opts != nil && opts.Ephemeral {
+		// Check if there is any previous session with an active TTL
+		previous, err := s.checkActiveSession(key)
+		if err != nil {
+			return err
+		}
+
+		// Create the global ephemeral session if it does not exist yet
+		if s.ephemeralSession == "" {
+			if err = s.createEphemeralSession(); err != nil {
+				return err
+			}
+		}
+
+		// If a previous session is still active for that key, use it
+		// else we use the global ephemeral session
+		if previous != "" {
+			p.Session = previous
+		} else {
+			p.Session = s.ephemeralSession
+		}
+
+		// Create lock option with the
+		// EphemeralSession
+		lockOpts := &api.LockOptions{
+			Key:     key,
+			Session: p.Session,
+		}
+
+		// Lock and ignore if lock is held
+		// It's just a placeholder for the
+		// ephemeral behavior
+		lock, _ := s.client.LockOpts(lockOpts)
+		if lock != nil {
+			lock.Lock(nil)
+		}
+
+		// Renew the session
+		_, _, err = s.client.Session().Renew(p.Session, nil)
+		if err != nil {
+			s.ephemeralSession = ""
+			return err
+		}
+	}
+
 	_, err := s.client.KV().Put(p, nil)
 	_, err := s.client.KV().Put(p, nil)
 	return err
 	return err
 }
 }
 
 
 // Delete a value at "key"
 // Delete a value at "key"
 func (s *Consul) Delete(key string) error {
 func (s *Consul) Delete(key string) error {
-	_, err := s.client.KV().Delete(partialFormat(key), nil)
+	_, err := s.client.KV().Delete(s.normalize(key), nil)
 	return err
 	return err
 }
 }
 
 
 // Exists checks that the key exists inside the store
 // Exists checks that the key exists inside the store
 func (s *Consul) Exists(key string) (bool, error) {
 func (s *Consul) Exists(key string) (bool, error) {
-	_, _, err := s.Get(key)
+	_, err := s.Get(key)
 	if err != nil && err == ErrKeyNotFound {
 	if err != nil && err == ErrKeyNotFound {
 		return false, err
 		return false, err
 	}
 	}
 	return true, nil
 	return true, nil
 }
 }
 
 
-// GetRange gets a range of values at "directory"
-func (s *Consul) GetRange(prefix string) (kvi []KVEntry, err error) {
-	pairs, _, err := s.client.KV().List(partialFormat(prefix), nil)
+// List the content of a given prefix
+func (s *Consul) List(prefix string) ([]*KVPair, error) {
+	pairs, _, err := s.client.KV().List(s.normalize(prefix), nil)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	if len(pairs) == 0 {
 	if len(pairs) == 0 {
 		return nil, ErrKeyNotFound
 		return nil, ErrKeyNotFound
 	}
 	}
+	kv := []*KVPair{}
 	for _, pair := range pairs {
 	for _, pair := range pairs {
 		if pair.Key == prefix {
 		if pair.Key == prefix {
 			continue
 			continue
 		}
 		}
-		kvi = append(kvi, &kviTuple{pair.Key, pair.Value, pair.ModifyIndex})
+		kv = append(kv, &KVPair{pair.Key, pair.Value, pair.ModifyIndex})
 	}
 	}
-	return kvi, nil
+	return kv, nil
 }
 }
 
 
-// DeleteRange deletes a range of values at "directory"
-func (s *Consul) DeleteRange(prefix string) error {
-	_, err := s.client.KV().DeleteTree(partialFormat(prefix), nil)
+// DeleteTree deletes a range of keys based on prefix
+func (s *Consul) DeleteTree(prefix string) error {
+	_, err := s.client.KV().DeleteTree(s.normalize(prefix), nil)
 	return err
 	return err
 }
 }
 
 
-// Watch a single key for modifications
-func (s *Consul) Watch(key string, heartbeat time.Duration, callback WatchCallback) error {
-	fkey := partialFormat(key)
-
-	// We get the last index first
-	_, meta, err := s.client.KV().Get(fkey, nil)
-	if err != nil {
-		return err
-	}
+// Watch changes on a key.
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Consul) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	key = s.normalize(key)
+	kv := s.client.KV()
+	watchCh := make(chan *KVPair)
 
 
-	// Add watch to map
-	s.watches[fkey] = &Watch{LastIndex: meta.LastIndex, Interval: heartbeat}
-	eventChan := s.waitForChange(fkey)
+	go func() {
+		defer close(watchCh)
 
 
-	for _ = range eventChan {
-		log.WithField("name", "consul").Debug("Key watch triggered")
-		entry, index, err := s.Get(key)
-		if err != nil {
-			log.Error("Cannot refresh the key: ", fkey, ", cancelling watch")
-			s.watches[fkey] = nil
-			return err
+		// Use a wait time in order to check if we should quit from time to
+		// time.
+		opts := &api.QueryOptions{WaitTime: DefaultWatchWaitTime}
+		for {
+			// Check if we should quit
+			select {
+			case <-stopCh:
+				return
+			default:
+			}
+			pair, meta, err := kv.Get(key, opts)
+			if err != nil {
+				log.Errorf("consul: %v", err)
+				return
+			}
+			// If LastIndex didn't change then it means `Get` returned because
+			// of the WaitTime and the key didn't change.
+			if opts.WaitIndex == meta.LastIndex {
+				continue
+			}
+			opts.WaitIndex = meta.LastIndex
+			// FIXME: What happens when a key is deleted?
+			if pair != nil {
+				watchCh <- &KVPair{pair.Key, pair.Value, pair.ModifyIndex}
+			}
 		}
 		}
+	}()
 
 
-		value := []KVEntry{&kviTuple{key, entry, index}}
-		callback(value)
-	}
-
-	return nil
+	return watchCh, nil
 }
 }
 
 
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *Consul) CancelWatch(key string) error {
-	key = partialFormat(key)
-	if _, ok := s.watches[key]; !ok {
-		log.Error("Chan does not exist for key: ", key)
-		return ErrWatchDoesNotExist
-	}
-	s.watches[key] = nil
-	return nil
-}
-
-// Internal function to check if a key has changed
-func (s *Consul) waitForChange(key string) <-chan uint64 {
-	ch := make(chan uint64)
+// WatchTree watches changes on a "directory"
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Consul) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	prefix = s.normalize(prefix)
 	kv := s.client.KV()
 	kv := s.client.KV()
+	watchCh := make(chan []*KVPair)
+
 	go func() {
 	go func() {
+		defer close(watchCh)
+
+		// Use a wait time in order to check if we should quit from time to
+		// time.
+		opts := &api.QueryOptions{WaitTime: DefaultWatchWaitTime}
 		for {
 		for {
-			watch, ok := s.watches[key]
-			if !ok {
-				log.Error("Cannot access last index for key: ", key, " closing channel")
-				break
-			}
-			option := &api.QueryOptions{
-				WaitIndex: watch.LastIndex,
-				WaitTime:  watch.Interval,
+			// Check if we should quit
+			select {
+			case <-stopCh:
+				return
+			default:
 			}
 			}
-			_, meta, err := kv.List(key, option)
+
+			pairs, meta, err := kv.List(prefix, opts)
 			if err != nil {
 			if err != nil {
-				log.WithField("name", "consul").Errorf("Discovery error: %v", err)
-				break
+				log.Errorf("consul: %v", err)
+				return
+			}
+			// If LastIndex didn't change then it means `Get` returned because
+			// of the WaitTime and the key didn't change.
+			if opts.WaitIndex == meta.LastIndex {
+				continue
 			}
 			}
-			watch.LastIndex = meta.LastIndex
-			ch <- watch.LastIndex
+			opts.WaitIndex = meta.LastIndex
+			kv := []*KVPair{}
+			for _, pair := range pairs {
+				if pair.Key == prefix {
+					continue
+				}
+				kv = append(kv, &KVPair{pair.Key, pair.Value, pair.ModifyIndex})
+			}
+			watchCh <- kv
 		}
 		}
-		close(ch)
 	}()
 	}()
-	return ch
-}
 
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *Consul) WatchRange(prefix string, filter string, heartbeat time.Duration, callback WatchCallback) error {
-	fprefix := partialFormat(prefix)
+	return watchCh, nil
+}
 
 
-	// We get the last index first
-	_, meta, err := s.client.KV().Get(prefix, nil)
-	if err != nil {
-		return err
+// NewLock returns a handle to a lock struct which can be used to acquire and
+// release the mutex.
+func (s *Consul) NewLock(key string, options *LockOptions) (Locker, error) {
+	consulOpts := &api.LockOptions{
+		Key: s.normalize(key),
 	}
 	}
-
-	// Add watch to map
-	s.watches[fprefix] = &Watch{LastIndex: meta.LastIndex, Interval: heartbeat}
-	eventChan := s.waitForChange(fprefix)
-
-	for _ = range eventChan {
-		log.WithField("name", "consul").Debug("Key watch triggered")
-		kvi, err := s.GetRange(prefix)
-		if err != nil {
-			log.Error("Cannot refresh keys with prefix: ", fprefix, ", cancelling watch")
-			s.watches[fprefix] = nil
-			return err
-		}
-		callback(kvi)
+	if options != nil {
+		consulOpts.Value = options.Value
 	}
 	}
-
-	return nil
-}
-
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *Consul) CancelWatchRange(prefix string) error {
-	return s.CancelWatch(prefix)
-}
-
-// Acquire the lock for "key"/"directory"
-func (s *Consul) Acquire(key string, value []byte) (string, error) {
-	key = partialFormat(key)
-	session := s.client.Session()
-	id, _, err := session.CreateNoChecks(nil, nil)
+	l, err := s.client.LockOpts(consulOpts)
 	if err != nil {
 	if err != nil {
-		return "", err
-	}
-
-	// Add session to map
-	s.sessions[id] = session
-
-	p := &api.KVPair{Key: key, Value: value, Session: id}
-	if work, _, err := s.client.KV().Acquire(p, nil); err != nil {
-		return "", err
-	} else if !work {
-		return "", ErrCannotLock
+		return nil, err
 	}
 	}
+	return &consulLock{lock: l}, nil
+}
 
 
-	return id, nil
+// Lock attempts to acquire the lock and blocks while doing so.
+// Returns a channel that is closed if our lock is lost or an error.
+func (l *consulLock) Lock() (<-chan struct{}, error) {
+	return l.lock.Lock(nil)
 }
 }
 
 
-// Release the lock for "key"/"directory"
-func (s *Consul) Release(id string) error {
-	if _, ok := s.sessions[id]; !ok {
-		log.Error("Lock session does not exist")
-		return ErrSessionUndefined
-	}
-	session := s.sessions[id]
-	session.Destroy(id, nil)
-	s.sessions[id] = nil
-	return nil
+// Unlock released the lock. It is an error to call this
+// if the lock is not currently held.
+func (l *consulLock) Unlock() error {
+	return l.lock.Unlock()
 }
 }
 
 
 // AtomicPut put a value at "key" if the key has not been
 // AtomicPut put a value at "key" if the key has not been
 // modified in the meantime, throws an error if this is the case
 // modified in the meantime, throws an error if this is the case
-func (s *Consul) AtomicPut(key string, _ []byte, newValue []byte, index uint64) (bool, error) {
-	p := &api.KVPair{Key: partialFormat(key), Value: newValue, ModifyIndex: index}
+func (s *Consul) AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error) {
+	if previous == nil {
+		return false, nil, ErrPreviousNotSpecified
+	}
+
+	p := &api.KVPair{Key: s.normalize(key), Value: value, ModifyIndex: previous.LastIndex}
 	if work, _, err := s.client.KV().CAS(p, nil); err != nil {
 	if work, _, err := s.client.KV().CAS(p, nil); err != nil {
-		return false, err
+		return false, nil, err
 	} else if !work {
 	} else if !work {
-		return false, ErrKeyModified
+		return false, nil, ErrKeyModified
 	}
 	}
-	return true, nil
+
+	pair, err := s.Get(key)
+	if err != nil {
+		return false, nil, err
+	}
+	return true, pair, nil
 }
 }
 
 
 // AtomicDelete deletes a value at "key" if the key has not
 // AtomicDelete deletes a value at "key" if the key has not
 // been modified in the meantime, throws an error if this is the case
 // been modified in the meantime, throws an error if this is the case
-func (s *Consul) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
-	p := &api.KVPair{Key: partialFormat(key), ModifyIndex: index}
+func (s *Consul) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	if previous == nil {
+		return false, ErrPreviousNotSpecified
+	}
+
+	p := &api.KVPair{Key: s.normalize(key), ModifyIndex: previous.LastIndex}
 	if work, _, err := s.client.KV().DeleteCAS(p, nil); err != nil {
 	if work, _, err := s.client.KV().DeleteCAS(p, nil); err != nil {
 		return false, err
 		return false, err
 	} else if !work {
 	} else if !work {
@@ -299,3 +396,8 @@ func (s *Consul) AtomicDelete(key string, oldValue []byte, index uint64) (bool,
 	}
 	}
 	return true, nil
 	return true, nil
 }
 }
+
+// Close closes the client connection
+func (s *Consul) Close() {
+	return
+}

+ 69 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul_test.go

@@ -0,0 +1,69 @@
+package store
+
+import (
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func makeConsulClient(t *testing.T) Store {
+	client := "localhost:8500"
+
+	kv, err := NewStore(
+		CONSUL,
+		[]string{client},
+		&Config{
+			ConnectionTimeout: 3 * time.Second,
+			EphemeralTTL:      2 * time.Second,
+		},
+	)
+	if err != nil {
+		t.Fatalf("cannot create store: %v", err)
+	}
+
+	return kv
+}
+
+func TestConsulStore(t *testing.T) {
+	kv := makeConsulClient(t)
+
+	testStore(t, kv)
+}
+
+func TestCreateEphemeralSession(t *testing.T) {
+	kv := makeConsulClient(t)
+
+	consul := kv.(*Consul)
+
+	err := consul.createEphemeralSession()
+	assert.NoError(t, err)
+	assert.NotEqual(t, consul.ephemeralSession, "")
+}
+
+func TestCheckActiveSession(t *testing.T) {
+	kv := makeConsulClient(t)
+
+	consul := kv.(*Consul)
+
+	key := "foo"
+	value := []byte("bar")
+
+	// Put the first key with the Ephemeral flag
+	err := kv.Put(key, value, &WriteOptions{Ephemeral: true})
+	assert.NoError(t, err)
+
+	// Session should not be empty
+	session, err := consul.checkActiveSession(key)
+	assert.NoError(t, err)
+	assert.NotEqual(t, session, "")
+
+	// Delete the key
+	err = kv.Delete(key)
+	assert.NoError(t, err)
+
+	// Check the session again, it should return nothing
+	session, err = consul.checkActiveSession(key)
+	assert.NoError(t, err)
+	assert.Equal(t, session, "")
+}

+ 288 - 108
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd.go

@@ -7,33 +7,59 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	log "github.com/Sirupsen/logrus"
 	etcd "github.com/coreos/go-etcd/etcd"
 	etcd "github.com/coreos/go-etcd/etcd"
 )
 )
 
 
 // Etcd embeds the client
 // Etcd embeds the client
 type Etcd struct {
 type Etcd struct {
-	client  *etcd.Client
-	watches map[string]chan<- bool
+	client       *etcd.Client
+	ephemeralTTL time.Duration
 }
 }
 
 
+type etcdLock struct {
+	client   *etcd.Client
+	stopLock chan struct{}
+	key      string
+	value    string
+	last     *etcd.Response
+	ttl      uint64
+}
+
+const (
+	defaultLockTTL    = 20 * time.Second
+	defaultUpdateTime = 5 * time.Second
+
+	// periodicSync is the time between each call to SyncCluster
+	periodicSync = 10 * time.Minute
+)
+
 // InitializeEtcd creates a new Etcd client given
 // InitializeEtcd creates a new Etcd client given
 // a list of endpoints and optional tls config
 // a list of endpoints and optional tls config
-func InitializeEtcd(addrs []string, options Config) (Store, error) {
+func InitializeEtcd(addrs []string, options *Config) (Store, error) {
 	s := &Etcd{}
 	s := &Etcd{}
-	s.watches = make(map[string]chan<- bool)
 
 
 	entries := createEndpoints(addrs, "http")
 	entries := createEndpoints(addrs, "http")
 	s.client = etcd.NewClient(entries)
 	s.client = etcd.NewClient(entries)
 
 
-	if options.TLS != nil {
-		s.setTLS(options.TLS)
-	}
-
-	if options.Timeout != 0 {
-		s.setTimeout(options.Timeout)
+	// Set options
+	if options != nil {
+		if options.TLS != nil {
+			s.setTLS(options.TLS)
+		}
+		if options.ConnectionTimeout != 0 {
+			s.setTimeout(options.ConnectionTimeout)
+		}
+		if options.EphemeralTTL != 0 {
+			s.setEphemeralTTL(options.EphemeralTTL)
+		}
 	}
 	}
 
 
+	go func() {
+		for {
+			s.client.SyncCluster()
+			time.Sleep(periodicSync)
+		}
+	}()
 	return s, nil
 	return s, nil
 }
 }
 
 
@@ -65,10 +91,14 @@ func (s *Etcd) setTimeout(time time.Duration) {
 	s.client.SetDialTimeout(time)
 	s.client.SetDialTimeout(time)
 }
 }
 
 
+// SetHeartbeat sets the heartbeat value to notify we are alive
+func (s *Etcd) setEphemeralTTL(time time.Duration) {
+	s.ephemeralTTL = time
+}
+
 // Create the entire path for a directory that does not exist
 // Create the entire path for a directory that does not exist
 func (s *Etcd) createDirectory(path string) error {
 func (s *Etcd) createDirectory(path string) error {
-	// TODO Handle TTL at key/dir creation -> use K/V struct for key infos?
-	if _, err := s.client.CreateDir(format(path), 10); err != nil {
+	if _, err := s.client.CreateDir(normalize(path), 10); err != nil {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 			if etcdError.ErrorCode != 105 { // Skip key already exists
 			if etcdError.ErrorCode != 105 { // Skip key already exists
 				return err
 				return err
@@ -82,28 +112,35 @@ func (s *Etcd) createDirectory(path string) error {
 
 
 // Get the value at "key", returns the last modified index
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
 // to use in conjunction to CAS calls
-func (s *Etcd) Get(key string) (value []byte, lastIndex uint64, err error) {
-	result, err := s.client.Get(format(key), false, false)
+func (s *Etcd) Get(key string) (*KVPair, error) {
+	result, err := s.client.Get(normalize(key), false, false)
 	if err != nil {
 	if err != nil {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 			// Not a Directory or Not a file
 			// Not a Directory or Not a file
 			if etcdError.ErrorCode == 102 || etcdError.ErrorCode == 104 {
 			if etcdError.ErrorCode == 102 || etcdError.ErrorCode == 104 {
-				return nil, 0, ErrKeyNotFound
+				return nil, ErrKeyNotFound
 			}
 			}
 		}
 		}
-		return nil, 0, err
+		return nil, err
 	}
 	}
-	return []byte(result.Node.Value), result.Node.ModifiedIndex, nil
+	return &KVPair{key, []byte(result.Node.Value), result.Node.ModifiedIndex}, nil
 }
 }
 
 
 // Put a value at "key"
 // Put a value at "key"
-func (s *Etcd) Put(key string, value []byte) error {
-	if _, err := s.client.Set(key, string(value), 0); err != nil {
+func (s *Etcd) Put(key string, value []byte, opts *WriteOptions) error {
+
+	// Default TTL = 0 means no expiration
+	var ttl uint64
+	if opts != nil && opts.Ephemeral {
+		ttl = uint64(s.ephemeralTTL.Seconds())
+	}
+
+	if _, err := s.client.Set(key, string(value), ttl); err != nil {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 			if etcdError.ErrorCode == 104 { // Not a directory
 			if etcdError.ErrorCode == 104 { // Not a directory
 				// Remove the last element (the actual key) and set the prefix as a dir
 				// Remove the last element (the actual key) and set the prefix as a dir
-				err = s.createDirectory(getDir(key))
-				if _, err := s.client.Set(key, string(value), 0); err != nil {
+				err = s.createDirectory(getDirectory(key))
+				if _, err := s.client.Set(key, string(value), ttl); err != nil {
 					return err
 					return err
 				}
 				}
 			}
 			}
@@ -115,7 +152,7 @@ func (s *Etcd) Put(key string, value []byte) error {
 
 
 // Delete a value at "key"
 // Delete a value at "key"
 func (s *Etcd) Delete(key string) error {
 func (s *Etcd) Delete(key string) error {
-	if _, err := s.client.Delete(format(key), false); err != nil {
+	if _, err := s.client.Delete(normalize(key), false); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
@@ -123,9 +160,9 @@ func (s *Etcd) Delete(key string) error {
 
 
 // Exists checks if the key exists inside the store
 // Exists checks if the key exists inside the store
 func (s *Etcd) Exists(key string) (bool, error) {
 func (s *Etcd) Exists(key string) (bool, error) {
-	value, _, err := s.Get(key)
+	entry, err := s.Get(key)
 	if err != nil {
 	if err != nil {
-		if err == ErrKeyNotFound || value == nil {
+		if err == ErrKeyNotFound || entry.Value == nil {
 			return false, nil
 			return false, nil
 		}
 		}
 		return false, err
 		return false, err
@@ -133,132 +170,275 @@ func (s *Etcd) Exists(key string) (bool, error) {
 	return true, nil
 	return true, nil
 }
 }
 
 
-// Watch a single key for modifications
-func (s *Etcd) Watch(key string, _ time.Duration, callback WatchCallback) error {
-	key = format(key)
-	watchChan := make(chan *etcd.Response)
-	stopChan := make(chan bool)
+// Watch changes on a key.
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Etcd) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	// Get the current value
+	current, err := s.Get(key)
+	if err != nil {
+		return nil, err
+	}
 
 
-	// Create new Watch entry
-	s.watches[key] = stopChan
+	// Start an etcd watch.
+	// Note: etcd will send the current value through the channel.
+	etcdWatchCh := make(chan *etcd.Response)
+	etcdStopCh := make(chan bool)
+	go s.client.Watch(normalize(key), 0, false, etcdWatchCh, etcdStopCh)
 
 
-	// Start watch
-	go s.client.Watch(key, 0, false, watchChan, stopChan)
+	// Adapter goroutine: The goal here is to convert wathever format etcd is
+	// using into our interface.
+	watchCh := make(chan *KVPair)
+	go func() {
+		defer close(watchCh)
 
 
-	for _ = range watchChan {
-		log.WithField("name", "etcd").Debug("Discovery watch triggered")
-		entry, index, err := s.Get(key)
-		if err != nil {
-			log.Error("Cannot refresh the key: ", key, ", cancelling watch")
-			s.watches[key] = nil
-			return err
+		// Push the current value through the channel.
+		watchCh <- current
+
+		for {
+			select {
+			case result := <-etcdWatchCh:
+				watchCh <- &KVPair{
+					key,
+					[]byte(result.Node.Value),
+					result.Node.ModifiedIndex,
+				}
+			case <-stopCh:
+				etcdStopCh <- true
+				return
+			}
 		}
 		}
-		kvi := []KVEntry{&kviTuple{key, entry, index}}
-		callback(kvi)
-	}
-	return nil
+	}()
+	return watchCh, nil
 }
 }
 
 
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *Etcd) CancelWatch(key string) error {
-	key = format(key)
-	if _, ok := s.watches[key]; !ok {
-		log.Error("Chan does not exist for key: ", key)
-		return ErrWatchDoesNotExist
+// WatchTree watches changes on a "directory"
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Etcd) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	// Get the current value
+	current, err := s.List(prefix)
+	if err != nil {
+		return nil, err
 	}
 	}
-	// Send stop signal to event chan
-	s.watches[key] <- true
-	s.watches[key] = nil
-	return nil
+
+	// Start an etcd watch.
+	etcdWatchCh := make(chan *etcd.Response)
+	etcdStopCh := make(chan bool)
+	go s.client.Watch(normalize(prefix), 0, true, etcdWatchCh, etcdStopCh)
+
+	// Adapter goroutine: The goal here is to convert wathever format etcd is
+	// using into our interface.
+	watchCh := make(chan []*KVPair)
+	go func() {
+		defer close(watchCh)
+
+		// Push the current value through the channel.
+		watchCh <- current
+
+		for {
+			select {
+			case <-etcdWatchCh:
+				// FIXME: We should probably use the value pushed by the channel.
+				// However, .Node.Nodes seems to be empty.
+				if list, err := s.List(prefix); err == nil {
+					watchCh <- list
+				}
+			case <-stopCh:
+				etcdStopCh <- true
+				return
+			}
+		}
+	}()
+	return watchCh, nil
 }
 }
 
 
 // AtomicPut put a value at "key" if the key has not been
 // AtomicPut put a value at "key" if the key has not been
 // modified in the meantime, throws an error if this is the case
 // modified in the meantime, throws an error if this is the case
-func (s *Etcd) AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error) {
-	resp, err := s.client.CompareAndSwap(format(key), string(newValue), 5, string(oldValue), 0)
-	if err != nil {
-		return false, err
-	}
-	if !(resp.Node.Value == string(newValue) && resp.Node.Key == key && resp.Node.TTL == 5) {
-		return false, ErrKeyModified
+func (s *Etcd) AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error) {
+	if previous == nil {
+		return false, nil, ErrPreviousNotSpecified
 	}
 	}
-	if !(resp.PrevNode.Value == string(newValue) && resp.PrevNode.Key == key && resp.PrevNode.TTL == 5) {
-		return false, ErrKeyModified
+
+	meta, err := s.client.CompareAndSwap(normalize(key), string(value), 0, "", previous.LastIndex)
+	if err != nil {
+		if etcdError, ok := err.(*etcd.EtcdError); ok {
+			if etcdError.ErrorCode == 101 { // Compare failed
+				return false, nil, ErrKeyModified
+			}
+		}
+		return false, nil, err
 	}
 	}
-	return true, nil
+	return true, &KVPair{Key: key, Value: value, LastIndex: meta.Node.ModifiedIndex}, nil
 }
 }
 
 
 // AtomicDelete deletes a value at "key" if the key has not
 // AtomicDelete deletes a value at "key" if the key has not
 // been modified in the meantime, throws an error if this is the case
 // been modified in the meantime, throws an error if this is the case
-func (s *Etcd) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
-	resp, err := s.client.CompareAndDelete(format(key), string(oldValue), 0)
+func (s *Etcd) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	if previous == nil {
+		return false, ErrPreviousNotSpecified
+	}
+
+	_, err := s.client.CompareAndDelete(normalize(key), "", previous.LastIndex)
 	if err != nil {
 	if err != nil {
+		if etcdError, ok := err.(*etcd.EtcdError); ok {
+			if etcdError.ErrorCode == 101 { // Compare failed
+				return false, ErrKeyModified
+			}
+		}
 		return false, err
 		return false, err
 	}
 	}
-	if !(resp.PrevNode.Value == string(oldValue) && resp.PrevNode.Key == key && resp.PrevNode.TTL == 5) {
-		return false, ErrKeyModified
-	}
 	return true, nil
 	return true, nil
 }
 }
 
 
-// GetRange gets a range of values at "directory"
-func (s *Etcd) GetRange(prefix string) ([]KVEntry, error) {
-	resp, err := s.client.Get(format(prefix), true, true)
+// List the content of a given prefix
+func (s *Etcd) List(prefix string) ([]*KVPair, error) {
+	resp, err := s.client.Get(normalize(prefix), true, true)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	kvi := make([]KVEntry, len(resp.Node.Nodes))
-	for i, n := range resp.Node.Nodes {
-		kvi[i] = &kviTuple{n.Key, []byte(n.Value), n.ModifiedIndex}
+	kv := []*KVPair{}
+	for _, n := range resp.Node.Nodes {
+		key := strings.TrimLeft(n.Key, "/")
+		kv = append(kv, &KVPair{key, []byte(n.Value), n.ModifiedIndex})
 	}
 	}
-	return kvi, nil
+	return kv, nil
 }
 }
 
 
-// DeleteRange deletes a range of values at "directory"
-func (s *Etcd) DeleteRange(prefix string) error {
-	if _, err := s.client.Delete(format(prefix), true); err != nil {
+// DeleteTree deletes a range of keys based on prefix
+func (s *Etcd) DeleteTree(prefix string) error {
+	if _, err := s.client.Delete(normalize(prefix), true); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *Etcd) WatchRange(prefix string, filter string, _ time.Duration, callback WatchCallback) error {
-	prefix = format(prefix)
-	watchChan := make(chan *etcd.Response)
-	stopChan := make(chan bool)
+// NewLock returns a handle to a lock struct which can be used to acquire and
+// release the mutex.
+func (s *Etcd) NewLock(key string, options *LockOptions) (Locker, error) {
+	var value string
+	ttl := uint64(time.Duration(defaultLockTTL).Seconds())
 
 
-	// Create new Watch entry
-	s.watches[prefix] = stopChan
+	// Apply options
+	if options != nil {
+		if options.Value != nil {
+			value = string(options.Value)
+		}
+		if options.TTL != 0 {
+			ttl = uint64(options.TTL.Seconds())
+		}
+	}
 
 
-	// Start watch
-	go s.client.Watch(prefix, 0, true, watchChan, stopChan)
-	for _ = range watchChan {
-		log.WithField("name", "etcd").Debug("Discovery watch triggered")
-		kvi, err := s.GetRange(prefix)
+	// Create lock object
+	lock := &etcdLock{
+		client: s.client,
+		key:    key,
+		value:  value,
+		ttl:    ttl,
+	}
+
+	return lock, nil
+}
+
+// Lock attempts to acquire the lock and blocks while doing so.
+// Returns a channel that is closed if our lock is lost or an error.
+func (l *etcdLock) Lock() (<-chan struct{}, error) {
+
+	key := normalize(l.key)
+
+	// Lock holder channels
+	lockHeld := make(chan struct{})
+	stopLocking := make(chan struct{})
+
+	var lastIndex uint64
+
+	for {
+		resp, err := l.client.Create(key, l.value, l.ttl)
 		if err != nil {
 		if err != nil {
-			log.Error("Cannot refresh the key: ", prefix, ", cancelling watch")
-			s.watches[prefix] = nil
-			return err
+			if etcdError, ok := err.(*etcd.EtcdError); ok {
+				// Key already exists
+				if etcdError.ErrorCode != 105 {
+					lastIndex = ^uint64(0)
+				}
+			}
+		} else {
+			lastIndex = resp.Node.ModifiedIndex
+		}
+
+		_, err = l.client.CompareAndSwap(key, l.value, l.ttl, "", lastIndex)
+
+		if err == nil {
+			// Leader section
+			l.stopLock = stopLocking
+			go l.holdLock(key, lockHeld, stopLocking)
+			break
+		} else {
+			// Seeker section
+			chW := make(chan *etcd.Response)
+			chWStop := make(chan bool)
+			l.waitLock(key, chW, chWStop)
+
+			// Delete or Expire event occured
+			// Retry
+		}
+	}
+
+	return lockHeld, nil
+}
+
+// Hold the lock as long as we can
+// Updates the key ttl periodically until we receive
+// an explicit stop signal from the Unlock method
+func (l *etcdLock) holdLock(key string, lockHeld chan struct{}, stopLocking chan struct{}) {
+	defer close(lockHeld)
+
+	update := time.NewTicker(defaultUpdateTime)
+	defer update.Stop()
+
+	var err error
+
+	for {
+		select {
+		case <-update.C:
+			l.last, err = l.client.Update(key, l.value, l.ttl)
+			if err != nil {
+				return
+			}
+
+		case <-stopLocking:
+			return
 		}
 		}
-		callback(kvi)
 	}
 	}
-	return nil
 }
 }
 
 
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *Etcd) CancelWatchRange(prefix string) error {
-	return s.CancelWatch(format(prefix))
+// WaitLock simply waits for the key to be available for creation
+func (l *etcdLock) waitLock(key string, eventCh chan *etcd.Response, stopWatchCh chan bool) {
+	go l.client.Watch(key, 0, false, eventCh, stopWatchCh)
+	for event := range eventCh {
+		if event.Action == "delete" || event.Action == "expire" {
+			return
+		}
+	}
 }
 }
 
 
-// Acquire the lock for "key"/"directory"
-func (s *Etcd) Acquire(key string, value []byte) (string, error) {
-	return "", ErrNotImplemented
+// Unlock released the lock. It is an error to call this
+// if the lock is not currently held.
+func (l *etcdLock) Unlock() error {
+	if l.stopLock != nil {
+		l.stopLock <- struct{}{}
+	}
+	if l.last != nil {
+		_, err := l.client.CompareAndDelete(normalize(l.key), l.value, l.last.Node.ModifiedIndex)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
 }
 }
 
 
-// Release the lock for "key"/"directory"
-func (s *Etcd) Release(session string) error {
-	return ErrNotImplemented
+// Close closes the client connection
+func (s *Etcd) Close() {
+	return
 }
 }

+ 30 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd_test.go

@@ -0,0 +1,30 @@
+package store
+
+import (
+	"testing"
+	"time"
+)
+
+func makeEtcdClient(t *testing.T) Store {
+	client := "localhost:4001"
+
+	kv, err := NewStore(
+		ETCD,
+		[]string{client},
+		&Config{
+			ConnectionTimeout: 3 * time.Second,
+			EphemeralTTL:      2 * time.Second,
+		},
+	)
+	if err != nil {
+		t.Fatalf("cannot create store: %v", err)
+	}
+
+	return kv
+}
+
+func TestEtcdStore(t *testing.T) {
+	kv := makeEtcdClient(t)
+
+	testStore(t, kv)
+}

+ 15 - 20
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/helpers.go

@@ -12,21 +12,22 @@ func createEndpoints(addrs []string, scheme string) (entries []string) {
 	return entries
 	return entries
 }
 }
 
 
-// Formats the key
-func format(key string) string {
-	return fullpath(splitKey(key))
+// Normalize the key for each store to the form:
+//
+//     /path/to/key
+//
+func normalize(key string) string {
+	return "/" + join(splitKey(key))
 }
 }
 
 
-// Formats the key partially (omits the first '/')
-func partialFormat(key string) string {
-	return partialpath(splitKey(key))
-}
-
-// Get the full directory part of the key
-func getDir(key string) string {
+// Get the full directory part of the key to the form:
+//
+//     /path/to/
+//
+func getDirectory(key string) string {
 	parts := splitKey(key)
 	parts := splitKey(key)
 	parts = parts[:len(parts)-1]
 	parts = parts[:len(parts)-1]
-	return fullpath(parts)
+	return "/" + join(parts)
 }
 }
 
 
 // SplitKey splits the key to extract path informations
 // SplitKey splits the key to extract path informations
@@ -39,13 +40,7 @@ func splitKey(key string) (path []string) {
 	return path
 	return path
 }
 }
 
 
-// Get the full correct path representation of a splitted key/directory
-func fullpath(path []string) string {
-	return "/" + strings.Join(path, "/")
-}
-
-// Get the partial correct path representation of a splitted key/directory
-// Omits the first '/'
-func partialpath(path []string) string {
-	return strings.Join(path, "/")
+// Join the path parts with '/'
+func join(parts []string) string {
+	return strings.Join(parts, "/")
 }
 }

+ 109 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/mock.go

@@ -0,0 +1,109 @@
+package store
+
+import "github.com/stretchr/testify/mock"
+
+// Mock store. Mocks all Store functions using testify.Mock.
+type Mock struct {
+	mock.Mock
+
+	// Endpoints passed to InitializeMock
+	Endpoints []string
+	// Options passed to InitializeMock
+	Options *Config
+}
+
+// InitializeMock creates a Mock store.
+func InitializeMock(endpoints []string, options *Config) (Store, error) {
+	s := &Mock{}
+	s.Endpoints = endpoints
+	s.Options = options
+	return s, nil
+}
+
+// Put mock
+func (s *Mock) Put(key string, value []byte, opts *WriteOptions) error {
+	args := s.Mock.Called(key, value, opts)
+	return args.Error(0)
+}
+
+// Get mock
+func (s *Mock) Get(key string) (*KVPair, error) {
+	args := s.Mock.Called(key)
+	return args.Get(0).(*KVPair), args.Error(1)
+}
+
+// Delete mock
+func (s *Mock) Delete(key string) error {
+	args := s.Mock.Called(key)
+	return args.Error(0)
+}
+
+// Exists mock
+func (s *Mock) Exists(key string) (bool, error) {
+	args := s.Mock.Called(key)
+	return args.Bool(0), args.Error(1)
+}
+
+// Watch mock
+func (s *Mock) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	args := s.Mock.Called(key, stopCh)
+	return args.Get(0).(<-chan *KVPair), args.Error(1)
+}
+
+// WatchTree mock
+func (s *Mock) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	args := s.Mock.Called(prefix, stopCh)
+	return args.Get(0).(chan []*KVPair), args.Error(1)
+}
+
+// NewLock mock
+func (s *Mock) NewLock(key string, options *LockOptions) (Locker, error) {
+	args := s.Mock.Called(key, options)
+	return args.Get(0).(Locker), args.Error(1)
+}
+
+// List mock
+func (s *Mock) List(prefix string) ([]*KVPair, error) {
+	args := s.Mock.Called(prefix)
+	return args.Get(0).([]*KVPair), args.Error(1)
+}
+
+// DeleteTree mock
+func (s *Mock) DeleteTree(prefix string) error {
+	args := s.Mock.Called(prefix)
+	return args.Error(0)
+}
+
+// AtomicPut mock
+func (s *Mock) AtomicPut(key string, value []byte, previous *KVPair, opts *WriteOptions) (bool, *KVPair, error) {
+	args := s.Mock.Called(key, value, previous, opts)
+	return args.Bool(0), args.Get(1).(*KVPair), args.Error(2)
+}
+
+// AtomicDelete mock
+func (s *Mock) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	args := s.Mock.Called(key, previous)
+	return args.Bool(0), args.Error(1)
+}
+
+// MockLock mock implementation of Locker
+type MockLock struct {
+	mock.Mock
+}
+
+// Lock mock
+func (l *MockLock) Lock() (<-chan struct{}, error) {
+	args := l.Mock.Called()
+	return args.Get(0).(<-chan struct{}), args.Error(1)
+}
+
+// Unlock mock
+func (l *MockLock) Unlock() error {
+	args := l.Mock.Called()
+	return args.Error(0)
+}
+
+// Close mock
+func (s *Mock) Close() {
+	return
+}

+ 107 - 45
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store.go

@@ -1,17 +1,54 @@
 package store
 package store
 
 
 import (
 import (
+	"crypto/tls"
+	"errors"
 	"time"
 	"time"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
 )
 )
 
 
-// WatchCallback is used for watch methods on keys
-// and is triggered on key change
-type WatchCallback func(kviTuple []KVEntry)
+// Backend represents a KV Store Backend
+type Backend string
+
+const (
+	// MOCK backend
+	MOCK Backend = "mock"
+	// CONSUL backend
+	CONSUL = "consul"
+	// ETCD backend
+	ETCD = "etcd"
+	// ZK backend
+	ZK = "zk"
+)
 
 
-// Initialize creates a new Store object, initializing the client
-type Initialize func(addrs []string, options Config) (Store, error)
+var (
+	// ErrInvalidTTL is a specific error to consul
+	ErrInvalidTTL = errors.New("Invalid TTL, please change the value to the miminum allowed ttl for the chosen store")
+	// ErrNotSupported is exported
+	ErrNotSupported = errors.New("Backend storage not supported yet, please choose another one")
+	// ErrNotImplemented is exported
+	ErrNotImplemented = errors.New("Call not implemented in current backend")
+	// ErrNotReachable is exported
+	ErrNotReachable = errors.New("Api not reachable")
+	// ErrCannotLock is exported
+	ErrCannotLock = errors.New("Error acquiring the lock")
+	// ErrWatchDoesNotExist is exported
+	ErrWatchDoesNotExist = errors.New("No watch found for specified key")
+	// ErrKeyModified is exported
+	ErrKeyModified = errors.New("Unable to complete atomic operation, key modified")
+	// ErrKeyNotFound is exported
+	ErrKeyNotFound = errors.New("Key not found in store")
+	// ErrPreviousNotSpecified is exported
+	ErrPreviousNotSpecified = errors.New("Previous K/V pair should be provided for the Atomic operation")
+)
+
+// Config contains the options for a storage client
+type Config struct {
+	TLS               *tls.Config
+	ConnectionTimeout time.Duration
+	EphemeralTTL      time.Duration
+}
 
 
 // Store represents the backend K/V storage
 // Store represents the backend K/V storage
 // Each store should support every call listed
 // Each store should support every call listed
@@ -19,10 +56,10 @@ type Initialize func(addrs []string, options Config) (Store, error)
 // backend for libkv
 // backend for libkv
 type Store interface {
 type Store interface {
 	// Put a value at the specified key
 	// Put a value at the specified key
-	Put(key string, value []byte) error
+	Put(key string, value []byte, options *WriteOptions) error
 
 
 	// Get a value given its key
 	// Get a value given its key
-	Get(key string) (value []byte, lastIndex uint64, err error)
+	Get(key string) (*KVPair, error)
 
 
 	// Delete the value at the specified key
 	// Delete the value at the specified key
 	Delete(key string) error
 	Delete(key string) error
@@ -30,61 +67,86 @@ type Store interface {
 	// Verify if a Key exists in the store
 	// Verify if a Key exists in the store
 	Exists(key string) (bool, error)
 	Exists(key string) (bool, error)
 
 
-	// Watch changes on a key
-	Watch(key string, heartbeat time.Duration, callback WatchCallback) error
+	// Watch changes on a key.
+	// Returns a channel that will receive changes or an error.
+	// Upon creating a watch, the current value will be sent to the channel.
+	// Providing a non-nil stopCh can be used to stop watching.
+	Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error)
 
 
-	// Cancel watch key
-	CancelWatch(key string) error
+	// WatchTree watches changes on a "directory"
+	// Returns a channel that will receive changes or an error.
+	// Upon creating a watch, the current value will be sent to the channel.
+	// Providing a non-nil stopCh can be used to stop watching.
+	WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error)
 
 
-	// Acquire the lock at key
-	Acquire(key string, value []byte) (string, error)
+	// CreateLock for a given key.
+	// The returned Locker is not held and must be acquired with `.Lock`.
+	// value is optional.
+	NewLock(key string, options *LockOptions) (Locker, error)
 
 
-	// Release the lock at key
-	Release(session string) error
+	// List the content of a given prefix
+	List(prefix string) ([]*KVPair, error)
 
 
-	// Get range of keys based on prefix
-	GetRange(prefix string) ([]KVEntry, error)
+	// DeleteTree deletes a range of keys based on prefix
+	DeleteTree(prefix string) error
 
 
-	// Delete range of keys based on prefix
-	DeleteRange(prefix string) error
+	// Atomic operation on a single value
+	AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
 
 
-	// Watch key namespaces
-	WatchRange(prefix string, filter string, heartbeat time.Duration, callback WatchCallback) error
+	// Atomic delete of a single value
+	AtomicDelete(key string, previous *KVPair) (bool, error)
 
 
-	// Cancel watch key range
-	CancelWatchRange(prefix string) error
+	// Close the store connection
+	Close()
+}
 
 
-	// Atomic operation on a single value
-	AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error)
+// KVPair represents {Key, Value, Lastindex} tuple
+type KVPair struct {
+	Key       string
+	Value     []byte
+	LastIndex uint64
+}
 
 
-	// Atomic delete of a single value
-	AtomicDelete(key string, oldValue []byte, index uint64) (bool, error)
+// WriteOptions contains optional request parameters
+type WriteOptions struct {
+	Heartbeat time.Duration
+	Ephemeral bool
 }
 }
 
 
-// KVEntry represents {Key, Value, Lastindex} tuple
-type KVEntry interface {
-	Key() string
-	Value() []byte
-	LastIndex() uint64
+// LockOptions contains optional request parameters
+type LockOptions struct {
+	Value []byte        // Optional, value to associate with the lock
+	TTL   time.Duration // Optional, expiration ttl associated with the lock
 }
 }
 
 
-var (
-	// List of Store services
-	stores map[string]Initialize
-)
+// WatchCallback is used for watch methods on keys
+// and is triggered on key change
+type WatchCallback func(entries ...*KVPair)
 
 
-func init() {
-	stores = make(map[string]Initialize)
-	stores["consul"] = InitializeConsul
-	stores["etcd"] = InitializeEtcd
-	stores["zk"] = InitializeZookeeper
+// Locker provides locking mechanism on top of the store.
+// Similar to `sync.Lock` except it may return errors.
+type Locker interface {
+	Lock() (<-chan struct{}, error)
+	Unlock() error
 }
 }
 
 
-// CreateStore creates a an instance of store
-func CreateStore(store string, addrs []string, options Config) (Store, error) {
+// Initialize creates a new Store object, initializing the client
+type Initialize func(addrs []string, options *Config) (Store, error)
+
+var (
+	// Backend initializers
+	initializers = map[Backend]Initialize{
+		MOCK:   InitializeMock,
+		CONSUL: InitializeConsul,
+		ETCD:   InitializeEtcd,
+		ZK:     InitializeZookeeper,
+	}
+)
 
 
-	if init, exists := stores[store]; exists {
-		log.WithFields(log.Fields{"store": store}).Debug("Initializing store service")
+// NewStore creates a an instance of store
+func NewStore(backend Backend, addrs []string, options *Config) (Store, error) {
+	if init, exists := initializers[backend]; exists {
+		log.WithFields(log.Fields{"backend": backend}).Debug("Initializing store service")
 		return init(addrs, options)
 		return init(addrs, options)
 	}
 	}
 
 

+ 401 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store_test.go

@@ -0,0 +1,401 @@
+package store
+
+import (
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func testStore(t *testing.T, kv Store) {
+	testPutGetDelete(t, kv)
+	testWatch(t, kv)
+	testWatchTree(t, kv)
+	testAtomicPut(t, kv)
+	testAtomicDelete(t, kv)
+	testLockUnlock(t, kv)
+	testPutEphemeral(t, kv)
+	testList(t, kv)
+	testDeleteTree(t, kv)
+}
+
+func testPutGetDelete(t *testing.T, kv Store) {
+	key := "foo"
+	value := []byte("bar")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	// Get should return the value and an incremented index
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Delete the key
+	err = kv.Delete(key)
+	assert.NoError(t, err)
+
+	// Get should fail
+	pair, err = kv.Get(key)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+}
+
+func testWatch(t *testing.T, kv Store) {
+	key := "hello"
+	value := []byte("world")
+	newValue := []byte("world!")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	stopCh := make(<-chan struct{})
+	events, err := kv.Watch(key, stopCh)
+	assert.NoError(t, err)
+	assert.NotNil(t, events)
+
+	// Update loop
+	go func() {
+		timeout := time.After(1 * time.Second)
+		tick := time.Tick(250 * time.Millisecond)
+		for {
+			select {
+			case <-timeout:
+				return
+			case <-tick:
+				err := kv.Put(key, newValue, nil)
+				if assert.NoError(t, err) {
+					continue
+				}
+				return
+			}
+		}
+	}()
+
+	// Check for updates
+	timeout := time.After(2 * time.Second)
+	eventCount := 1
+	for {
+		select {
+		case event := <-events:
+			assert.NotNil(t, event)
+			if eventCount == 1 {
+				assert.Equal(t, event.Key, key)
+				assert.Equal(t, event.Value, value)
+			} else {
+				assert.Equal(t, event.Key, key)
+				assert.Equal(t, event.Value, newValue)
+			}
+			eventCount++
+			// We received all the events we wanted to check
+			if eventCount >= 4 {
+				return
+			}
+		case <-timeout:
+			t.Fatal("Timeout reached")
+			return
+		}
+	}
+}
+
+func testWatchTree(t *testing.T, kv Store) {
+	dir := "tree"
+
+	node1 := "tree/node1"
+	value1 := []byte("node1")
+
+	node2 := "tree/node2"
+	value2 := []byte("node2")
+
+	node3 := "tree/node3"
+	value3 := []byte("node3")
+
+	err := kv.Put(node1, value1, nil)
+	assert.NoError(t, err)
+	err = kv.Put(node2, value2, nil)
+	assert.NoError(t, err)
+	err = kv.Put(node3, value3, nil)
+	assert.NoError(t, err)
+
+	stopCh := make(<-chan struct{})
+	events, err := kv.WatchTree(dir, stopCh)
+	assert.NoError(t, err)
+	assert.NotNil(t, events)
+
+	// Update loop
+	go func() {
+		timeout := time.After(250 * time.Millisecond)
+		for {
+			select {
+			case <-timeout:
+				err := kv.Delete(node3)
+				assert.NoError(t, err)
+				return
+			}
+		}
+	}()
+
+	// Check for updates
+	timeout := time.After(4 * time.Second)
+	for {
+		select {
+		case event := <-events:
+			assert.NotNil(t, event)
+			// We received the Delete event on a child node
+			// Exit test successfully
+			if len(event) == 2 {
+				return
+			}
+		case <-timeout:
+			t.Fatal("Timeout reached")
+			return
+		}
+	}
+}
+
+func testAtomicPut(t *testing.T, kv Store) {
+	key := "hello"
+	value := []byte("world")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	// Get should return the value and an incremented index
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// This CAS should succeed
+	success, _, err := kv.AtomicPut("hello", []byte("WORLD"), pair, nil)
+	assert.NoError(t, err)
+	assert.True(t, success)
+
+	// This CAS should fail
+	pair.LastIndex = 0
+	success, _, err = kv.AtomicPut("hello", []byte("WORLDWORLD"), pair, nil)
+	assert.Error(t, err)
+	assert.False(t, success)
+}
+
+func testAtomicDelete(t *testing.T, kv Store) {
+	key := "atomic"
+	value := []byte("world")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	// Get should return the value and an incremented index
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	tempIndex := pair.LastIndex
+
+	// AtomicDelete should fail
+	pair.LastIndex = 0
+	success, err := kv.AtomicDelete(key, pair)
+	assert.Error(t, err)
+	assert.False(t, success)
+
+	// AtomicDelete should succeed
+	pair.LastIndex = tempIndex
+	success, err = kv.AtomicDelete(key, pair)
+	assert.NoError(t, err)
+	assert.True(t, success)
+}
+
+func testLockUnlock(t *testing.T, kv Store) {
+	t.Parallel()
+
+	key := "foo"
+	value := []byte("bar")
+
+	// We should be able to create a new lock on key
+	lock, err := kv.NewLock(key, &LockOptions{Value: value})
+	assert.NoError(t, err)
+	assert.NotNil(t, lock)
+
+	// Lock should successfully succeed or block
+	lockChan, err := lock.Lock()
+	assert.NoError(t, err)
+	assert.NotNil(t, lockChan)
+
+	// Get should work
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Unlock should succeed
+	err = lock.Unlock()
+	assert.NoError(t, err)
+
+	// Get should work
+	pair, err = kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+}
+
+// FIXME Gracefully handle Zookeeper
+func testPutEphemeral(t *testing.T, kv Store) {
+	// Zookeeper: initialize client here (Close() hangs otherwise)
+	zookeeper := false
+	if _, ok := kv.(*Zookeeper); ok {
+		zookeeper = true
+		kv = makeZkClient(t)
+	}
+
+	firstKey := "first"
+	firstValue := []byte("foo")
+
+	secondKey := "second"
+	secondValue := []byte("bar")
+
+	// Put the first key with the Ephemeral flag
+	err := kv.Put(firstKey, firstValue, &WriteOptions{Ephemeral: true})
+	assert.NoError(t, err)
+
+	// Put a second key with the Ephemeral flag
+	err = kv.Put(secondKey, secondValue, &WriteOptions{Ephemeral: true})
+	assert.NoError(t, err)
+
+	// Get on firstKey should work
+	pair, err := kv.Get(firstKey)
+	assert.NoError(t, err)
+	assert.NotNil(t, pair)
+
+	// Get on secondKey should work
+	pair, err = kv.Get(secondKey)
+	assert.NoError(t, err)
+	assert.NotNil(t, pair)
+
+	// Zookeeper: close client connection
+	if zookeeper {
+		kv.Close()
+	}
+
+	// Let the session expire
+	time.Sleep(5 * time.Second)
+
+	// Zookeeper: re-create the client
+	if zookeeper {
+		kv = makeZkClient(t)
+	}
+
+	// Get on firstKey shouldn't work
+	pair, err = kv.Get(firstKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+
+	// Get on secondKey shouldn't work
+	pair, err = kv.Get(secondKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+}
+
+func testList(t *testing.T, kv Store) {
+	prefix := "nodes"
+
+	firstKey := "nodes/first"
+	firstValue := []byte("first")
+
+	secondKey := "nodes/second"
+	secondValue := []byte("second")
+
+	// Put the first key
+	err := kv.Put(firstKey, firstValue, nil)
+	assert.NoError(t, err)
+
+	// Put the second key
+	err = kv.Put(secondKey, secondValue, nil)
+	assert.NoError(t, err)
+
+	// List should work and return the two correct values
+	pairs, err := kv.List(prefix)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pairs) {
+		assert.Equal(t, len(pairs), 2)
+	}
+
+	// Check pairs, those are not necessarily in Put order
+	for _, pair := range pairs {
+		if pair.Key == firstKey {
+			assert.Equal(t, pair.Value, firstValue)
+		}
+		if pair.Key == secondKey {
+			assert.Equal(t, pair.Value, secondValue)
+		}
+	}
+}
+
+func testDeleteTree(t *testing.T, kv Store) {
+	prefix := "nodes"
+
+	firstKey := "nodes/first"
+	firstValue := []byte("first")
+
+	secondKey := "nodes/second"
+	secondValue := []byte("second")
+
+	// Put the first key
+	err := kv.Put(firstKey, firstValue, nil)
+	assert.NoError(t, err)
+
+	// Put the second key
+	err = kv.Put(secondKey, secondValue, nil)
+	assert.NoError(t, err)
+
+	// Get should work on the first Key
+	pair, err := kv.Get(firstKey)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, firstValue)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Get should work on the second Key
+	pair, err = kv.Get(secondKey)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, secondValue)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Delete Values under directory `nodes`
+	err = kv.DeleteTree(prefix)
+	assert.NoError(t, err)
+
+	// Get should fail on both keys
+	pair, err = kv.Get(firstKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+
+	pair, err = kv.Get(secondKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+}

+ 0 - 60
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/structs.go

@@ -1,60 +0,0 @@
-package store
-
-import (
-	"crypto/tls"
-	"errors"
-	"time"
-)
-
-var (
-	// ErrNotSupported is exported
-	ErrNotSupported = errors.New("Backend storage not supported yet, please choose another one")
-	// ErrNotImplemented is exported
-	ErrNotImplemented = errors.New("Call not implemented in current backend")
-	// ErrNotReachable is exported
-	ErrNotReachable = errors.New("Api not reachable")
-	// ErrCannotLock is exported
-	ErrCannotLock = errors.New("Error acquiring the lock")
-	// ErrWatchDoesNotExist is exported
-	ErrWatchDoesNotExist = errors.New("No watch found for specified key")
-	// ErrKeyModified is exported
-	ErrKeyModified = errors.New("Unable to complete atomic operation, key modified")
-	// ErrKeyNotFound is exported
-	ErrKeyNotFound = errors.New("Key not found in store")
-)
-
-// KV represents the different supported K/V
-type KV string
-
-const (
-	// CONSUL is exported
-	CONSUL KV = "consul"
-	// ETCD is exported
-	ETCD = "etcd"
-	// ZOOKEEPER is exported
-	ZOOKEEPER = "zookeeper"
-)
-
-// Config contains the options for a storage client
-type Config struct {
-	TLS     *tls.Config
-	Timeout time.Duration
-}
-
-type kviTuple struct {
-	key       string
-	value     []byte
-	lastIndex uint64
-}
-
-func (kvi *kviTuple) Key() string {
-	return kvi.key
-}
-
-func (kvi *kviTuple) Value() []byte {
-	return kvi.value
-}
-
-func (kvi *kviTuple) LastIndex() uint64 {
-	return kvi.lastIndex
-}

+ 192 - 94
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper.go

@@ -8,23 +8,32 @@ import (
 	zk "github.com/samuel/go-zookeeper/zk"
 	zk "github.com/samuel/go-zookeeper/zk"
 )
 )
 
 
+const defaultTimeout = 10 * time.Second
+
 // Zookeeper embeds the zookeeper client
 // Zookeeper embeds the zookeeper client
-// and list of watches
 type Zookeeper struct {
 type Zookeeper struct {
 	timeout time.Duration
 	timeout time.Duration
 	client  *zk.Conn
 	client  *zk.Conn
-	watches map[string]<-chan zk.Event
+}
+
+type zookeeperLock struct {
+	client *zk.Conn
+	lock   *zk.Lock
+	key    string
+	value  []byte
 }
 }
 
 
 // InitializeZookeeper creates a new Zookeeper client
 // InitializeZookeeper creates a new Zookeeper client
 // given a list of endpoints and optional tls config
 // given a list of endpoints and optional tls config
-func InitializeZookeeper(endpoints []string, options Config) (Store, error) {
+func InitializeZookeeper(endpoints []string, options *Config) (Store, error) {
 	s := &Zookeeper{}
 	s := &Zookeeper{}
-	s.watches = make(map[string]<-chan zk.Event)
-	s.timeout = 5 * time.Second // default timeout
+	s.timeout = defaultTimeout
 
 
-	if options.Timeout != 0 {
-		s.setTimeout(options.Timeout)
+	// Set options
+	if options != nil {
+		if options.ConnectionTimeout != 0 {
+			s.setTimeout(options.ConnectionTimeout)
+		}
 	}
 	}
 
 
 	conn, _, err := zk.Connect(endpoints, s.timeout)
 	conn, _, err := zk.Connect(endpoints, s.timeout)
@@ -43,21 +52,25 @@ func (s *Zookeeper) setTimeout(time time.Duration) {
 
 
 // Get the value at "key", returns the last modified index
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
 // to use in conjunction to CAS calls
-func (s *Zookeeper) Get(key string) (value []byte, lastIndex uint64, err error) {
-	resp, meta, err := s.client.Get(format(key))
+func (s *Zookeeper) Get(key string) (*KVPair, error) {
+	resp, meta, err := s.client.Get(normalize(key))
 	if err != nil {
 	if err != nil {
-		return nil, 0, err
+		return nil, err
 	}
 	}
 	if resp == nil {
 	if resp == nil {
-		return nil, 0, ErrKeyNotFound
+		return nil, ErrKeyNotFound
 	}
 	}
-	return resp, uint64(meta.Mzxid), nil
+	return &KVPair{key, resp, uint64(meta.Version)}, nil
 }
 }
 
 
 // Create the entire path for a directory that does not exist
 // Create the entire path for a directory that does not exist
-func (s *Zookeeper) createFullpath(path []string) error {
+func (s *Zookeeper) createFullpath(path []string, ephemeral bool) error {
 	for i := 1; i <= len(path); i++ {
 	for i := 1; i <= len(path); i++ {
 		newpath := "/" + strings.Join(path[:i], "/")
 		newpath := "/" + strings.Join(path[:i], "/")
+		if i == len(path) && ephemeral {
+			_, err := s.client.Create(newpath, []byte{1}, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
+			return err
+		}
 		_, err := s.client.Create(newpath, []byte{1}, 0, zk.WorldACL(zk.PermAll))
 		_, err := s.client.Create(newpath, []byte{1}, 0, zk.WorldACL(zk.PermAll))
 		if err != nil {
 		if err != nil {
 			// Skip if node already exists
 			// Skip if node already exists
@@ -70,14 +83,18 @@ func (s *Zookeeper) createFullpath(path []string) error {
 }
 }
 
 
 // Put a value at "key"
 // Put a value at "key"
-func (s *Zookeeper) Put(key string, value []byte) error {
-	fkey := format(key)
+func (s *Zookeeper) Put(key string, value []byte, opts *WriteOptions) error {
+	fkey := normalize(key)
 	exists, err := s.Exists(key)
 	exists, err := s.Exists(key)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	if !exists {
 	if !exists {
-		s.createFullpath(splitKey(key))
+		if opts != nil && opts.Ephemeral {
+			s.createFullpath(splitKey(key), opts.Ephemeral)
+		} else {
+			s.createFullpath(splitKey(key), false)
+		}
 	}
 	}
 	_, err = s.client.Set(fkey, value, -1)
 	_, err = s.client.Set(fkey, value, -1)
 	return err
 	return err
@@ -85,129 +102,210 @@ func (s *Zookeeper) Put(key string, value []byte) error {
 
 
 // Delete a value at "key"
 // Delete a value at "key"
 func (s *Zookeeper) Delete(key string) error {
 func (s *Zookeeper) Delete(key string) error {
-	err := s.client.Delete(format(key), -1)
+	err := s.client.Delete(normalize(key), -1)
 	return err
 	return err
 }
 }
 
 
 // Exists checks if the key exists inside the store
 // Exists checks if the key exists inside the store
 func (s *Zookeeper) Exists(key string) (bool, error) {
 func (s *Zookeeper) Exists(key string) (bool, error) {
-	exists, _, err := s.client.Exists(format(key))
+	exists, _, err := s.client.Exists(normalize(key))
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
 	return exists, nil
 	return exists, nil
 }
 }
 
 
-// Watch a single key for modifications
-func (s *Zookeeper) Watch(key string, _ time.Duration, callback WatchCallback) error {
-	fkey := format(key)
-	_, _, eventChan, err := s.client.GetW(fkey)
+// Watch changes on a key.
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Zookeeper) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	fkey := normalize(key)
+	pair, err := s.Get(key)
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
 
 
-	// Create a new Watch entry with eventChan
-	s.watches[fkey] = eventChan
+	// Catch zk notifications and fire changes into the channel.
+	watchCh := make(chan *KVPair)
+	go func() {
+		defer close(watchCh)
 
 
-	for e := range eventChan {
-		if e.Type == zk.EventNodeChildrenChanged {
-			log.WithField("name", "zk").Debug("Discovery watch triggered")
-			entry, index, err := s.Get(key)
-			kvi := []KVEntry{&kviTuple{key, []byte(entry), index}}
-			if err == nil {
-				callback(kvi)
+		// Get returns the current value before setting the watch.
+		watchCh <- pair
+		for {
+			_, _, eventCh, err := s.client.GetW(fkey)
+			if err != nil {
+				return
+			}
+			select {
+			case e := <-eventCh:
+				if e.Type == zk.EventNodeDataChanged {
+					if entry, err := s.Get(key); err == nil {
+						watchCh <- entry
+					}
+				}
+			case <-stopCh:
+				// There is no way to stop GetW so just quit
+				return
 			}
 			}
 		}
 		}
-	}
+	}()
 
 
-	return nil
+	return watchCh, nil
 }
 }
 
 
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *Zookeeper) CancelWatch(key string) error {
-	key = format(key)
-	if _, ok := s.watches[key]; !ok {
-		log.Error("Chan does not exist for key: ", key)
-		return ErrWatchDoesNotExist
+// WatchTree watches changes on a "directory"
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Zookeeper) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	fprefix := normalize(prefix)
+	entries, err := s.List(prefix)
+	if err != nil {
+		return nil, err
 	}
 	}
-	// Just remove the entry on watches key
-	s.watches[key] = nil
-	return nil
+
+	// Catch zk notifications and fire changes into the channel.
+	watchCh := make(chan []*KVPair)
+	go func() {
+		defer close(watchCh)
+
+		// List returns the current values before setting the watch.
+		watchCh <- entries
+
+		for {
+			_, _, eventCh, err := s.client.ChildrenW(fprefix)
+			if err != nil {
+				return
+			}
+			select {
+			case e := <-eventCh:
+				if e.Type == zk.EventNodeChildrenChanged {
+					if kv, err := s.List(prefix); err == nil {
+						watchCh <- kv
+					}
+				}
+			case <-stopCh:
+				// There is no way to stop GetW so just quit
+				return
+			}
+		}
+	}()
+
+	return watchCh, nil
 }
 }
 
 
-// GetRange gets a range of values at "directory"
-func (s *Zookeeper) GetRange(prefix string) (kvi []KVEntry, err error) {
-	prefix = format(prefix)
-	entries, stat, err := s.client.Children(prefix)
+// List the content of a given prefix
+func (s *Zookeeper) List(prefix string) ([]*KVPair, error) {
+	keys, stat, err := s.client.Children(normalize(prefix))
 	if err != nil {
 	if err != nil {
-		log.Error("Cannot fetch range of keys beginning with prefix: ", prefix)
 		return nil, err
 		return nil, err
 	}
 	}
-	for _, item := range entries {
-		kvi = append(kvi, &kviTuple{prefix, []byte(item), uint64(stat.Mzxid)})
+	kv := []*KVPair{}
+	for _, key := range keys {
+		// FIXME Costly Get request for each child key..
+		pair, err := s.Get(prefix + normalize(key))
+		if err != nil {
+			return nil, err
+		}
+		kv = append(kv, &KVPair{key, []byte(pair.Value), uint64(stat.Version)})
 	}
 	}
-	return kvi, err
+	return kv, nil
 }
 }
 
 
-// DeleteRange deletes a range of values at "directory"
-func (s *Zookeeper) DeleteRange(prefix string) error {
-	err := s.client.Delete(format(prefix), -1)
+// DeleteTree deletes a range of keys based on prefix
+func (s *Zookeeper) DeleteTree(prefix string) error {
+	pairs, err := s.List(prefix)
+	if err != nil {
+		return err
+	}
+	var reqs []interface{}
+	for _, pair := range pairs {
+		reqs = append(reqs, &zk.DeleteRequest{
+			Path:    normalize(prefix + "/" + pair.Key),
+			Version: -1,
+		})
+	}
+	_, err = s.client.Multi(reqs...)
 	return err
 	return err
 }
 }
 
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *Zookeeper) WatchRange(prefix string, filter string, _ time.Duration, callback WatchCallback) error {
-	fprefix := format(prefix)
-	_, _, eventChan, err := s.client.ChildrenW(fprefix)
+// AtomicPut put a value at "key" if the key has not been
+// modified in the meantime, throws an error if this is the case
+func (s *Zookeeper) AtomicPut(key string, value []byte, previous *KVPair, _ *WriteOptions) (bool, *KVPair, error) {
+	if previous == nil {
+		return false, nil, ErrPreviousNotSpecified
+	}
+
+	meta, err := s.client.Set(normalize(key), value, int32(previous.LastIndex))
 	if err != nil {
 	if err != nil {
-		return err
+		if err == zk.ErrBadVersion {
+			return false, nil, ErrKeyModified
+		}
+		return false, nil, err
 	}
 	}
+	return true, &KVPair{Key: key, Value: value, LastIndex: uint64(meta.Version)}, nil
+}
 
 
-	// Create a new Watch entry with eventChan
-	s.watches[fprefix] = eventChan
+// AtomicDelete deletes a value at "key" if the key has not
+// been modified in the meantime, throws an error if this is the case
+func (s *Zookeeper) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	if previous == nil {
+		return false, ErrPreviousNotSpecified
+	}
 
 
-	for e := range eventChan {
-		if e.Type == zk.EventNodeChildrenChanged {
-			log.WithField("name", "zk").Debug("Discovery watch triggered")
-			kvi, err := s.GetRange(prefix)
-			if err == nil {
-				callback(kvi)
-			}
+	err := s.client.Delete(normalize(key), int32(previous.LastIndex))
+	if err != nil {
+		if err == zk.ErrBadVersion {
+			return false, ErrKeyModified
 		}
 		}
+		return false, err
 	}
 	}
-
-	return nil
+	return true, nil
 }
 }
 
 
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *Zookeeper) CancelWatchRange(prefix string) error {
-	return s.CancelWatch(prefix)
-}
+// NewLock returns a handle to a lock struct which can be used to acquire and
+// release the mutex.
+func (s *Zookeeper) NewLock(key string, options *LockOptions) (Locker, error) {
+	value := []byte("")
 
 
-// AtomicPut put a value at "key" if the key has not been
-// modified in the meantime, throws an error if this is the case
-func (s *Zookeeper) AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error) {
-	// Use index of Set method to implement CAS
-	return false, ErrNotImplemented
+	// Apply options
+	if options != nil {
+		if options.Value != nil {
+			value = options.Value
+		}
+	}
+
+	return &zookeeperLock{
+		client: s.client,
+		key:    normalize(key),
+		value:  value,
+		lock:   zk.NewLock(s.client, normalize(key), zk.WorldACL(zk.PermAll)),
+	}, nil
 }
 }
 
 
-// AtomicDelete deletes a value at "key" if the key has not
-// been modified in the meantime, throws an error if this is the case
-func (s *Zookeeper) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
-	return false, ErrNotImplemented
+// Lock attempts to acquire the lock and blocks while doing so.
+// Returns a channel that is closed if our lock is lost or an error.
+func (l *zookeeperLock) Lock() (<-chan struct{}, error) {
+	err := l.lock.Lock()
+
+	if err == nil {
+		// We hold the lock, we can set our value
+		// FIXME: When the last leader leaves the election, this value will be left behind
+		_, err = l.client.Set(l.key, l.value, -1)
+	}
+
+	return make(chan struct{}), err
 }
 }
 
 
-// Acquire the lock for "key"/"directory"
-func (s *Zookeeper) Acquire(path string, value []byte) (string, error) {
-	// lock := zk.NewLock(s.client, path, nil)
-	// locks[path] = lock
-	// lock.Lock()
-	return "", ErrNotImplemented
+// Unlock released the lock. It is an error to call this
+// if the lock is not currently held.
+func (l *zookeeperLock) Unlock() error {
+	return l.lock.Unlock()
 }
 }
 
 
-// Release the lock for "key"/"directory"
-func (s *Zookeeper) Release(session string) error {
-	return ErrNotImplemented
+// Close closes the client connection
+func (s *Zookeeper) Close() {
+	s.client.Close()
 }
 }

+ 30 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper_test.go

@@ -0,0 +1,30 @@
+package store
+
+import (
+	"testing"
+	"time"
+)
+
+func makeZkClient(t *testing.T) Store {
+	client := "localhost:2181"
+
+	kv, err := NewStore(
+		ZK,
+		[]string{client},
+		&Config{
+			ConnectionTimeout: 3 * time.Second,
+			EphemeralTTL:      2 * time.Second,
+		},
+	)
+	if err != nil {
+		t.Fatalf("cannot create store: %v", err)
+	}
+
+	return kv
+}
+
+func TestZkStore(t *testing.T) {
+	kv := makeZkClient(t)
+
+	testStore(t, kv)
+}

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/.gitignore

@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe

+ 23 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/LICENSE.md

@@ -0,0 +1,23 @@
+objx - by Mat Ryer and Tyler Bunnell
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Stretchr, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 3 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/README.md

@@ -0,0 +1,3 @@
+# objx
+
+  * Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx)

+ 179 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors.go

@@ -0,0 +1,179 @@
+package objx
+
+import (
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+// arrayAccesRegexString is the regex used to extract the array number
+// from the access path
+const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
+
+// arrayAccesRegex is the compiled arrayAccesRegexString
+var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
+
+// Get gets the value using the specified selector and
+// returns it inside a new Obj object.
+//
+// If it cannot find the value, Get will return a nil
+// value inside an instance of Obj.
+//
+// Get can only operate directly on map[string]interface{} and []interface.
+//
+// Example
+//
+// To access the title of the third chapter of the second book, do:
+//
+//    o.Get("books[1].chapters[2].title")
+func (m Map) Get(selector string) *Value {
+	rawObj := access(m, selector, nil, false, false)
+	return &Value{data: rawObj}
+}
+
+// Set sets the value using the specified selector and
+// returns the object on which Set was called.
+//
+// Set can only operate directly on map[string]interface{} and []interface
+//
+// Example
+//
+// To set the title of the third chapter of the second book, do:
+//
+//    o.Set("books[1].chapters[2].title","Time to Go")
+func (m Map) Set(selector string, value interface{}) Map {
+	access(m, selector, value, true, false)
+	return m
+}
+
+// access accesses the object using the selector and performs the
+// appropriate action.
+func access(current, selector, value interface{}, isSet, panics bool) interface{} {
+
+	switch selector.(type) {
+	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+
+		if array, ok := current.([]interface{}); ok {
+			index := intFromInterface(selector)
+
+			if index >= len(array) {
+				if panics {
+					panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
+				}
+				return nil
+			}
+
+			return array[index]
+		}
+
+		return nil
+
+	case string:
+
+		selStr := selector.(string)
+		selSegs := strings.SplitN(selStr, PathSeparator, 2)
+		thisSel := selSegs[0]
+		index := -1
+		var err error
+
+		// https://github.com/stretchr/objx/issues/12
+		if strings.Contains(thisSel, "[") {
+
+			arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
+
+			if len(arrayMatches) > 0 {
+
+				// Get the key into the map
+				thisSel = arrayMatches[1]
+
+				// Get the index into the array at the key
+				index, err = strconv.Atoi(arrayMatches[2])
+
+				if err != nil {
+					// This should never happen. If it does, something has gone
+					// seriously wrong. Panic.
+					panic("objx: Array index is not an integer.  Must use array[int].")
+				}
+
+			}
+		}
+
+		if curMap, ok := current.(Map); ok {
+			current = map[string]interface{}(curMap)
+		}
+
+		// get the object in question
+		switch current.(type) {
+		case map[string]interface{}:
+			curMSI := current.(map[string]interface{})
+			if len(selSegs) <= 1 && isSet {
+				curMSI[thisSel] = value
+				return nil
+			} else {
+				current = curMSI[thisSel]
+			}
+		default:
+			current = nil
+		}
+
+		if current == nil && panics {
+			panic(fmt.Sprintf("objx: '%v' invalid on object.", selector))
+		}
+
+		// do we need to access the item of an array?
+		if index > -1 {
+			if array, ok := current.([]interface{}); ok {
+				if index < len(array) {
+					current = array[index]
+				} else {
+					if panics {
+						panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
+					}
+					current = nil
+				}
+			}
+		}
+
+		if len(selSegs) > 1 {
+			current = access(current, selSegs[1], value, isSet, panics)
+		}
+
+	}
+
+	return current
+
+}
+
+// intFromInterface converts an interface object to the largest
+// representation of an unsigned integer using a type switch and
+// assertions
+func intFromInterface(selector interface{}) int {
+	var value int
+	switch selector.(type) {
+	case int:
+		value = selector.(int)
+	case int8:
+		value = int(selector.(int8))
+	case int16:
+		value = int(selector.(int16))
+	case int32:
+		value = int(selector.(int32))
+	case int64:
+		value = int(selector.(int64))
+	case uint:
+		value = int(selector.(uint))
+	case uint8:
+		value = int(selector.(uint8))
+	case uint16:
+		value = int(selector.(uint16))
+	case uint32:
+		value = int(selector.(uint32))
+	case uint64:
+		value = int(selector.(uint64))
+	default:
+		panic("objx: array access argument is not an integer type (this should never happen)")
+	}
+
+	return value
+}

+ 145 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors_test.go

@@ -0,0 +1,145 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestAccessorsAccessGetSingleField(t *testing.T) {
+
+	current := map[string]interface{}{"name": "Tyler"}
+	assert.Equal(t, "Tyler", access(current, "name", nil, false, true))
+
+}
+func TestAccessorsAccessGetDeep(t *testing.T) {
+
+	current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
+	assert.Equal(t, "Tyler", access(current, "name.first", nil, false, true))
+	assert.Equal(t, "Bunnell", access(current, "name.last", nil, false, true))
+
+}
+func TestAccessorsAccessGetDeepDeep(t *testing.T) {
+
+	current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
+	assert.Equal(t, 4, access(current, "one.two.three.four", nil, false, true))
+
+}
+func TestAccessorsAccessGetInsideArray(t *testing.T) {
+
+	current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
+	assert.Equal(t, "Tyler", access(current, "names[0].first", nil, false, true))
+	assert.Equal(t, "Bunnell", access(current, "names[0].last", nil, false, true))
+	assert.Equal(t, "Capitol", access(current, "names[1].first", nil, false, true))
+	assert.Equal(t, "Bollocks", access(current, "names[1].last", nil, false, true))
+
+	assert.Panics(t, func() {
+		access(current, "names[2]", nil, false, true)
+	})
+	assert.Nil(t, access(current, "names[2]", nil, false, false))
+
+}
+
+func TestAccessorsAccessGetFromArrayWithInt(t *testing.T) {
+
+	current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
+	one := access(current, 0, nil, false, false)
+	two := access(current, 1, nil, false, false)
+	three := access(current, 2, nil, false, false)
+
+	assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
+	assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
+	assert.Nil(t, three)
+
+}
+
+func TestAccessorsGet(t *testing.T) {
+
+	current := New(map[string]interface{}{"name": "Tyler"})
+	assert.Equal(t, "Tyler", current.Get("name").data)
+
+}
+
+func TestAccessorsAccessSetSingleField(t *testing.T) {
+
+	current := map[string]interface{}{"name": "Tyler"}
+	access(current, "name", "Mat", true, false)
+	assert.Equal(t, current["name"], "Mat")
+
+	access(current, "age", 29, true, true)
+	assert.Equal(t, current["age"], 29)
+
+}
+
+func TestAccessorsAccessSetSingleFieldNotExisting(t *testing.T) {
+
+	current := map[string]interface{}{}
+	access(current, "name", "Mat", true, false)
+	assert.Equal(t, current["name"], "Mat")
+
+}
+
+func TestAccessorsAccessSetDeep(t *testing.T) {
+
+	current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
+
+	access(current, "name.first", "Mat", true, true)
+	access(current, "name.last", "Ryer", true, true)
+
+	assert.Equal(t, "Mat", access(current, "name.first", nil, false, true))
+	assert.Equal(t, "Ryer", access(current, "name.last", nil, false, true))
+
+}
+func TestAccessorsAccessSetDeepDeep(t *testing.T) {
+
+	current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
+
+	access(current, "one.two.three.four", 5, true, true)
+
+	assert.Equal(t, 5, access(current, "one.two.three.four", nil, false, true))
+
+}
+func TestAccessorsAccessSetArray(t *testing.T) {
+
+	current := map[string]interface{}{"names": []interface{}{"Tyler"}}
+
+	access(current, "names[0]", "Mat", true, true)
+
+	assert.Equal(t, "Mat", access(current, "names[0]", nil, false, true))
+
+}
+func TestAccessorsAccessSetInsideArray(t *testing.T) {
+
+	current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
+
+	access(current, "names[0].first", "Mat", true, true)
+	access(current, "names[0].last", "Ryer", true, true)
+	access(current, "names[1].first", "Captain", true, true)
+	access(current, "names[1].last", "Underpants", true, true)
+
+	assert.Equal(t, "Mat", access(current, "names[0].first", nil, false, true))
+	assert.Equal(t, "Ryer", access(current, "names[0].last", nil, false, true))
+	assert.Equal(t, "Captain", access(current, "names[1].first", nil, false, true))
+	assert.Equal(t, "Underpants", access(current, "names[1].last", nil, false, true))
+
+}
+
+func TestAccessorsAccessSetFromArrayWithInt(t *testing.T) {
+
+	current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
+	one := access(current, 0, nil, false, false)
+	two := access(current, 1, nil, false, false)
+	three := access(current, 2, nil, false, false)
+
+	assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
+	assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
+	assert.Nil(t, three)
+
+}
+
+func TestAccessorsSet(t *testing.T) {
+
+	current := New(map[string]interface{}{"name": "Tyler"})
+	current.Set("name", "Mat")
+	assert.Equal(t, "Mat", current.Get("name").data)
+
+}

+ 14 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/array-access.txt

@@ -0,0 +1,14 @@
+  case []{1}:
+    a := object.([]{1})
+    if isSet {
+      a[index] = value.({1})
+    } else {
+      if index >= len(a) {
+        if panics {
+          panic(fmt.Sprintf("objx: Index %d is out of range because the []{1} only contains %d items.", index, len(a)))
+        }
+        return nil
+      } else {
+        return a[index]
+      }
+    }

+ 86 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/index.html

@@ -0,0 +1,86 @@
+<html>
+	<head>
+	<title>
+		Codegen
+	</title>
+	<style>
+		body {
+			width: 800px;
+			margin: auto;
+		}
+		textarea {
+			width: 100%;
+			min-height: 100px;
+			font-family: Courier;
+		}
+	</style>
+	</head>
+	<body>
+
+		<h2>
+			Template
+		</h2>
+		<p>
+			Use <code>{x}</code> as a placeholder for each argument.
+		</p>
+		<textarea id="template"></textarea>
+
+		<h2>
+			Arguments (comma separated)
+		</h2>
+		<p>
+			One block per line
+		</p>
+		<textarea id="args"></textarea>
+
+		<h2>
+			Output
+		</h2>
+		<input id="go" type="button" value="Generate code" />
+
+		<textarea id="output"></textarea>
+
+		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
+		<script>
+
+			$(function(){
+
+				$("#go").click(function(){
+
+					var output = ""
+					var template = $("#template").val()
+					var args = $("#args").val()
+
+					// collect the args
+					var argLines = args.split("\n")
+					for (var line in argLines) {
+
+						var argLine = argLines[line];
+						var thisTemp = template
+
+						// get individual args
+						var args = argLine.split(",")
+
+						for (var argI in args) {
+							var argText = args[argI];
+							var argPlaceholder = "{" + argI + "}";
+
+							while (thisTemp.indexOf(argPlaceholder) > -1) {
+								thisTemp = thisTemp.replace(argPlaceholder, argText);
+							}
+
+						}
+
+						output += thisTemp
+
+					}
+
+					$("#output").val(output);
+
+				});
+
+			});
+
+		</script>
+	</body>
+</html>

+ 286 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/template.txt

@@ -0,0 +1,286 @@
+/*
+	{4} ({1} and []{1})
+	--------------------------------------------------
+*/
+
+// {4} gets the value as a {1}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) {4}(optionalDefault ...{1}) {1} {
+	if s, ok := v.data.({1}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return {3}
+}
+
+// Must{4} gets the value as a {1}.
+//
+// Panics if the object is not a {1}.
+func (v *Value) Must{4}() {1} {
+	return v.data.({1})
+}
+
+// {4}Slice gets the value as a []{1}, returns the optionalDefault
+// value or nil if the value is not a []{1}.
+func (v *Value) {4}Slice(optionalDefault ...[]{1}) []{1} {
+	if s, ok := v.data.([]{1}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// Must{4}Slice gets the value as a []{1}.
+//
+// Panics if the object is not a []{1}.
+func (v *Value) Must{4}Slice() []{1} {
+	return v.data.([]{1})
+}
+
+// Is{4} gets whether the object contained is a {1} or not.
+func (v *Value) Is{4}() bool {
+  _, ok := v.data.({1})
+  return ok
+}
+
+// Is{4}Slice gets whether the object contained is a []{1} or not.
+func (v *Value) Is{4}Slice() bool {
+	_, ok := v.data.([]{1})
+	return ok
+}
+
+// Each{4} calls the specified callback for each object
+// in the []{1}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) Each{4}(callback func(int, {1}) bool) *Value {
+
+	for index, val := range v.Must{4}Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// Where{4} uses the specified decider function to select items
+// from the []{1}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) Where{4}(decider func(int, {1}) bool) *Value {
+
+	var selected []{1}
+
+	v.Each{4}(func(index int, val {1}) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data:selected}
+
+}
+
+// Group{4} uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]{1}.
+func (v *Value) Group{4}(grouper func(int, {1}) string) *Value {
+
+	groups := make(map[string][]{1})
+
+	v.Each{4}(func(index int, val {1}) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]{1}, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data:groups}
+
+}
+
+// Replace{4} uses the specified function to replace each {1}s
+// by iterating each item.  The data in the returned result will be a
+// []{1} containing the replaced items.
+func (v *Value) Replace{4}(replacer func(int, {1}) {1}) *Value {
+
+	arr := v.Must{4}Slice()
+	replaced := make([]{1}, len(arr))
+
+	v.Each{4}(func(index int, val {1}) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data:replaced}
+
+}
+
+// Collect{4} uses the specified collector function to collect a value
+// for each of the {1}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) Collect{4}(collector func(int, {1}) interface{}) *Value {
+
+	arr := v.Must{4}Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.Each{4}(func(index int, val {1}) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data:collected}
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func Test{4}(t *testing.T) {
+
+  val := {1}( {2} )
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").{4}())
+	assert.Equal(t, val, New(m).Get("value").Must{4}())
+	assert.Equal(t, {1}({3}), New(m).Get("nothing").{4}())
+	assert.Equal(t, val, New(m).Get("nothing").{4}({2}))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").Must{4}()
+	})
+
+}
+
+func Test{4}Slice(t *testing.T) {
+
+  val := {1}( {2} )
+	m := map[string]interface{}{"value": []{1}{ val }, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").{4}Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").Must{4}Slice()[0])
+	assert.Equal(t, []{1}(nil), New(m).Get("nothing").{4}Slice())
+	assert.Equal(t, val, New(m).Get("nothing").{4}Slice( []{1}{ {1}({2}) } )[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").Must{4}Slice()
+	})
+
+}
+
+func TestIs{4}(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: {1}({2})}
+	assert.True(t, v.Is{4}())
+
+	v = &Value{data: []{1}{ {1}({2}) }}
+	assert.True(t, v.Is{4}Slice())
+
+}
+
+func TestEach{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+	count := 0
+	replacedVals := make([]{1}, 0)
+	assert.Equal(t, v, v.Each{4}(func(i int, val {1}) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.Must{4}Slice()[0])
+	assert.Equal(t, replacedVals[1], v.Must{4}Slice()[1])
+	assert.Equal(t, replacedVals[2], v.Must{4}Slice()[2])
+
+}
+
+func TestWhere{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	selected := v.Where{4}(func(i int, val {1}) bool {
+		return i%2==0
+	}).Must{4}Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroup{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	grouped := v.Group{4}(func(i int, val {1}) string {
+		return fmt.Sprintf("%v", i%2==0)
+	}).data.(map[string][]{1})
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplace{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	rawArr := v.Must{4}Slice()
+
+	replaced := v.Replace{4}(func(index int, val {1}) {1} {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.Must{4}Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollect{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	collected := v.Collect{4}(func(index int, val {1}) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}

+ 20 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/types_list.txt

@@ -0,0 +1,20 @@
+Interface,interface{},"something",nil,Inter
+Map,map[string]interface{},map[string]interface{}{"name":"Tyler"},nil,MSI
+ObjxMap,(Map),New(1),New(nil),ObjxMap
+Bool,bool,true,false,Bool
+String,string,"hello","",Str
+Int,int,1,0,Int
+Int8,int8,1,0,Int8
+Int16,int16,1,0,Int16
+Int32,int32,1,0,Int32
+Int64,int64,1,0,Int64
+Uint,uint,1,0,Uint
+Uint8,uint8,1,0,Uint8
+Uint16,uint16,1,0,Uint16
+Uint32,uint32,1,0,Uint32
+Uint64,uint64,1,0,Uint64
+Uintptr,uintptr,1,0,Uintptr
+Float32,float32,1,0,Float32
+Float64,float64,1,0,Float64
+Complex64,complex64,1,0,Complex64
+Complex128,complex128,1,0,Complex128

+ 13 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/constants.go

@@ -0,0 +1,13 @@
+package objx
+
+const (
+	// PathSeparator is the character used to separate the elements
+	// of the keypath.
+	//
+	// For example, `location.address.city`
+	PathSeparator string = "."
+
+	// SignatureSeparator is the character that is used to
+	// separate the Base64 string from the security signature.
+	SignatureSeparator = "_"
+)

+ 117 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions.go

@@ -0,0 +1,117 @@
+package objx
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/url"
+)
+
+// JSON converts the contained object to a JSON string
+// representation
+func (m Map) JSON() (string, error) {
+
+	result, err := json.Marshal(m)
+
+	if err != nil {
+		err = errors.New("objx: JSON encode failed with: " + err.Error())
+	}
+
+	return string(result), err
+
+}
+
+// MustJSON converts the contained object to a JSON string
+// representation and panics if there is an error
+func (m Map) MustJSON() string {
+	result, err := m.JSON()
+	if err != nil {
+		panic(err.Error())
+	}
+	return result
+}
+
+// Base64 converts the contained object to a Base64 string
+// representation of the JSON string representation
+func (m Map) Base64() (string, error) {
+
+	var buf bytes.Buffer
+
+	jsonData, err := m.JSON()
+	if err != nil {
+		return "", err
+	}
+
+	encoder := base64.NewEncoder(base64.StdEncoding, &buf)
+	encoder.Write([]byte(jsonData))
+	encoder.Close()
+
+	return buf.String(), nil
+
+}
+
+// MustBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and panics
+// if there is an error
+func (m Map) MustBase64() string {
+	result, err := m.Base64()
+	if err != nil {
+		panic(err.Error())
+	}
+	return result
+}
+
+// SignedBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and signs it
+// using the provided key.
+func (m Map) SignedBase64(key string) (string, error) {
+
+	base64, err := m.Base64()
+	if err != nil {
+		return "", err
+	}
+
+	sig := HashWithKey(base64, key)
+
+	return base64 + SignatureSeparator + sig, nil
+
+}
+
+// MustSignedBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and signs it
+// using the provided key and panics if there is an error
+func (m Map) MustSignedBase64(key string) string {
+	result, err := m.SignedBase64(key)
+	if err != nil {
+		panic(err.Error())
+	}
+	return result
+}
+
+/*
+	URL Query
+	------------------------------------------------
+*/
+
+// URLValues creates a url.Values object from an Obj. This
+// function requires that the wrapped object be a map[string]interface{}
+func (m Map) URLValues() url.Values {
+
+	vals := make(url.Values)
+
+	for k, v := range m {
+		//TODO: can this be done without sprintf?
+		vals.Set(k, fmt.Sprintf("%v", v))
+	}
+
+	return vals
+}
+
+// URLQuery gets an encoded URL query representing the given
+// Obj. This function requires that the wrapped object be a
+// map[string]interface{}
+func (m Map) URLQuery() (string, error) {
+	return m.URLValues().Encode(), nil
+}

+ 94 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions_test.go

@@ -0,0 +1,94 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestConversionJSON(t *testing.T) {
+
+	jsonString := `{"name":"Mat"}`
+	o := MustFromJSON(jsonString)
+
+	result, err := o.JSON()
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, jsonString, result)
+	}
+
+	assert.Equal(t, jsonString, o.MustJSON())
+
+}
+
+func TestConversionJSONWithError(t *testing.T) {
+
+	o := MSI()
+	o["test"] = func() {}
+
+	assert.Panics(t, func() {
+		o.MustJSON()
+	})
+
+	_, err := o.JSON()
+
+	assert.Error(t, err)
+
+}
+
+func TestConversionBase64(t *testing.T) {
+
+	o := New(map[string]interface{}{"name": "Mat"})
+
+	result, err := o.Base64()
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", result)
+	}
+
+	assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", o.MustBase64())
+
+}
+
+func TestConversionBase64WithError(t *testing.T) {
+
+	o := MSI()
+	o["test"] = func() {}
+
+	assert.Panics(t, func() {
+		o.MustBase64()
+	})
+
+	_, err := o.Base64()
+
+	assert.Error(t, err)
+
+}
+
+func TestConversionSignedBase64(t *testing.T) {
+
+	o := New(map[string]interface{}{"name": "Mat"})
+
+	result, err := o.SignedBase64("key")
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", result)
+	}
+
+	assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", o.MustSignedBase64("key"))
+
+}
+
+func TestConversionSignedBase64WithError(t *testing.T) {
+
+	o := MSI()
+	o["test"] = func() {}
+
+	assert.Panics(t, func() {
+		o.MustSignedBase64("key")
+	})
+
+	_, err := o.SignedBase64("key")
+
+	assert.Error(t, err)
+
+}

+ 72 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/doc.go

@@ -0,0 +1,72 @@
+// objx - Go package for dealing with maps, slices, JSON and other data.
+//
+// Overview
+//
+// Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
+// a powerful `Get` method (among others) that allows you to easily and quickly get
+// access to data within the map, without having to worry too much about type assertions,
+// missing data, default values etc.
+//
+// Pattern
+//
+// Objx uses a preditable pattern to make access data from within `map[string]interface{}'s
+// easy.
+//
+// Call one of the `objx.` functions to create your `objx.Map` to get going:
+//
+//     m, err := objx.FromJSON(json)
+//
+// NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
+// the rest will be optimistic and try to figure things out without panicking.
+//
+// Use `Get` to access the value you're interested in.  You can use dot and array
+// notation too:
+//
+//     m.Get("places[0].latlng")
+//
+// Once you have saught the `Value` you're interested in, you can use the `Is*` methods
+// to determine its type.
+//
+//     if m.Get("code").IsStr() { /* ... */ }
+//
+// Or you can just assume the type, and use one of the strong type methods to
+// extract the real value:
+//
+//     m.Get("code").Int()
+//
+// If there's no value there (or if it's the wrong type) then a default value
+// will be returned, or you can be explicit about the default value.
+//
+//     Get("code").Int(-1)
+//
+// If you're dealing with a slice of data as a value, Objx provides many useful
+// methods for iterating, manipulating and selecting that data.  You can find out more
+// by exploring the index below.
+//
+// Reading data
+//
+// A simple example of how to use Objx:
+//
+//     // use MustFromJSON to make an objx.Map from some JSON
+//     m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
+//
+//     // get the details
+//     name := m.Get("name").Str()
+//     age := m.Get("age").Int()
+//
+//     // get their nickname (or use their name if they
+//     // don't have one)
+//     nickname := m.Get("nickname").Str(name)
+//
+// Ranging
+//
+// Since `objx.Map` is a `map[string]interface{}` you can treat it as such.  For
+// example, to `range` the data, do what you would expect:
+//
+//     m := objx.MustFromJSON(json)
+//     for key, value := range m {
+//
+//       /* ... do your magic ... */
+//
+//     }
+package objx

+ 98 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/fixture_test.go

@@ -0,0 +1,98 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+var fixtures = []struct {
+	// name is the name of the fixture (used for reporting
+	// failures)
+	name string
+	// data is the JSON data to be worked on
+	data string
+	// get is the argument(s) to pass to Get
+	get interface{}
+	// output is the expected output
+	output interface{}
+}{
+	{
+		name:   "Simple get",
+		data:   `{"name": "Mat"}`,
+		get:    "name",
+		output: "Mat",
+	},
+	{
+		name:   "Get with dot notation",
+		data:   `{"address": {"city": "Boulder"}}`,
+		get:    "address.city",
+		output: "Boulder",
+	},
+	{
+		name:   "Deep get with dot notation",
+		data:   `{"one": {"two": {"three": {"four": "hello"}}}}`,
+		get:    "one.two.three.four",
+		output: "hello",
+	},
+	{
+		name:   "Get missing with dot notation",
+		data:   `{"one": {"two": {"three": {"four": "hello"}}}}`,
+		get:    "one.ten",
+		output: nil,
+	},
+	{
+		name:   "Get with array notation",
+		data:   `{"tags": ["one", "two", "three"]}`,
+		get:    "tags[1]",
+		output: "two",
+	},
+	{
+		name:   "Get with array and dot notation",
+		data:   `{"types": { "tags": ["one", "two", "three"]}}`,
+		get:    "types.tags[1]",
+		output: "two",
+	},
+	{
+		name:   "Get with array and dot notation - field after array",
+		data:   `{"tags": [{"name":"one"}, {"name":"two"}, {"name":"three"}]}`,
+		get:    "tags[1].name",
+		output: "two",
+	},
+	{
+		name:   "Complex get with array and dot notation",
+		data:   `{"tags": [{"list": [{"one":"pizza"}]}]}`,
+		get:    "tags[0].list[0].one",
+		output: "pizza",
+	},
+	{
+		name:   "Get field from within string should be nil",
+		data:   `{"name":"Tyler"}`,
+		get:    "name.something",
+		output: nil,
+	},
+	{
+		name:   "Get field from within string (using array accessor) should be nil",
+		data:   `{"numbers":["one", "two", "three"]}`,
+		get:    "numbers[0].nope",
+		output: nil,
+	},
+}
+
+func TestFixtures(t *testing.T) {
+
+	for _, fixture := range fixtures {
+
+		m := MustFromJSON(fixture.data)
+
+		// get the value
+		t.Logf("Running get fixture: \"%s\" (%v)", fixture.name, fixture)
+		value := m.Get(fixture.get.(string))
+
+		// make sure it matches
+		assert.Equal(t, fixture.output, value.data,
+			"Get fixture \"%s\" failed: %v", fixture.name, fixture,
+		)
+
+	}
+
+}

+ 222 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map.go

@@ -0,0 +1,222 @@
+package objx
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"net/url"
+	"strings"
+)
+
+// MSIConvertable is an interface that defines methods for converting your
+// custom types to a map[string]interface{} representation.
+type MSIConvertable interface {
+	// MSI gets a map[string]interface{} (msi) representing the
+	// object.
+	MSI() map[string]interface{}
+}
+
+// Map provides extended functionality for working with
+// untyped data, in particular map[string]interface (msi).
+type Map map[string]interface{}
+
+// Value returns the internal value instance
+func (m Map) Value() *Value {
+	return &Value{data: m}
+}
+
+// Nil represents a nil Map.
+var Nil Map = New(nil)
+
+// New creates a new Map containing the map[string]interface{} in the data argument.
+// If the data argument is not a map[string]interface, New attempts to call the
+// MSI() method on the MSIConvertable interface to create one.
+func New(data interface{}) Map {
+	if _, ok := data.(map[string]interface{}); !ok {
+		if converter, ok := data.(MSIConvertable); ok {
+			data = converter.MSI()
+		} else {
+			return nil
+		}
+	}
+	return Map(data.(map[string]interface{}))
+}
+
+// MSI creates a map[string]interface{} and puts it inside a new Map.
+//
+// The arguments follow a key, value pattern.
+//
+// Panics
+//
+// Panics if any key arugment is non-string or if there are an odd number of arguments.
+//
+// Example
+//
+// To easily create Maps:
+//
+//     m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
+//
+//     // creates an Map equivalent to
+//     m := objx.New(map[string]interface{}{"name": "Mat", "age": 29, "subobj": map[string]interface{}{"active": true}})
+func MSI(keyAndValuePairs ...interface{}) Map {
+
+	newMap := make(map[string]interface{})
+	keyAndValuePairsLen := len(keyAndValuePairs)
+
+	if keyAndValuePairsLen%2 != 0 {
+		panic("objx: MSI must have an even number of arguments following the 'key, value' pattern.")
+	}
+
+	for i := 0; i < keyAndValuePairsLen; i = i + 2 {
+
+		key := keyAndValuePairs[i]
+		value := keyAndValuePairs[i+1]
+
+		// make sure the key is a string
+		keyString, keyStringOK := key.(string)
+		if !keyStringOK {
+			panic("objx: MSI must follow 'string, interface{}' pattern.  " + keyString + " is not a valid key.")
+		}
+
+		newMap[keyString] = value
+
+	}
+
+	return New(newMap)
+}
+
+// ****** Conversion Constructors
+
+// MustFromJSON creates a new Map containing the data specified in the
+// jsonString.
+//
+// Panics if the JSON is invalid.
+func MustFromJSON(jsonString string) Map {
+	o, err := FromJSON(jsonString)
+
+	if err != nil {
+		panic("objx: MustFromJSON failed with error: " + err.Error())
+	}
+
+	return o
+}
+
+// FromJSON creates a new Map containing the data specified in the
+// jsonString.
+//
+// Returns an error if the JSON is invalid.
+func FromJSON(jsonString string) (Map, error) {
+
+	var data interface{}
+	err := json.Unmarshal([]byte(jsonString), &data)
+
+	if err != nil {
+		return Nil, err
+	}
+
+	return New(data), nil
+
+}
+
+// FromBase64 creates a new Obj containing the data specified
+// in the Base64 string.
+//
+// The string is an encoded JSON string returned by Base64
+func FromBase64(base64String string) (Map, error) {
+
+	decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
+
+	decoded, err := ioutil.ReadAll(decoder)
+	if err != nil {
+		return nil, err
+	}
+
+	return FromJSON(string(decoded))
+}
+
+// MustFromBase64 creates a new Obj containing the data specified
+// in the Base64 string and panics if there is an error.
+//
+// The string is an encoded JSON string returned by Base64
+func MustFromBase64(base64String string) Map {
+
+	result, err := FromBase64(base64String)
+
+	if err != nil {
+		panic("objx: MustFromBase64 failed with error: " + err.Error())
+	}
+
+	return result
+}
+
+// FromSignedBase64 creates a new Obj containing the data specified
+// in the Base64 string.
+//
+// The string is an encoded JSON string returned by SignedBase64
+func FromSignedBase64(base64String, key string) (Map, error) {
+	parts := strings.Split(base64String, SignatureSeparator)
+	if len(parts) != 2 {
+		return nil, errors.New("objx: Signed base64 string is malformed.")
+	}
+
+	sig := HashWithKey(parts[0], key)
+	if parts[1] != sig {
+		return nil, errors.New("objx: Signature for base64 data does not match.")
+	}
+
+	return FromBase64(parts[0])
+}
+
+// MustFromSignedBase64 creates a new Obj containing the data specified
+// in the Base64 string and panics if there is an error.
+//
+// The string is an encoded JSON string returned by Base64
+func MustFromSignedBase64(base64String, key string) Map {
+
+	result, err := FromSignedBase64(base64String, key)
+
+	if err != nil {
+		panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
+	}
+
+	return result
+}
+
+// FromURLQuery generates a new Obj by parsing the specified
+// query.
+//
+// For queries with multiple values, the first value is selected.
+func FromURLQuery(query string) (Map, error) {
+
+	vals, err := url.ParseQuery(query)
+
+	if err != nil {
+		return nil, err
+	}
+
+	m := make(map[string]interface{})
+	for k, vals := range vals {
+		m[k] = vals[0]
+	}
+
+	return New(m), nil
+}
+
+// MustFromURLQuery generates a new Obj by parsing the specified
+// query.
+//
+// For queries with multiple values, the first value is selected.
+//
+// Panics if it encounters an error
+func MustFromURLQuery(query string) Map {
+
+	o, err := FromURLQuery(query)
+
+	if err != nil {
+		panic("objx: MustFromURLQuery failed with error: " + err.Error())
+	}
+
+	return o
+
+}

+ 10 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_for_test.go

@@ -0,0 +1,10 @@
+package objx
+
+var TestMap map[string]interface{} = map[string]interface{}{
+	"name": "Tyler",
+	"address": map[string]interface{}{
+		"city":  "Salt Lake City",
+		"state": "UT",
+	},
+	"numbers": []interface{}{"one", "two", "three", "four", "five"},
+}

+ 147 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_test.go

@@ -0,0 +1,147 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+type Convertable struct {
+	name string
+}
+
+func (c *Convertable) MSI() map[string]interface{} {
+	return map[string]interface{}{"name": c.name}
+}
+
+type Unconvertable struct {
+	name string
+}
+
+func TestMapCreation(t *testing.T) {
+
+	o := New(nil)
+	assert.Nil(t, o)
+
+	o = New("Tyler")
+	assert.Nil(t, o)
+
+	unconvertable := &Unconvertable{name: "Tyler"}
+	o = New(unconvertable)
+	assert.Nil(t, o)
+
+	convertable := &Convertable{name: "Tyler"}
+	o = New(convertable)
+	if assert.NotNil(t, convertable) {
+		assert.Equal(t, "Tyler", o["name"], "Tyler")
+	}
+
+	o = MSI()
+	if assert.NotNil(t, o) {
+		assert.NotNil(t, o)
+	}
+
+	o = MSI("name", "Tyler")
+	if assert.NotNil(t, o) {
+		if assert.NotNil(t, o) {
+			assert.Equal(t, o["name"], "Tyler")
+		}
+	}
+
+}
+
+func TestMapMustFromJSONWithError(t *testing.T) {
+
+	_, err := FromJSON(`"name":"Mat"}`)
+	assert.Error(t, err)
+
+}
+
+func TestMapFromJSON(t *testing.T) {
+
+	o := MustFromJSON(`{"name":"Mat"}`)
+
+	if assert.NotNil(t, o) {
+		if assert.NotNil(t, o) {
+			assert.Equal(t, "Mat", o["name"])
+		}
+	}
+
+}
+
+func TestMapFromJSONWithError(t *testing.T) {
+
+	var m Map
+
+	assert.Panics(t, func() {
+		m = MustFromJSON(`"name":"Mat"}`)
+	})
+
+	assert.Nil(t, m)
+
+}
+
+func TestMapFromBase64String(t *testing.T) {
+
+	base64String := "eyJuYW1lIjoiTWF0In0="
+
+	o, err := FromBase64(base64String)
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, o.Get("name").Str(), "Mat")
+	}
+
+	assert.Equal(t, MustFromBase64(base64String).Get("name").Str(), "Mat")
+
+}
+
+func TestMapFromBase64StringWithError(t *testing.T) {
+
+	base64String := "eyJuYW1lIjoiTWFasd0In0="
+
+	_, err := FromBase64(base64String)
+
+	assert.Error(t, err)
+
+	assert.Panics(t, func() {
+		MustFromBase64(base64String)
+	})
+
+}
+
+func TestMapFromSignedBase64String(t *testing.T) {
+
+	base64String := "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
+
+	o, err := FromSignedBase64(base64String, "key")
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, o.Get("name").Str(), "Mat")
+	}
+
+	assert.Equal(t, MustFromSignedBase64(base64String, "key").Get("name").Str(), "Mat")
+
+}
+
+func TestMapFromSignedBase64StringWithError(t *testing.T) {
+
+	base64String := "eyJuYW1lasdIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
+
+	_, err := FromSignedBase64(base64String, "key")
+
+	assert.Error(t, err)
+
+	assert.Panics(t, func() {
+		MustFromSignedBase64(base64String, "key")
+	})
+
+}
+
+func TestMapFromURLQuery(t *testing.T) {
+
+	m, err := FromURLQuery("name=tyler&state=UT")
+	if assert.NoError(t, err) && assert.NotNil(t, m) {
+		assert.Equal(t, "tyler", m.Get("name").Str())
+		assert.Equal(t, "UT", m.Get("state").Str())
+	}
+
+}

+ 81 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations.go

@@ -0,0 +1,81 @@
+package objx
+
+// Exclude returns a new Map with the keys in the specified []string
+// excluded.
+func (d Map) Exclude(exclude []string) Map {
+
+	excluded := make(Map)
+	for k, v := range d {
+		var shouldInclude bool = true
+		for _, toExclude := range exclude {
+			if k == toExclude {
+				shouldInclude = false
+				break
+			}
+		}
+		if shouldInclude {
+			excluded[k] = v
+		}
+	}
+
+	return excluded
+}
+
+// Copy creates a shallow copy of the Obj.
+func (m Map) Copy() Map {
+	copied := make(map[string]interface{})
+	for k, v := range m {
+		copied[k] = v
+	}
+	return New(copied)
+}
+
+// Merge blends the specified map with a copy of this map and returns the result.
+//
+// Keys that appear in both will be selected from the specified map.
+// This method requires that the wrapped object be a map[string]interface{}
+func (m Map) Merge(merge Map) Map {
+	return m.Copy().MergeHere(merge)
+}
+
+// Merge blends the specified map with this map and returns the current map.
+//
+// Keys that appear in both will be selected from the specified map.  The original map
+// will be modified. This method requires that
+// the wrapped object be a map[string]interface{}
+func (m Map) MergeHere(merge Map) Map {
+
+	for k, v := range merge {
+		m[k] = v
+	}
+
+	return m
+
+}
+
+// Transform builds a new Obj giving the transformer a chance
+// to change the keys and values as it goes. This method requires that
+// the wrapped object be a map[string]interface{}
+func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
+	newMap := make(map[string]interface{})
+	for k, v := range m {
+		modifiedKey, modifiedVal := transformer(k, v)
+		newMap[modifiedKey] = modifiedVal
+	}
+	return New(newMap)
+}
+
+// TransformKeys builds a new map using the specified key mapping.
+//
+// Unspecified keys will be unaltered.
+// This method requires that the wrapped object be a map[string]interface{}
+func (m Map) TransformKeys(mapping map[string]string) Map {
+	return m.Transform(func(key string, value interface{}) (string, interface{}) {
+
+		if newKey, ok := mapping[key]; ok {
+			return newKey, value
+		}
+
+		return key, value
+	})
+}

+ 77 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations_test.go

@@ -0,0 +1,77 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestExclude(t *testing.T) {
+
+	d := make(Map)
+	d["name"] = "Mat"
+	d["age"] = 29
+	d["secret"] = "ABC"
+
+	excluded := d.Exclude([]string{"secret"})
+
+	assert.Equal(t, d["name"], excluded["name"])
+	assert.Equal(t, d["age"], excluded["age"])
+	assert.False(t, excluded.Has("secret"), "secret should be excluded")
+
+}
+
+func TestCopy(t *testing.T) {
+
+	d1 := make(map[string]interface{})
+	d1["name"] = "Tyler"
+	d1["location"] = "UT"
+
+	d1Obj := New(d1)
+	d2Obj := d1Obj.Copy()
+
+	d2Obj["name"] = "Mat"
+
+	assert.Equal(t, d1Obj.Get("name").Str(), "Tyler")
+	assert.Equal(t, d2Obj.Get("name").Str(), "Mat")
+
+}
+
+func TestMerge(t *testing.T) {
+
+	d := make(map[string]interface{})
+	d["name"] = "Mat"
+
+	d1 := make(map[string]interface{})
+	d1["name"] = "Tyler"
+	d1["location"] = "UT"
+
+	dObj := New(d)
+	d1Obj := New(d1)
+
+	merged := dObj.Merge(d1Obj)
+
+	assert.Equal(t, merged.Get("name").Str(), d1Obj.Get("name").Str())
+	assert.Equal(t, merged.Get("location").Str(), d1Obj.Get("location").Str())
+	assert.Empty(t, dObj.Get("location").Str())
+
+}
+
+func TestMergeHere(t *testing.T) {
+
+	d := make(map[string]interface{})
+	d["name"] = "Mat"
+
+	d1 := make(map[string]interface{})
+	d1["name"] = "Tyler"
+	d1["location"] = "UT"
+
+	dObj := New(d)
+	d1Obj := New(d1)
+
+	merged := dObj.MergeHere(d1Obj)
+
+	assert.Equal(t, dObj, merged, "With MergeHere, it should return the first modified map")
+	assert.Equal(t, merged.Get("name").Str(), d1Obj.Get("name").Str())
+	assert.Equal(t, merged.Get("location").Str(), d1Obj.Get("location").Str())
+	assert.Equal(t, merged.Get("location").Str(), dObj.Get("location").Str())
+}

+ 14 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security.go

@@ -0,0 +1,14 @@
+package objx
+
+import (
+	"crypto/sha1"
+	"encoding/hex"
+)
+
+// HashWithKey hashes the specified string using the security
+// key.
+func HashWithKey(data, key string) string {
+	hash := sha1.New()
+	hash.Write([]byte(data + ":" + key))
+	return hex.EncodeToString(hash.Sum(nil))
+}

+ 12 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security_test.go

@@ -0,0 +1,12 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestHashWithKey(t *testing.T) {
+
+	assert.Equal(t, "0ce84d8d01f2c7b6e0882b784429c54d280ea2d9", HashWithKey("abc", "def"))
+
+}

+ 41 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/simple_example_test.go

@@ -0,0 +1,41 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestSimpleExample(t *testing.T) {
+
+	// build a map from a JSON object
+	o := MustFromJSON(`{"name":"Mat","foods":["indian","chinese"], "location":{"county":"hobbiton","city":"the shire"}}`)
+
+	// Map can be used as a straight map[string]interface{}
+	assert.Equal(t, o["name"], "Mat")
+
+	// Get an Value object
+	v := o.Get("name")
+	assert.Equal(t, v, &Value{data: "Mat"})
+
+	// Test the contained value
+	assert.False(t, v.IsInt())
+	assert.False(t, v.IsBool())
+	assert.True(t, v.IsStr())
+
+	// Get the contained value
+	assert.Equal(t, v.Str(), "Mat")
+
+	// Get a default value if the contained value is not of the expected type or does not exist
+	assert.Equal(t, 1, v.Int(1))
+
+	// Get a value by using array notation
+	assert.Equal(t, "indian", o.Get("foods[0]").Data())
+
+	// Set a value by using array notation
+	o.Set("foods[0]", "italian")
+	assert.Equal(t, "italian", o.Get("foods[0]").Str())
+
+	// Get a value by using dot notation
+	assert.Equal(t, "hobbiton", o.Get("location.county").Str())
+
+}

+ 17 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests.go

@@ -0,0 +1,17 @@
+package objx
+
+// Has gets whether there is something at the specified selector
+// or not.
+//
+// If m is nil, Has will always return false.
+func (m Map) Has(selector string) bool {
+	if m == nil {
+		return false
+	}
+	return !m.Get(selector).IsNil()
+}
+
+// IsNil gets whether the data is nil or not.
+func (v *Value) IsNil() bool {
+	return v == nil || v.data == nil
+}

+ 24 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests_test.go

@@ -0,0 +1,24 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestHas(t *testing.T) {
+
+	m := New(TestMap)
+
+	assert.True(t, m.Has("name"))
+	assert.True(t, m.Has("address.state"))
+	assert.True(t, m.Has("numbers[4]"))
+
+	assert.False(t, m.Has("address.state.nope"))
+	assert.False(t, m.Has("address.nope"))
+	assert.False(t, m.Has("nope"))
+	assert.False(t, m.Has("numbers[5]"))
+
+	m = nil
+	assert.False(t, m.Has("nothing"))
+
+}

+ 2881 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen.go

@@ -0,0 +1,2881 @@
+package objx
+
+/*
+	Inter (interface{} and []interface{})
+	--------------------------------------------------
+*/
+
+// Inter gets the value as a interface{}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Inter(optionalDefault ...interface{}) interface{} {
+	if s, ok := v.data.(interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInter gets the value as a interface{}.
+//
+// Panics if the object is not a interface{}.
+func (v *Value) MustInter() interface{} {
+	return v.data.(interface{})
+}
+
+// InterSlice gets the value as a []interface{}, returns the optionalDefault
+// value or nil if the value is not a []interface{}.
+func (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} {
+	if s, ok := v.data.([]interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInterSlice gets the value as a []interface{}.
+//
+// Panics if the object is not a []interface{}.
+func (v *Value) MustInterSlice() []interface{} {
+	return v.data.([]interface{})
+}
+
+// IsInter gets whether the object contained is a interface{} or not.
+func (v *Value) IsInter() bool {
+	_, ok := v.data.(interface{})
+	return ok
+}
+
+// IsInterSlice gets whether the object contained is a []interface{} or not.
+func (v *Value) IsInterSlice() bool {
+	_, ok := v.data.([]interface{})
+	return ok
+}
+
+// EachInter calls the specified callback for each object
+// in the []interface{}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInter(callback func(int, interface{}) bool) *Value {
+
+	for index, val := range v.MustInterSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInter uses the specified decider function to select items
+// from the []interface{}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInter(decider func(int, interface{}) bool) *Value {
+
+	var selected []interface{}
+
+	v.EachInter(func(index int, val interface{}) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInter uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]interface{}.
+func (v *Value) GroupInter(grouper func(int, interface{}) string) *Value {
+
+	groups := make(map[string][]interface{})
+
+	v.EachInter(func(index int, val interface{}) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]interface{}, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInter uses the specified function to replace each interface{}s
+// by iterating each item.  The data in the returned result will be a
+// []interface{} containing the replaced items.
+func (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value {
+
+	arr := v.MustInterSlice()
+	replaced := make([]interface{}, len(arr))
+
+	v.EachInter(func(index int, val interface{}) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInter uses the specified collector function to collect a value
+// for each of the interface{}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value {
+
+	arr := v.MustInterSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInter(func(index int, val interface{}) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	MSI (map[string]interface{} and []map[string]interface{})
+	--------------------------------------------------
+*/
+
+// MSI gets the value as a map[string]interface{}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} {
+	if s, ok := v.data.(map[string]interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustMSI gets the value as a map[string]interface{}.
+//
+// Panics if the object is not a map[string]interface{}.
+func (v *Value) MustMSI() map[string]interface{} {
+	return v.data.(map[string]interface{})
+}
+
+// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault
+// value or nil if the value is not a []map[string]interface{}.
+func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} {
+	if s, ok := v.data.([]map[string]interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustMSISlice gets the value as a []map[string]interface{}.
+//
+// Panics if the object is not a []map[string]interface{}.
+func (v *Value) MustMSISlice() []map[string]interface{} {
+	return v.data.([]map[string]interface{})
+}
+
+// IsMSI gets whether the object contained is a map[string]interface{} or not.
+func (v *Value) IsMSI() bool {
+	_, ok := v.data.(map[string]interface{})
+	return ok
+}
+
+// IsMSISlice gets whether the object contained is a []map[string]interface{} or not.
+func (v *Value) IsMSISlice() bool {
+	_, ok := v.data.([]map[string]interface{})
+	return ok
+}
+
+// EachMSI calls the specified callback for each object
+// in the []map[string]interface{}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value {
+
+	for index, val := range v.MustMSISlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereMSI uses the specified decider function to select items
+// from the []map[string]interface{}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value {
+
+	var selected []map[string]interface{}
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupMSI uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]map[string]interface{}.
+func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value {
+
+	groups := make(map[string][]map[string]interface{})
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]map[string]interface{}, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceMSI uses the specified function to replace each map[string]interface{}s
+// by iterating each item.  The data in the returned result will be a
+// []map[string]interface{} containing the replaced items.
+func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value {
+
+	arr := v.MustMSISlice()
+	replaced := make([]map[string]interface{}, len(arr))
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectMSI uses the specified collector function to collect a value
+// for each of the map[string]interface{}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value {
+
+	arr := v.MustMSISlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	ObjxMap ((Map) and [](Map))
+	--------------------------------------------------
+*/
+
+// ObjxMap gets the value as a (Map), returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) ObjxMap(optionalDefault ...(Map)) Map {
+	if s, ok := v.data.((Map)); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return New(nil)
+}
+
+// MustObjxMap gets the value as a (Map).
+//
+// Panics if the object is not a (Map).
+func (v *Value) MustObjxMap() Map {
+	return v.data.((Map))
+}
+
+// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault
+// value or nil if the value is not a [](Map).
+func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) {
+	if s, ok := v.data.([](Map)); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustObjxMapSlice gets the value as a [](Map).
+//
+// Panics if the object is not a [](Map).
+func (v *Value) MustObjxMapSlice() [](Map) {
+	return v.data.([](Map))
+}
+
+// IsObjxMap gets whether the object contained is a (Map) or not.
+func (v *Value) IsObjxMap() bool {
+	_, ok := v.data.((Map))
+	return ok
+}
+
+// IsObjxMapSlice gets whether the object contained is a [](Map) or not.
+func (v *Value) IsObjxMapSlice() bool {
+	_, ok := v.data.([](Map))
+	return ok
+}
+
+// EachObjxMap calls the specified callback for each object
+// in the [](Map).
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value {
+
+	for index, val := range v.MustObjxMapSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereObjxMap uses the specified decider function to select items
+// from the [](Map).  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value {
+
+	var selected [](Map)
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupObjxMap uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][](Map).
+func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value {
+
+	groups := make(map[string][](Map))
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([](Map), 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceObjxMap uses the specified function to replace each (Map)s
+// by iterating each item.  The data in the returned result will be a
+// [](Map) containing the replaced items.
+func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value {
+
+	arr := v.MustObjxMapSlice()
+	replaced := make([](Map), len(arr))
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectObjxMap uses the specified collector function to collect a value
+// for each of the (Map)s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value {
+
+	arr := v.MustObjxMapSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Bool (bool and []bool)
+	--------------------------------------------------
+*/
+
+// Bool gets the value as a bool, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Bool(optionalDefault ...bool) bool {
+	if s, ok := v.data.(bool); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return false
+}
+
+// MustBool gets the value as a bool.
+//
+// Panics if the object is not a bool.
+func (v *Value) MustBool() bool {
+	return v.data.(bool)
+}
+
+// BoolSlice gets the value as a []bool, returns the optionalDefault
+// value or nil if the value is not a []bool.
+func (v *Value) BoolSlice(optionalDefault ...[]bool) []bool {
+	if s, ok := v.data.([]bool); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustBoolSlice gets the value as a []bool.
+//
+// Panics if the object is not a []bool.
+func (v *Value) MustBoolSlice() []bool {
+	return v.data.([]bool)
+}
+
+// IsBool gets whether the object contained is a bool or not.
+func (v *Value) IsBool() bool {
+	_, ok := v.data.(bool)
+	return ok
+}
+
+// IsBoolSlice gets whether the object contained is a []bool or not.
+func (v *Value) IsBoolSlice() bool {
+	_, ok := v.data.([]bool)
+	return ok
+}
+
+// EachBool calls the specified callback for each object
+// in the []bool.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachBool(callback func(int, bool) bool) *Value {
+
+	for index, val := range v.MustBoolSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereBool uses the specified decider function to select items
+// from the []bool.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereBool(decider func(int, bool) bool) *Value {
+
+	var selected []bool
+
+	v.EachBool(func(index int, val bool) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupBool uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]bool.
+func (v *Value) GroupBool(grouper func(int, bool) string) *Value {
+
+	groups := make(map[string][]bool)
+
+	v.EachBool(func(index int, val bool) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]bool, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceBool uses the specified function to replace each bools
+// by iterating each item.  The data in the returned result will be a
+// []bool containing the replaced items.
+func (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value {
+
+	arr := v.MustBoolSlice()
+	replaced := make([]bool, len(arr))
+
+	v.EachBool(func(index int, val bool) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectBool uses the specified collector function to collect a value
+// for each of the bools in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectBool(collector func(int, bool) interface{}) *Value {
+
+	arr := v.MustBoolSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachBool(func(index int, val bool) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Str (string and []string)
+	--------------------------------------------------
+*/
+
+// Str gets the value as a string, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Str(optionalDefault ...string) string {
+	if s, ok := v.data.(string); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return ""
+}
+
+// MustStr gets the value as a string.
+//
+// Panics if the object is not a string.
+func (v *Value) MustStr() string {
+	return v.data.(string)
+}
+
+// StrSlice gets the value as a []string, returns the optionalDefault
+// value or nil if the value is not a []string.
+func (v *Value) StrSlice(optionalDefault ...[]string) []string {
+	if s, ok := v.data.([]string); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustStrSlice gets the value as a []string.
+//
+// Panics if the object is not a []string.
+func (v *Value) MustStrSlice() []string {
+	return v.data.([]string)
+}
+
+// IsStr gets whether the object contained is a string or not.
+func (v *Value) IsStr() bool {
+	_, ok := v.data.(string)
+	return ok
+}
+
+// IsStrSlice gets whether the object contained is a []string or not.
+func (v *Value) IsStrSlice() bool {
+	_, ok := v.data.([]string)
+	return ok
+}
+
+// EachStr calls the specified callback for each object
+// in the []string.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachStr(callback func(int, string) bool) *Value {
+
+	for index, val := range v.MustStrSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereStr uses the specified decider function to select items
+// from the []string.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereStr(decider func(int, string) bool) *Value {
+
+	var selected []string
+
+	v.EachStr(func(index int, val string) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupStr uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]string.
+func (v *Value) GroupStr(grouper func(int, string) string) *Value {
+
+	groups := make(map[string][]string)
+
+	v.EachStr(func(index int, val string) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]string, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceStr uses the specified function to replace each strings
+// by iterating each item.  The data in the returned result will be a
+// []string containing the replaced items.
+func (v *Value) ReplaceStr(replacer func(int, string) string) *Value {
+
+	arr := v.MustStrSlice()
+	replaced := make([]string, len(arr))
+
+	v.EachStr(func(index int, val string) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectStr uses the specified collector function to collect a value
+// for each of the strings in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectStr(collector func(int, string) interface{}) *Value {
+
+	arr := v.MustStrSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachStr(func(index int, val string) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int (int and []int)
+	--------------------------------------------------
+*/
+
+// Int gets the value as a int, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int(optionalDefault ...int) int {
+	if s, ok := v.data.(int); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt gets the value as a int.
+//
+// Panics if the object is not a int.
+func (v *Value) MustInt() int {
+	return v.data.(int)
+}
+
+// IntSlice gets the value as a []int, returns the optionalDefault
+// value or nil if the value is not a []int.
+func (v *Value) IntSlice(optionalDefault ...[]int) []int {
+	if s, ok := v.data.([]int); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustIntSlice gets the value as a []int.
+//
+// Panics if the object is not a []int.
+func (v *Value) MustIntSlice() []int {
+	return v.data.([]int)
+}
+
+// IsInt gets whether the object contained is a int or not.
+func (v *Value) IsInt() bool {
+	_, ok := v.data.(int)
+	return ok
+}
+
+// IsIntSlice gets whether the object contained is a []int or not.
+func (v *Value) IsIntSlice() bool {
+	_, ok := v.data.([]int)
+	return ok
+}
+
+// EachInt calls the specified callback for each object
+// in the []int.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt(callback func(int, int) bool) *Value {
+
+	for index, val := range v.MustIntSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt uses the specified decider function to select items
+// from the []int.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt(decider func(int, int) bool) *Value {
+
+	var selected []int
+
+	v.EachInt(func(index int, val int) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int.
+func (v *Value) GroupInt(grouper func(int, int) string) *Value {
+
+	groups := make(map[string][]int)
+
+	v.EachInt(func(index int, val int) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt uses the specified function to replace each ints
+// by iterating each item.  The data in the returned result will be a
+// []int containing the replaced items.
+func (v *Value) ReplaceInt(replacer func(int, int) int) *Value {
+
+	arr := v.MustIntSlice()
+	replaced := make([]int, len(arr))
+
+	v.EachInt(func(index int, val int) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt uses the specified collector function to collect a value
+// for each of the ints in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt(collector func(int, int) interface{}) *Value {
+
+	arr := v.MustIntSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt(func(index int, val int) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int8 (int8 and []int8)
+	--------------------------------------------------
+*/
+
+// Int8 gets the value as a int8, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int8(optionalDefault ...int8) int8 {
+	if s, ok := v.data.(int8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt8 gets the value as a int8.
+//
+// Panics if the object is not a int8.
+func (v *Value) MustInt8() int8 {
+	return v.data.(int8)
+}
+
+// Int8Slice gets the value as a []int8, returns the optionalDefault
+// value or nil if the value is not a []int8.
+func (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 {
+	if s, ok := v.data.([]int8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt8Slice gets the value as a []int8.
+//
+// Panics if the object is not a []int8.
+func (v *Value) MustInt8Slice() []int8 {
+	return v.data.([]int8)
+}
+
+// IsInt8 gets whether the object contained is a int8 or not.
+func (v *Value) IsInt8() bool {
+	_, ok := v.data.(int8)
+	return ok
+}
+
+// IsInt8Slice gets whether the object contained is a []int8 or not.
+func (v *Value) IsInt8Slice() bool {
+	_, ok := v.data.([]int8)
+	return ok
+}
+
+// EachInt8 calls the specified callback for each object
+// in the []int8.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt8(callback func(int, int8) bool) *Value {
+
+	for index, val := range v.MustInt8Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt8 uses the specified decider function to select items
+// from the []int8.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt8(decider func(int, int8) bool) *Value {
+
+	var selected []int8
+
+	v.EachInt8(func(index int, val int8) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt8 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int8.
+func (v *Value) GroupInt8(grouper func(int, int8) string) *Value {
+
+	groups := make(map[string][]int8)
+
+	v.EachInt8(func(index int, val int8) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int8, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt8 uses the specified function to replace each int8s
+// by iterating each item.  The data in the returned result will be a
+// []int8 containing the replaced items.
+func (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value {
+
+	arr := v.MustInt8Slice()
+	replaced := make([]int8, len(arr))
+
+	v.EachInt8(func(index int, val int8) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt8 uses the specified collector function to collect a value
+// for each of the int8s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value {
+
+	arr := v.MustInt8Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt8(func(index int, val int8) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int16 (int16 and []int16)
+	--------------------------------------------------
+*/
+
+// Int16 gets the value as a int16, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int16(optionalDefault ...int16) int16 {
+	if s, ok := v.data.(int16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt16 gets the value as a int16.
+//
+// Panics if the object is not a int16.
+func (v *Value) MustInt16() int16 {
+	return v.data.(int16)
+}
+
+// Int16Slice gets the value as a []int16, returns the optionalDefault
+// value or nil if the value is not a []int16.
+func (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 {
+	if s, ok := v.data.([]int16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt16Slice gets the value as a []int16.
+//
+// Panics if the object is not a []int16.
+func (v *Value) MustInt16Slice() []int16 {
+	return v.data.([]int16)
+}
+
+// IsInt16 gets whether the object contained is a int16 or not.
+func (v *Value) IsInt16() bool {
+	_, ok := v.data.(int16)
+	return ok
+}
+
+// IsInt16Slice gets whether the object contained is a []int16 or not.
+func (v *Value) IsInt16Slice() bool {
+	_, ok := v.data.([]int16)
+	return ok
+}
+
+// EachInt16 calls the specified callback for each object
+// in the []int16.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt16(callback func(int, int16) bool) *Value {
+
+	for index, val := range v.MustInt16Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt16 uses the specified decider function to select items
+// from the []int16.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt16(decider func(int, int16) bool) *Value {
+
+	var selected []int16
+
+	v.EachInt16(func(index int, val int16) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt16 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int16.
+func (v *Value) GroupInt16(grouper func(int, int16) string) *Value {
+
+	groups := make(map[string][]int16)
+
+	v.EachInt16(func(index int, val int16) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int16, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt16 uses the specified function to replace each int16s
+// by iterating each item.  The data in the returned result will be a
+// []int16 containing the replaced items.
+func (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value {
+
+	arr := v.MustInt16Slice()
+	replaced := make([]int16, len(arr))
+
+	v.EachInt16(func(index int, val int16) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt16 uses the specified collector function to collect a value
+// for each of the int16s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value {
+
+	arr := v.MustInt16Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt16(func(index int, val int16) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int32 (int32 and []int32)
+	--------------------------------------------------
+*/
+
+// Int32 gets the value as a int32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int32(optionalDefault ...int32) int32 {
+	if s, ok := v.data.(int32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt32 gets the value as a int32.
+//
+// Panics if the object is not a int32.
+func (v *Value) MustInt32() int32 {
+	return v.data.(int32)
+}
+
+// Int32Slice gets the value as a []int32, returns the optionalDefault
+// value or nil if the value is not a []int32.
+func (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 {
+	if s, ok := v.data.([]int32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt32Slice gets the value as a []int32.
+//
+// Panics if the object is not a []int32.
+func (v *Value) MustInt32Slice() []int32 {
+	return v.data.([]int32)
+}
+
+// IsInt32 gets whether the object contained is a int32 or not.
+func (v *Value) IsInt32() bool {
+	_, ok := v.data.(int32)
+	return ok
+}
+
+// IsInt32Slice gets whether the object contained is a []int32 or not.
+func (v *Value) IsInt32Slice() bool {
+	_, ok := v.data.([]int32)
+	return ok
+}
+
+// EachInt32 calls the specified callback for each object
+// in the []int32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt32(callback func(int, int32) bool) *Value {
+
+	for index, val := range v.MustInt32Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt32 uses the specified decider function to select items
+// from the []int32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt32(decider func(int, int32) bool) *Value {
+
+	var selected []int32
+
+	v.EachInt32(func(index int, val int32) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int32.
+func (v *Value) GroupInt32(grouper func(int, int32) string) *Value {
+
+	groups := make(map[string][]int32)
+
+	v.EachInt32(func(index int, val int32) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int32, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt32 uses the specified function to replace each int32s
+// by iterating each item.  The data in the returned result will be a
+// []int32 containing the replaced items.
+func (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value {
+
+	arr := v.MustInt32Slice()
+	replaced := make([]int32, len(arr))
+
+	v.EachInt32(func(index int, val int32) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt32 uses the specified collector function to collect a value
+// for each of the int32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value {
+
+	arr := v.MustInt32Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt32(func(index int, val int32) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int64 (int64 and []int64)
+	--------------------------------------------------
+*/
+
+// Int64 gets the value as a int64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int64(optionalDefault ...int64) int64 {
+	if s, ok := v.data.(int64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt64 gets the value as a int64.
+//
+// Panics if the object is not a int64.
+func (v *Value) MustInt64() int64 {
+	return v.data.(int64)
+}
+
+// Int64Slice gets the value as a []int64, returns the optionalDefault
+// value or nil if the value is not a []int64.
+func (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 {
+	if s, ok := v.data.([]int64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt64Slice gets the value as a []int64.
+//
+// Panics if the object is not a []int64.
+func (v *Value) MustInt64Slice() []int64 {
+	return v.data.([]int64)
+}
+
+// IsInt64 gets whether the object contained is a int64 or not.
+func (v *Value) IsInt64() bool {
+	_, ok := v.data.(int64)
+	return ok
+}
+
+// IsInt64Slice gets whether the object contained is a []int64 or not.
+func (v *Value) IsInt64Slice() bool {
+	_, ok := v.data.([]int64)
+	return ok
+}
+
+// EachInt64 calls the specified callback for each object
+// in the []int64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt64(callback func(int, int64) bool) *Value {
+
+	for index, val := range v.MustInt64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt64 uses the specified decider function to select items
+// from the []int64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt64(decider func(int, int64) bool) *Value {
+
+	var selected []int64
+
+	v.EachInt64(func(index int, val int64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int64.
+func (v *Value) GroupInt64(grouper func(int, int64) string) *Value {
+
+	groups := make(map[string][]int64)
+
+	v.EachInt64(func(index int, val int64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt64 uses the specified function to replace each int64s
+// by iterating each item.  The data in the returned result will be a
+// []int64 containing the replaced items.
+func (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value {
+
+	arr := v.MustInt64Slice()
+	replaced := make([]int64, len(arr))
+
+	v.EachInt64(func(index int, val int64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt64 uses the specified collector function to collect a value
+// for each of the int64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value {
+
+	arr := v.MustInt64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt64(func(index int, val int64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint (uint and []uint)
+	--------------------------------------------------
+*/
+
+// Uint gets the value as a uint, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint(optionalDefault ...uint) uint {
+	if s, ok := v.data.(uint); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint gets the value as a uint.
+//
+// Panics if the object is not a uint.
+func (v *Value) MustUint() uint {
+	return v.data.(uint)
+}
+
+// UintSlice gets the value as a []uint, returns the optionalDefault
+// value or nil if the value is not a []uint.
+func (v *Value) UintSlice(optionalDefault ...[]uint) []uint {
+	if s, ok := v.data.([]uint); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUintSlice gets the value as a []uint.
+//
+// Panics if the object is not a []uint.
+func (v *Value) MustUintSlice() []uint {
+	return v.data.([]uint)
+}
+
+// IsUint gets whether the object contained is a uint or not.
+func (v *Value) IsUint() bool {
+	_, ok := v.data.(uint)
+	return ok
+}
+
+// IsUintSlice gets whether the object contained is a []uint or not.
+func (v *Value) IsUintSlice() bool {
+	_, ok := v.data.([]uint)
+	return ok
+}
+
+// EachUint calls the specified callback for each object
+// in the []uint.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint(callback func(int, uint) bool) *Value {
+
+	for index, val := range v.MustUintSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint uses the specified decider function to select items
+// from the []uint.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint(decider func(int, uint) bool) *Value {
+
+	var selected []uint
+
+	v.EachUint(func(index int, val uint) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint.
+func (v *Value) GroupUint(grouper func(int, uint) string) *Value {
+
+	groups := make(map[string][]uint)
+
+	v.EachUint(func(index int, val uint) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint uses the specified function to replace each uints
+// by iterating each item.  The data in the returned result will be a
+// []uint containing the replaced items.
+func (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value {
+
+	arr := v.MustUintSlice()
+	replaced := make([]uint, len(arr))
+
+	v.EachUint(func(index int, val uint) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint uses the specified collector function to collect a value
+// for each of the uints in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint(collector func(int, uint) interface{}) *Value {
+
+	arr := v.MustUintSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint(func(index int, val uint) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint8 (uint8 and []uint8)
+	--------------------------------------------------
+*/
+
+// Uint8 gets the value as a uint8, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint8(optionalDefault ...uint8) uint8 {
+	if s, ok := v.data.(uint8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint8 gets the value as a uint8.
+//
+// Panics if the object is not a uint8.
+func (v *Value) MustUint8() uint8 {
+	return v.data.(uint8)
+}
+
+// Uint8Slice gets the value as a []uint8, returns the optionalDefault
+// value or nil if the value is not a []uint8.
+func (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 {
+	if s, ok := v.data.([]uint8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint8Slice gets the value as a []uint8.
+//
+// Panics if the object is not a []uint8.
+func (v *Value) MustUint8Slice() []uint8 {
+	return v.data.([]uint8)
+}
+
+// IsUint8 gets whether the object contained is a uint8 or not.
+func (v *Value) IsUint8() bool {
+	_, ok := v.data.(uint8)
+	return ok
+}
+
+// IsUint8Slice gets whether the object contained is a []uint8 or not.
+func (v *Value) IsUint8Slice() bool {
+	_, ok := v.data.([]uint8)
+	return ok
+}
+
+// EachUint8 calls the specified callback for each object
+// in the []uint8.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint8(callback func(int, uint8) bool) *Value {
+
+	for index, val := range v.MustUint8Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint8 uses the specified decider function to select items
+// from the []uint8.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint8(decider func(int, uint8) bool) *Value {
+
+	var selected []uint8
+
+	v.EachUint8(func(index int, val uint8) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint8 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint8.
+func (v *Value) GroupUint8(grouper func(int, uint8) string) *Value {
+
+	groups := make(map[string][]uint8)
+
+	v.EachUint8(func(index int, val uint8) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint8, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint8 uses the specified function to replace each uint8s
+// by iterating each item.  The data in the returned result will be a
+// []uint8 containing the replaced items.
+func (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value {
+
+	arr := v.MustUint8Slice()
+	replaced := make([]uint8, len(arr))
+
+	v.EachUint8(func(index int, val uint8) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint8 uses the specified collector function to collect a value
+// for each of the uint8s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value {
+
+	arr := v.MustUint8Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint8(func(index int, val uint8) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint16 (uint16 and []uint16)
+	--------------------------------------------------
+*/
+
+// Uint16 gets the value as a uint16, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint16(optionalDefault ...uint16) uint16 {
+	if s, ok := v.data.(uint16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint16 gets the value as a uint16.
+//
+// Panics if the object is not a uint16.
+func (v *Value) MustUint16() uint16 {
+	return v.data.(uint16)
+}
+
+// Uint16Slice gets the value as a []uint16, returns the optionalDefault
+// value or nil if the value is not a []uint16.
+func (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 {
+	if s, ok := v.data.([]uint16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint16Slice gets the value as a []uint16.
+//
+// Panics if the object is not a []uint16.
+func (v *Value) MustUint16Slice() []uint16 {
+	return v.data.([]uint16)
+}
+
+// IsUint16 gets whether the object contained is a uint16 or not.
+func (v *Value) IsUint16() bool {
+	_, ok := v.data.(uint16)
+	return ok
+}
+
+// IsUint16Slice gets whether the object contained is a []uint16 or not.
+func (v *Value) IsUint16Slice() bool {
+	_, ok := v.data.([]uint16)
+	return ok
+}
+
+// EachUint16 calls the specified callback for each object
+// in the []uint16.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint16(callback func(int, uint16) bool) *Value {
+
+	for index, val := range v.MustUint16Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint16 uses the specified decider function to select items
+// from the []uint16.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint16(decider func(int, uint16) bool) *Value {
+
+	var selected []uint16
+
+	v.EachUint16(func(index int, val uint16) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint16 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint16.
+func (v *Value) GroupUint16(grouper func(int, uint16) string) *Value {
+
+	groups := make(map[string][]uint16)
+
+	v.EachUint16(func(index int, val uint16) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint16, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint16 uses the specified function to replace each uint16s
+// by iterating each item.  The data in the returned result will be a
+// []uint16 containing the replaced items.
+func (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value {
+
+	arr := v.MustUint16Slice()
+	replaced := make([]uint16, len(arr))
+
+	v.EachUint16(func(index int, val uint16) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint16 uses the specified collector function to collect a value
+// for each of the uint16s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value {
+
+	arr := v.MustUint16Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint16(func(index int, val uint16) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint32 (uint32 and []uint32)
+	--------------------------------------------------
+*/
+
+// Uint32 gets the value as a uint32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint32(optionalDefault ...uint32) uint32 {
+	if s, ok := v.data.(uint32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint32 gets the value as a uint32.
+//
+// Panics if the object is not a uint32.
+func (v *Value) MustUint32() uint32 {
+	return v.data.(uint32)
+}
+
+// Uint32Slice gets the value as a []uint32, returns the optionalDefault
+// value or nil if the value is not a []uint32.
+func (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 {
+	if s, ok := v.data.([]uint32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint32Slice gets the value as a []uint32.
+//
+// Panics if the object is not a []uint32.
+func (v *Value) MustUint32Slice() []uint32 {
+	return v.data.([]uint32)
+}
+
+// IsUint32 gets whether the object contained is a uint32 or not.
+func (v *Value) IsUint32() bool {
+	_, ok := v.data.(uint32)
+	return ok
+}
+
+// IsUint32Slice gets whether the object contained is a []uint32 or not.
+func (v *Value) IsUint32Slice() bool {
+	_, ok := v.data.([]uint32)
+	return ok
+}
+
+// EachUint32 calls the specified callback for each object
+// in the []uint32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint32(callback func(int, uint32) bool) *Value {
+
+	for index, val := range v.MustUint32Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint32 uses the specified decider function to select items
+// from the []uint32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint32(decider func(int, uint32) bool) *Value {
+
+	var selected []uint32
+
+	v.EachUint32(func(index int, val uint32) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint32.
+func (v *Value) GroupUint32(grouper func(int, uint32) string) *Value {
+
+	groups := make(map[string][]uint32)
+
+	v.EachUint32(func(index int, val uint32) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint32, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint32 uses the specified function to replace each uint32s
+// by iterating each item.  The data in the returned result will be a
+// []uint32 containing the replaced items.
+func (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value {
+
+	arr := v.MustUint32Slice()
+	replaced := make([]uint32, len(arr))
+
+	v.EachUint32(func(index int, val uint32) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint32 uses the specified collector function to collect a value
+// for each of the uint32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value {
+
+	arr := v.MustUint32Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint32(func(index int, val uint32) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint64 (uint64 and []uint64)
+	--------------------------------------------------
+*/
+
+// Uint64 gets the value as a uint64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint64(optionalDefault ...uint64) uint64 {
+	if s, ok := v.data.(uint64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint64 gets the value as a uint64.
+//
+// Panics if the object is not a uint64.
+func (v *Value) MustUint64() uint64 {
+	return v.data.(uint64)
+}
+
+// Uint64Slice gets the value as a []uint64, returns the optionalDefault
+// value or nil if the value is not a []uint64.
+func (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 {
+	if s, ok := v.data.([]uint64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint64Slice gets the value as a []uint64.
+//
+// Panics if the object is not a []uint64.
+func (v *Value) MustUint64Slice() []uint64 {
+	return v.data.([]uint64)
+}
+
+// IsUint64 gets whether the object contained is a uint64 or not.
+func (v *Value) IsUint64() bool {
+	_, ok := v.data.(uint64)
+	return ok
+}
+
+// IsUint64Slice gets whether the object contained is a []uint64 or not.
+func (v *Value) IsUint64Slice() bool {
+	_, ok := v.data.([]uint64)
+	return ok
+}
+
+// EachUint64 calls the specified callback for each object
+// in the []uint64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint64(callback func(int, uint64) bool) *Value {
+
+	for index, val := range v.MustUint64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint64 uses the specified decider function to select items
+// from the []uint64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint64(decider func(int, uint64) bool) *Value {
+
+	var selected []uint64
+
+	v.EachUint64(func(index int, val uint64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint64.
+func (v *Value) GroupUint64(grouper func(int, uint64) string) *Value {
+
+	groups := make(map[string][]uint64)
+
+	v.EachUint64(func(index int, val uint64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint64 uses the specified function to replace each uint64s
+// by iterating each item.  The data in the returned result will be a
+// []uint64 containing the replaced items.
+func (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value {
+
+	arr := v.MustUint64Slice()
+	replaced := make([]uint64, len(arr))
+
+	v.EachUint64(func(index int, val uint64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint64 uses the specified collector function to collect a value
+// for each of the uint64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value {
+
+	arr := v.MustUint64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint64(func(index int, val uint64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uintptr (uintptr and []uintptr)
+	--------------------------------------------------
+*/
+
+// Uintptr gets the value as a uintptr, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uintptr(optionalDefault ...uintptr) uintptr {
+	if s, ok := v.data.(uintptr); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUintptr gets the value as a uintptr.
+//
+// Panics if the object is not a uintptr.
+func (v *Value) MustUintptr() uintptr {
+	return v.data.(uintptr)
+}
+
+// UintptrSlice gets the value as a []uintptr, returns the optionalDefault
+// value or nil if the value is not a []uintptr.
+func (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr {
+	if s, ok := v.data.([]uintptr); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUintptrSlice gets the value as a []uintptr.
+//
+// Panics if the object is not a []uintptr.
+func (v *Value) MustUintptrSlice() []uintptr {
+	return v.data.([]uintptr)
+}
+
+// IsUintptr gets whether the object contained is a uintptr or not.
+func (v *Value) IsUintptr() bool {
+	_, ok := v.data.(uintptr)
+	return ok
+}
+
+// IsUintptrSlice gets whether the object contained is a []uintptr or not.
+func (v *Value) IsUintptrSlice() bool {
+	_, ok := v.data.([]uintptr)
+	return ok
+}
+
+// EachUintptr calls the specified callback for each object
+// in the []uintptr.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value {
+
+	for index, val := range v.MustUintptrSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUintptr uses the specified decider function to select items
+// from the []uintptr.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value {
+
+	var selected []uintptr
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUintptr uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uintptr.
+func (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value {
+
+	groups := make(map[string][]uintptr)
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uintptr, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUintptr uses the specified function to replace each uintptrs
+// by iterating each item.  The data in the returned result will be a
+// []uintptr containing the replaced items.
+func (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value {
+
+	arr := v.MustUintptrSlice()
+	replaced := make([]uintptr, len(arr))
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUintptr uses the specified collector function to collect a value
+// for each of the uintptrs in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value {
+
+	arr := v.MustUintptrSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Float32 (float32 and []float32)
+	--------------------------------------------------
+*/
+
+// Float32 gets the value as a float32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Float32(optionalDefault ...float32) float32 {
+	if s, ok := v.data.(float32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustFloat32 gets the value as a float32.
+//
+// Panics if the object is not a float32.
+func (v *Value) MustFloat32() float32 {
+	return v.data.(float32)
+}
+
+// Float32Slice gets the value as a []float32, returns the optionalDefault
+// value or nil if the value is not a []float32.
+func (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 {
+	if s, ok := v.data.([]float32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustFloat32Slice gets the value as a []float32.
+//
+// Panics if the object is not a []float32.
+func (v *Value) MustFloat32Slice() []float32 {
+	return v.data.([]float32)
+}
+
+// IsFloat32 gets whether the object contained is a float32 or not.
+func (v *Value) IsFloat32() bool {
+	_, ok := v.data.(float32)
+	return ok
+}
+
+// IsFloat32Slice gets whether the object contained is a []float32 or not.
+func (v *Value) IsFloat32Slice() bool {
+	_, ok := v.data.([]float32)
+	return ok
+}
+
+// EachFloat32 calls the specified callback for each object
+// in the []float32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachFloat32(callback func(int, float32) bool) *Value {
+
+	for index, val := range v.MustFloat32Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereFloat32 uses the specified decider function to select items
+// from the []float32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereFloat32(decider func(int, float32) bool) *Value {
+
+	var selected []float32
+
+	v.EachFloat32(func(index int, val float32) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupFloat32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]float32.
+func (v *Value) GroupFloat32(grouper func(int, float32) string) *Value {
+
+	groups := make(map[string][]float32)
+
+	v.EachFloat32(func(index int, val float32) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]float32, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceFloat32 uses the specified function to replace each float32s
+// by iterating each item.  The data in the returned result will be a
+// []float32 containing the replaced items.
+func (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value {
+
+	arr := v.MustFloat32Slice()
+	replaced := make([]float32, len(arr))
+
+	v.EachFloat32(func(index int, val float32) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectFloat32 uses the specified collector function to collect a value
+// for each of the float32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value {
+
+	arr := v.MustFloat32Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachFloat32(func(index int, val float32) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Float64 (float64 and []float64)
+	--------------------------------------------------
+*/
+
+// Float64 gets the value as a float64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Float64(optionalDefault ...float64) float64 {
+	if s, ok := v.data.(float64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustFloat64 gets the value as a float64.
+//
+// Panics if the object is not a float64.
+func (v *Value) MustFloat64() float64 {
+	return v.data.(float64)
+}
+
+// Float64Slice gets the value as a []float64, returns the optionalDefault
+// value or nil if the value is not a []float64.
+func (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 {
+	if s, ok := v.data.([]float64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustFloat64Slice gets the value as a []float64.
+//
+// Panics if the object is not a []float64.
+func (v *Value) MustFloat64Slice() []float64 {
+	return v.data.([]float64)
+}
+
+// IsFloat64 gets whether the object contained is a float64 or not.
+func (v *Value) IsFloat64() bool {
+	_, ok := v.data.(float64)
+	return ok
+}
+
+// IsFloat64Slice gets whether the object contained is a []float64 or not.
+func (v *Value) IsFloat64Slice() bool {
+	_, ok := v.data.([]float64)
+	return ok
+}
+
+// EachFloat64 calls the specified callback for each object
+// in the []float64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachFloat64(callback func(int, float64) bool) *Value {
+
+	for index, val := range v.MustFloat64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereFloat64 uses the specified decider function to select items
+// from the []float64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereFloat64(decider func(int, float64) bool) *Value {
+
+	var selected []float64
+
+	v.EachFloat64(func(index int, val float64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupFloat64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]float64.
+func (v *Value) GroupFloat64(grouper func(int, float64) string) *Value {
+
+	groups := make(map[string][]float64)
+
+	v.EachFloat64(func(index int, val float64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]float64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceFloat64 uses the specified function to replace each float64s
+// by iterating each item.  The data in the returned result will be a
+// []float64 containing the replaced items.
+func (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value {
+
+	arr := v.MustFloat64Slice()
+	replaced := make([]float64, len(arr))
+
+	v.EachFloat64(func(index int, val float64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectFloat64 uses the specified collector function to collect a value
+// for each of the float64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value {
+
+	arr := v.MustFloat64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachFloat64(func(index int, val float64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Complex64 (complex64 and []complex64)
+	--------------------------------------------------
+*/
+
+// Complex64 gets the value as a complex64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Complex64(optionalDefault ...complex64) complex64 {
+	if s, ok := v.data.(complex64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustComplex64 gets the value as a complex64.
+//
+// Panics if the object is not a complex64.
+func (v *Value) MustComplex64() complex64 {
+	return v.data.(complex64)
+}
+
+// Complex64Slice gets the value as a []complex64, returns the optionalDefault
+// value or nil if the value is not a []complex64.
+func (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 {
+	if s, ok := v.data.([]complex64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustComplex64Slice gets the value as a []complex64.
+//
+// Panics if the object is not a []complex64.
+func (v *Value) MustComplex64Slice() []complex64 {
+	return v.data.([]complex64)
+}
+
+// IsComplex64 gets whether the object contained is a complex64 or not.
+func (v *Value) IsComplex64() bool {
+	_, ok := v.data.(complex64)
+	return ok
+}
+
+// IsComplex64Slice gets whether the object contained is a []complex64 or not.
+func (v *Value) IsComplex64Slice() bool {
+	_, ok := v.data.([]complex64)
+	return ok
+}
+
+// EachComplex64 calls the specified callback for each object
+// in the []complex64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachComplex64(callback func(int, complex64) bool) *Value {
+
+	for index, val := range v.MustComplex64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereComplex64 uses the specified decider function to select items
+// from the []complex64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value {
+
+	var selected []complex64
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupComplex64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]complex64.
+func (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value {
+
+	groups := make(map[string][]complex64)
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]complex64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceComplex64 uses the specified function to replace each complex64s
+// by iterating each item.  The data in the returned result will be a
+// []complex64 containing the replaced items.
+func (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value {
+
+	arr := v.MustComplex64Slice()
+	replaced := make([]complex64, len(arr))
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectComplex64 uses the specified collector function to collect a value
+// for each of the complex64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value {
+
+	arr := v.MustComplex64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Complex128 (complex128 and []complex128)
+	--------------------------------------------------
+*/
+
+// Complex128 gets the value as a complex128, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Complex128(optionalDefault ...complex128) complex128 {
+	if s, ok := v.data.(complex128); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustComplex128 gets the value as a complex128.
+//
+// Panics if the object is not a complex128.
+func (v *Value) MustComplex128() complex128 {
+	return v.data.(complex128)
+}
+
+// Complex128Slice gets the value as a []complex128, returns the optionalDefault
+// value or nil if the value is not a []complex128.
+func (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 {
+	if s, ok := v.data.([]complex128); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustComplex128Slice gets the value as a []complex128.
+//
+// Panics if the object is not a []complex128.
+func (v *Value) MustComplex128Slice() []complex128 {
+	return v.data.([]complex128)
+}
+
+// IsComplex128 gets whether the object contained is a complex128 or not.
+func (v *Value) IsComplex128() bool {
+	_, ok := v.data.(complex128)
+	return ok
+}
+
+// IsComplex128Slice gets whether the object contained is a []complex128 or not.
+func (v *Value) IsComplex128Slice() bool {
+	_, ok := v.data.([]complex128)
+	return ok
+}
+
+// EachComplex128 calls the specified callback for each object
+// in the []complex128.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachComplex128(callback func(int, complex128) bool) *Value {
+
+	for index, val := range v.MustComplex128Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereComplex128 uses the specified decider function to select items
+// from the []complex128.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value {
+
+	var selected []complex128
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupComplex128 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]complex128.
+func (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value {
+
+	groups := make(map[string][]complex128)
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]complex128, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceComplex128 uses the specified function to replace each complex128s
+// by iterating each item.  The data in the returned result will be a
+// []complex128 containing the replaced items.
+func (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value {
+
+	arr := v.MustComplex128Slice()
+	replaced := make([]complex128, len(arr))
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectComplex128 uses the specified collector function to collect a value
+// for each of the complex128s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value {
+
+	arr := v.MustComplex128Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}

+ 2867 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen_test.go

@@ -0,0 +1,2867 @@
+package objx
+
+import (
+	"fmt"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInter(t *testing.T) {
+
+	val := interface{}("something")
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Inter())
+	assert.Equal(t, val, New(m).Get("value").MustInter())
+	assert.Equal(t, interface{}(nil), New(m).Get("nothing").Inter())
+	assert.Equal(t, val, New(m).Get("nothing").Inter("something"))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInter()
+	})
+
+}
+
+func TestInterSlice(t *testing.T) {
+
+	val := interface{}("something")
+	m := map[string]interface{}{"value": []interface{}{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").InterSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInterSlice()[0])
+	assert.Equal(t, []interface{}(nil), New(m).Get("nothing").InterSlice())
+	assert.Equal(t, val, New(m).Get("nothing").InterSlice([]interface{}{interface{}("something")})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInterSlice()
+	})
+
+}
+
+func TestIsInter(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: interface{}("something")}
+	assert.True(t, v.IsInter())
+
+	v = &Value{data: []interface{}{interface{}("something")}}
+	assert.True(t, v.IsInterSlice())
+
+}
+
+func TestEachInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+	count := 0
+	replacedVals := make([]interface{}, 0)
+	assert.Equal(t, v, v.EachInter(func(i int, val interface{}) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInterSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInterSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInterSlice()[2])
+
+}
+
+func TestWhereInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	selected := v.WhereInter(func(i int, val interface{}) bool {
+		return i%2 == 0
+	}).MustInterSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	grouped := v.GroupInter(func(i int, val interface{}) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]interface{})
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	rawArr := v.MustInterSlice()
+
+	replaced := v.ReplaceInter(func(index int, val interface{}) interface{} {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInterSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	collected := v.CollectInter(func(index int, val interface{}) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestMSI(t *testing.T) {
+
+	val := map[string]interface{}(map[string]interface{}{"name": "Tyler"})
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").MSI())
+	assert.Equal(t, val, New(m).Get("value").MustMSI())
+	assert.Equal(t, map[string]interface{}(nil), New(m).Get("nothing").MSI())
+	assert.Equal(t, val, New(m).Get("nothing").MSI(map[string]interface{}{"name": "Tyler"}))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustMSI()
+	})
+
+}
+
+func TestMSISlice(t *testing.T) {
+
+	val := map[string]interface{}(map[string]interface{}{"name": "Tyler"})
+	m := map[string]interface{}{"value": []map[string]interface{}{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").MSISlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustMSISlice()[0])
+	assert.Equal(t, []map[string]interface{}(nil), New(m).Get("nothing").MSISlice())
+	assert.Equal(t, val, New(m).Get("nothing").MSISlice([]map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"})})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustMSISlice()
+	})
+
+}
+
+func TestIsMSI(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: map[string]interface{}(map[string]interface{}{"name": "Tyler"})}
+	assert.True(t, v.IsMSI())
+
+	v = &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+	assert.True(t, v.IsMSISlice())
+
+}
+
+func TestEachMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+	count := 0
+	replacedVals := make([]map[string]interface{}, 0)
+	assert.Equal(t, v, v.EachMSI(func(i int, val map[string]interface{}) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustMSISlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustMSISlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustMSISlice()[2])
+
+}
+
+func TestWhereMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	selected := v.WhereMSI(func(i int, val map[string]interface{}) bool {
+		return i%2 == 0
+	}).MustMSISlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	grouped := v.GroupMSI(func(i int, val map[string]interface{}) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]map[string]interface{})
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	rawArr := v.MustMSISlice()
+
+	replaced := v.ReplaceMSI(func(index int, val map[string]interface{}) map[string]interface{} {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustMSISlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	collected := v.CollectMSI(func(index int, val map[string]interface{}) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestObjxMap(t *testing.T) {
+
+	val := (Map)(New(1))
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").ObjxMap())
+	assert.Equal(t, val, New(m).Get("value").MustObjxMap())
+	assert.Equal(t, (Map)(New(nil)), New(m).Get("nothing").ObjxMap())
+	assert.Equal(t, val, New(m).Get("nothing").ObjxMap(New(1)))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustObjxMap()
+	})
+
+}
+
+func TestObjxMapSlice(t *testing.T) {
+
+	val := (Map)(New(1))
+	m := map[string]interface{}{"value": [](Map){val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").ObjxMapSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustObjxMapSlice()[0])
+	assert.Equal(t, [](Map)(nil), New(m).Get("nothing").ObjxMapSlice())
+	assert.Equal(t, val, New(m).Get("nothing").ObjxMapSlice([](Map){(Map)(New(1))})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustObjxMapSlice()
+	})
+
+}
+
+func TestIsObjxMap(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: (Map)(New(1))}
+	assert.True(t, v.IsObjxMap())
+
+	v = &Value{data: [](Map){(Map)(New(1))}}
+	assert.True(t, v.IsObjxMapSlice())
+
+}
+
+func TestEachObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+	count := 0
+	replacedVals := make([](Map), 0)
+	assert.Equal(t, v, v.EachObjxMap(func(i int, val Map) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustObjxMapSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustObjxMapSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustObjxMapSlice()[2])
+
+}
+
+func TestWhereObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	selected := v.WhereObjxMap(func(i int, val Map) bool {
+		return i%2 == 0
+	}).MustObjxMapSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	grouped := v.GroupObjxMap(func(i int, val Map) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][](Map))
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	rawArr := v.MustObjxMapSlice()
+
+	replaced := v.ReplaceObjxMap(func(index int, val Map) Map {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustObjxMapSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	collected := v.CollectObjxMap(func(index int, val Map) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestBool(t *testing.T) {
+
+	val := bool(true)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Bool())
+	assert.Equal(t, val, New(m).Get("value").MustBool())
+	assert.Equal(t, bool(false), New(m).Get("nothing").Bool())
+	assert.Equal(t, val, New(m).Get("nothing").Bool(true))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustBool()
+	})
+
+}
+
+func TestBoolSlice(t *testing.T) {
+
+	val := bool(true)
+	m := map[string]interface{}{"value": []bool{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").BoolSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustBoolSlice()[0])
+	assert.Equal(t, []bool(nil), New(m).Get("nothing").BoolSlice())
+	assert.Equal(t, val, New(m).Get("nothing").BoolSlice([]bool{bool(true)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustBoolSlice()
+	})
+
+}
+
+func TestIsBool(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: bool(true)}
+	assert.True(t, v.IsBool())
+
+	v = &Value{data: []bool{bool(true)}}
+	assert.True(t, v.IsBoolSlice())
+
+}
+
+func TestEachBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true)}}
+	count := 0
+	replacedVals := make([]bool, 0)
+	assert.Equal(t, v, v.EachBool(func(i int, val bool) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustBoolSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustBoolSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustBoolSlice()[2])
+
+}
+
+func TestWhereBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	selected := v.WhereBool(func(i int, val bool) bool {
+		return i%2 == 0
+	}).MustBoolSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	grouped := v.GroupBool(func(i int, val bool) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]bool)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	rawArr := v.MustBoolSlice()
+
+	replaced := v.ReplaceBool(func(index int, val bool) bool {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustBoolSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	collected := v.CollectBool(func(index int, val bool) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestStr(t *testing.T) {
+
+	val := string("hello")
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Str())
+	assert.Equal(t, val, New(m).Get("value").MustStr())
+	assert.Equal(t, string(""), New(m).Get("nothing").Str())
+	assert.Equal(t, val, New(m).Get("nothing").Str("hello"))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustStr()
+	})
+
+}
+
+func TestStrSlice(t *testing.T) {
+
+	val := string("hello")
+	m := map[string]interface{}{"value": []string{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").StrSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustStrSlice()[0])
+	assert.Equal(t, []string(nil), New(m).Get("nothing").StrSlice())
+	assert.Equal(t, val, New(m).Get("nothing").StrSlice([]string{string("hello")})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustStrSlice()
+	})
+
+}
+
+func TestIsStr(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: string("hello")}
+	assert.True(t, v.IsStr())
+
+	v = &Value{data: []string{string("hello")}}
+	assert.True(t, v.IsStrSlice())
+
+}
+
+func TestEachStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+	count := 0
+	replacedVals := make([]string, 0)
+	assert.Equal(t, v, v.EachStr(func(i int, val string) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustStrSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustStrSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustStrSlice()[2])
+
+}
+
+func TestWhereStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	selected := v.WhereStr(func(i int, val string) bool {
+		return i%2 == 0
+	}).MustStrSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	grouped := v.GroupStr(func(i int, val string) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]string)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	rawArr := v.MustStrSlice()
+
+	replaced := v.ReplaceStr(func(index int, val string) string {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustStrSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	collected := v.CollectStr(func(index int, val string) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt(t *testing.T) {
+
+	val := int(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int())
+	assert.Equal(t, val, New(m).Get("value").MustInt())
+	assert.Equal(t, int(0), New(m).Get("nothing").Int())
+	assert.Equal(t, val, New(m).Get("nothing").Int(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt()
+	})
+
+}
+
+func TestIntSlice(t *testing.T) {
+
+	val := int(1)
+	m := map[string]interface{}{"value": []int{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").IntSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustIntSlice()[0])
+	assert.Equal(t, []int(nil), New(m).Get("nothing").IntSlice())
+	assert.Equal(t, val, New(m).Get("nothing").IntSlice([]int{int(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustIntSlice()
+	})
+
+}
+
+func TestIsInt(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int(1)}
+	assert.True(t, v.IsInt())
+
+	v = &Value{data: []int{int(1)}}
+	assert.True(t, v.IsIntSlice())
+
+}
+
+func TestEachInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1)}}
+	count := 0
+	replacedVals := make([]int, 0)
+	assert.Equal(t, v, v.EachInt(func(i int, val int) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustIntSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustIntSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustIntSlice()[2])
+
+}
+
+func TestWhereInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	selected := v.WhereInt(func(i int, val int) bool {
+		return i%2 == 0
+	}).MustIntSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	grouped := v.GroupInt(func(i int, val int) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	rawArr := v.MustIntSlice()
+
+	replaced := v.ReplaceInt(func(index int, val int) int {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustIntSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	collected := v.CollectInt(func(index int, val int) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt8(t *testing.T) {
+
+	val := int8(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int8())
+	assert.Equal(t, val, New(m).Get("value").MustInt8())
+	assert.Equal(t, int8(0), New(m).Get("nothing").Int8())
+	assert.Equal(t, val, New(m).Get("nothing").Int8(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt8()
+	})
+
+}
+
+func TestInt8Slice(t *testing.T) {
+
+	val := int8(1)
+	m := map[string]interface{}{"value": []int8{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int8Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt8Slice()[0])
+	assert.Equal(t, []int8(nil), New(m).Get("nothing").Int8Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int8Slice([]int8{int8(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt8Slice()
+	})
+
+}
+
+func TestIsInt8(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int8(1)}
+	assert.True(t, v.IsInt8())
+
+	v = &Value{data: []int8{int8(1)}}
+	assert.True(t, v.IsInt8Slice())
+
+}
+
+func TestEachInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1)}}
+	count := 0
+	replacedVals := make([]int8, 0)
+	assert.Equal(t, v, v.EachInt8(func(i int, val int8) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt8Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt8Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt8Slice()[2])
+
+}
+
+func TestWhereInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	selected := v.WhereInt8(func(i int, val int8) bool {
+		return i%2 == 0
+	}).MustInt8Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	grouped := v.GroupInt8(func(i int, val int8) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int8)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	rawArr := v.MustInt8Slice()
+
+	replaced := v.ReplaceInt8(func(index int, val int8) int8 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt8Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	collected := v.CollectInt8(func(index int, val int8) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt16(t *testing.T) {
+
+	val := int16(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int16())
+	assert.Equal(t, val, New(m).Get("value").MustInt16())
+	assert.Equal(t, int16(0), New(m).Get("nothing").Int16())
+	assert.Equal(t, val, New(m).Get("nothing").Int16(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt16()
+	})
+
+}
+
+func TestInt16Slice(t *testing.T) {
+
+	val := int16(1)
+	m := map[string]interface{}{"value": []int16{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int16Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt16Slice()[0])
+	assert.Equal(t, []int16(nil), New(m).Get("nothing").Int16Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int16Slice([]int16{int16(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt16Slice()
+	})
+
+}
+
+func TestIsInt16(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int16(1)}
+	assert.True(t, v.IsInt16())
+
+	v = &Value{data: []int16{int16(1)}}
+	assert.True(t, v.IsInt16Slice())
+
+}
+
+func TestEachInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1)}}
+	count := 0
+	replacedVals := make([]int16, 0)
+	assert.Equal(t, v, v.EachInt16(func(i int, val int16) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt16Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt16Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt16Slice()[2])
+
+}
+
+func TestWhereInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	selected := v.WhereInt16(func(i int, val int16) bool {
+		return i%2 == 0
+	}).MustInt16Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	grouped := v.GroupInt16(func(i int, val int16) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int16)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	rawArr := v.MustInt16Slice()
+
+	replaced := v.ReplaceInt16(func(index int, val int16) int16 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt16Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	collected := v.CollectInt16(func(index int, val int16) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt32(t *testing.T) {
+
+	val := int32(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int32())
+	assert.Equal(t, val, New(m).Get("value").MustInt32())
+	assert.Equal(t, int32(0), New(m).Get("nothing").Int32())
+	assert.Equal(t, val, New(m).Get("nothing").Int32(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt32()
+	})
+
+}
+
+func TestInt32Slice(t *testing.T) {
+
+	val := int32(1)
+	m := map[string]interface{}{"value": []int32{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int32Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt32Slice()[0])
+	assert.Equal(t, []int32(nil), New(m).Get("nothing").Int32Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int32Slice([]int32{int32(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt32Slice()
+	})
+
+}
+
+func TestIsInt32(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int32(1)}
+	assert.True(t, v.IsInt32())
+
+	v = &Value{data: []int32{int32(1)}}
+	assert.True(t, v.IsInt32Slice())
+
+}
+
+func TestEachInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1)}}
+	count := 0
+	replacedVals := make([]int32, 0)
+	assert.Equal(t, v, v.EachInt32(func(i int, val int32) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt32Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt32Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt32Slice()[2])
+
+}
+
+func TestWhereInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	selected := v.WhereInt32(func(i int, val int32) bool {
+		return i%2 == 0
+	}).MustInt32Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	grouped := v.GroupInt32(func(i int, val int32) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int32)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	rawArr := v.MustInt32Slice()
+
+	replaced := v.ReplaceInt32(func(index int, val int32) int32 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt32Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	collected := v.CollectInt32(func(index int, val int32) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt64(t *testing.T) {
+
+	val := int64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int64())
+	assert.Equal(t, val, New(m).Get("value").MustInt64())
+	assert.Equal(t, int64(0), New(m).Get("nothing").Int64())
+	assert.Equal(t, val, New(m).Get("nothing").Int64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt64()
+	})
+
+}
+
+func TestInt64Slice(t *testing.T) {
+
+	val := int64(1)
+	m := map[string]interface{}{"value": []int64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt64Slice()[0])
+	assert.Equal(t, []int64(nil), New(m).Get("nothing").Int64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int64Slice([]int64{int64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt64Slice()
+	})
+
+}
+
+func TestIsInt64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int64(1)}
+	assert.True(t, v.IsInt64())
+
+	v = &Value{data: []int64{int64(1)}}
+	assert.True(t, v.IsInt64Slice())
+
+}
+
+func TestEachInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1)}}
+	count := 0
+	replacedVals := make([]int64, 0)
+	assert.Equal(t, v, v.EachInt64(func(i int, val int64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt64Slice()[2])
+
+}
+
+func TestWhereInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	selected := v.WhereInt64(func(i int, val int64) bool {
+		return i%2 == 0
+	}).MustInt64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	grouped := v.GroupInt64(func(i int, val int64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	rawArr := v.MustInt64Slice()
+
+	replaced := v.ReplaceInt64(func(index int, val int64) int64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	collected := v.CollectInt64(func(index int, val int64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint(t *testing.T) {
+
+	val := uint(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint())
+	assert.Equal(t, val, New(m).Get("value").MustUint())
+	assert.Equal(t, uint(0), New(m).Get("nothing").Uint())
+	assert.Equal(t, val, New(m).Get("nothing").Uint(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint()
+	})
+
+}
+
+func TestUintSlice(t *testing.T) {
+
+	val := uint(1)
+	m := map[string]interface{}{"value": []uint{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").UintSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUintSlice()[0])
+	assert.Equal(t, []uint(nil), New(m).Get("nothing").UintSlice())
+	assert.Equal(t, val, New(m).Get("nothing").UintSlice([]uint{uint(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUintSlice()
+	})
+
+}
+
+func TestIsUint(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint(1)}
+	assert.True(t, v.IsUint())
+
+	v = &Value{data: []uint{uint(1)}}
+	assert.True(t, v.IsUintSlice())
+
+}
+
+func TestEachUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1)}}
+	count := 0
+	replacedVals := make([]uint, 0)
+	assert.Equal(t, v, v.EachUint(func(i int, val uint) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUintSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUintSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUintSlice()[2])
+
+}
+
+func TestWhereUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	selected := v.WhereUint(func(i int, val uint) bool {
+		return i%2 == 0
+	}).MustUintSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	grouped := v.GroupUint(func(i int, val uint) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	rawArr := v.MustUintSlice()
+
+	replaced := v.ReplaceUint(func(index int, val uint) uint {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUintSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	collected := v.CollectUint(func(index int, val uint) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint8(t *testing.T) {
+
+	val := uint8(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint8())
+	assert.Equal(t, val, New(m).Get("value").MustUint8())
+	assert.Equal(t, uint8(0), New(m).Get("nothing").Uint8())
+	assert.Equal(t, val, New(m).Get("nothing").Uint8(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint8()
+	})
+
+}
+
+func TestUint8Slice(t *testing.T) {
+
+	val := uint8(1)
+	m := map[string]interface{}{"value": []uint8{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint8Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint8Slice()[0])
+	assert.Equal(t, []uint8(nil), New(m).Get("nothing").Uint8Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint8Slice([]uint8{uint8(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint8Slice()
+	})
+
+}
+
+func TestIsUint8(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint8(1)}
+	assert.True(t, v.IsUint8())
+
+	v = &Value{data: []uint8{uint8(1)}}
+	assert.True(t, v.IsUint8Slice())
+
+}
+
+func TestEachUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+	count := 0
+	replacedVals := make([]uint8, 0)
+	assert.Equal(t, v, v.EachUint8(func(i int, val uint8) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint8Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint8Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint8Slice()[2])
+
+}
+
+func TestWhereUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	selected := v.WhereUint8(func(i int, val uint8) bool {
+		return i%2 == 0
+	}).MustUint8Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	grouped := v.GroupUint8(func(i int, val uint8) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint8)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	rawArr := v.MustUint8Slice()
+
+	replaced := v.ReplaceUint8(func(index int, val uint8) uint8 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint8Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	collected := v.CollectUint8(func(index int, val uint8) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint16(t *testing.T) {
+
+	val := uint16(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint16())
+	assert.Equal(t, val, New(m).Get("value").MustUint16())
+	assert.Equal(t, uint16(0), New(m).Get("nothing").Uint16())
+	assert.Equal(t, val, New(m).Get("nothing").Uint16(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint16()
+	})
+
+}
+
+func TestUint16Slice(t *testing.T) {
+
+	val := uint16(1)
+	m := map[string]interface{}{"value": []uint16{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint16Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint16Slice()[0])
+	assert.Equal(t, []uint16(nil), New(m).Get("nothing").Uint16Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint16Slice([]uint16{uint16(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint16Slice()
+	})
+
+}
+
+func TestIsUint16(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint16(1)}
+	assert.True(t, v.IsUint16())
+
+	v = &Value{data: []uint16{uint16(1)}}
+	assert.True(t, v.IsUint16Slice())
+
+}
+
+func TestEachUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+	count := 0
+	replacedVals := make([]uint16, 0)
+	assert.Equal(t, v, v.EachUint16(func(i int, val uint16) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint16Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint16Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint16Slice()[2])
+
+}
+
+func TestWhereUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	selected := v.WhereUint16(func(i int, val uint16) bool {
+		return i%2 == 0
+	}).MustUint16Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	grouped := v.GroupUint16(func(i int, val uint16) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint16)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	rawArr := v.MustUint16Slice()
+
+	replaced := v.ReplaceUint16(func(index int, val uint16) uint16 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint16Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	collected := v.CollectUint16(func(index int, val uint16) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint32(t *testing.T) {
+
+	val := uint32(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint32())
+	assert.Equal(t, val, New(m).Get("value").MustUint32())
+	assert.Equal(t, uint32(0), New(m).Get("nothing").Uint32())
+	assert.Equal(t, val, New(m).Get("nothing").Uint32(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint32()
+	})
+
+}
+
+func TestUint32Slice(t *testing.T) {
+
+	val := uint32(1)
+	m := map[string]interface{}{"value": []uint32{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint32Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint32Slice()[0])
+	assert.Equal(t, []uint32(nil), New(m).Get("nothing").Uint32Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint32Slice([]uint32{uint32(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint32Slice()
+	})
+
+}
+
+func TestIsUint32(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint32(1)}
+	assert.True(t, v.IsUint32())
+
+	v = &Value{data: []uint32{uint32(1)}}
+	assert.True(t, v.IsUint32Slice())
+
+}
+
+func TestEachUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+	count := 0
+	replacedVals := make([]uint32, 0)
+	assert.Equal(t, v, v.EachUint32(func(i int, val uint32) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint32Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint32Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint32Slice()[2])
+
+}
+
+func TestWhereUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	selected := v.WhereUint32(func(i int, val uint32) bool {
+		return i%2 == 0
+	}).MustUint32Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	grouped := v.GroupUint32(func(i int, val uint32) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint32)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	rawArr := v.MustUint32Slice()
+
+	replaced := v.ReplaceUint32(func(index int, val uint32) uint32 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint32Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	collected := v.CollectUint32(func(index int, val uint32) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint64(t *testing.T) {
+
+	val := uint64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint64())
+	assert.Equal(t, val, New(m).Get("value").MustUint64())
+	assert.Equal(t, uint64(0), New(m).Get("nothing").Uint64())
+	assert.Equal(t, val, New(m).Get("nothing").Uint64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint64()
+	})
+
+}
+
+func TestUint64Slice(t *testing.T) {
+
+	val := uint64(1)
+	m := map[string]interface{}{"value": []uint64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint64Slice()[0])
+	assert.Equal(t, []uint64(nil), New(m).Get("nothing").Uint64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint64Slice([]uint64{uint64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint64Slice()
+	})
+
+}
+
+func TestIsUint64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint64(1)}
+	assert.True(t, v.IsUint64())
+
+	v = &Value{data: []uint64{uint64(1)}}
+	assert.True(t, v.IsUint64Slice())
+
+}
+
+func TestEachUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+	count := 0
+	replacedVals := make([]uint64, 0)
+	assert.Equal(t, v, v.EachUint64(func(i int, val uint64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint64Slice()[2])
+
+}
+
+func TestWhereUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	selected := v.WhereUint64(func(i int, val uint64) bool {
+		return i%2 == 0
+	}).MustUint64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	grouped := v.GroupUint64(func(i int, val uint64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	rawArr := v.MustUint64Slice()
+
+	replaced := v.ReplaceUint64(func(index int, val uint64) uint64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	collected := v.CollectUint64(func(index int, val uint64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUintptr(t *testing.T) {
+
+	val := uintptr(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uintptr())
+	assert.Equal(t, val, New(m).Get("value").MustUintptr())
+	assert.Equal(t, uintptr(0), New(m).Get("nothing").Uintptr())
+	assert.Equal(t, val, New(m).Get("nothing").Uintptr(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUintptr()
+	})
+
+}
+
+func TestUintptrSlice(t *testing.T) {
+
+	val := uintptr(1)
+	m := map[string]interface{}{"value": []uintptr{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").UintptrSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUintptrSlice()[0])
+	assert.Equal(t, []uintptr(nil), New(m).Get("nothing").UintptrSlice())
+	assert.Equal(t, val, New(m).Get("nothing").UintptrSlice([]uintptr{uintptr(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUintptrSlice()
+	})
+
+}
+
+func TestIsUintptr(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uintptr(1)}
+	assert.True(t, v.IsUintptr())
+
+	v = &Value{data: []uintptr{uintptr(1)}}
+	assert.True(t, v.IsUintptrSlice())
+
+}
+
+func TestEachUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+	count := 0
+	replacedVals := make([]uintptr, 0)
+	assert.Equal(t, v, v.EachUintptr(func(i int, val uintptr) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUintptrSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUintptrSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUintptrSlice()[2])
+
+}
+
+func TestWhereUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	selected := v.WhereUintptr(func(i int, val uintptr) bool {
+		return i%2 == 0
+	}).MustUintptrSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	grouped := v.GroupUintptr(func(i int, val uintptr) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uintptr)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	rawArr := v.MustUintptrSlice()
+
+	replaced := v.ReplaceUintptr(func(index int, val uintptr) uintptr {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUintptrSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	collected := v.CollectUintptr(func(index int, val uintptr) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestFloat32(t *testing.T) {
+
+	val := float32(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float32())
+	assert.Equal(t, val, New(m).Get("value").MustFloat32())
+	assert.Equal(t, float32(0), New(m).Get("nothing").Float32())
+	assert.Equal(t, val, New(m).Get("nothing").Float32(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustFloat32()
+	})
+
+}
+
+func TestFloat32Slice(t *testing.T) {
+
+	val := float32(1)
+	m := map[string]interface{}{"value": []float32{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float32Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustFloat32Slice()[0])
+	assert.Equal(t, []float32(nil), New(m).Get("nothing").Float32Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Float32Slice([]float32{float32(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustFloat32Slice()
+	})
+
+}
+
+func TestIsFloat32(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: float32(1)}
+	assert.True(t, v.IsFloat32())
+
+	v = &Value{data: []float32{float32(1)}}
+	assert.True(t, v.IsFloat32Slice())
+
+}
+
+func TestEachFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1)}}
+	count := 0
+	replacedVals := make([]float32, 0)
+	assert.Equal(t, v, v.EachFloat32(func(i int, val float32) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustFloat32Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustFloat32Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustFloat32Slice()[2])
+
+}
+
+func TestWhereFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	selected := v.WhereFloat32(func(i int, val float32) bool {
+		return i%2 == 0
+	}).MustFloat32Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	grouped := v.GroupFloat32(func(i int, val float32) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]float32)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	rawArr := v.MustFloat32Slice()
+
+	replaced := v.ReplaceFloat32(func(index int, val float32) float32 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustFloat32Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	collected := v.CollectFloat32(func(index int, val float32) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestFloat64(t *testing.T) {
+
+	val := float64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float64())
+	assert.Equal(t, val, New(m).Get("value").MustFloat64())
+	assert.Equal(t, float64(0), New(m).Get("nothing").Float64())
+	assert.Equal(t, val, New(m).Get("nothing").Float64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustFloat64()
+	})
+
+}
+
+func TestFloat64Slice(t *testing.T) {
+
+	val := float64(1)
+	m := map[string]interface{}{"value": []float64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustFloat64Slice()[0])
+	assert.Equal(t, []float64(nil), New(m).Get("nothing").Float64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Float64Slice([]float64{float64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustFloat64Slice()
+	})
+
+}
+
+func TestIsFloat64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: float64(1)}
+	assert.True(t, v.IsFloat64())
+
+	v = &Value{data: []float64{float64(1)}}
+	assert.True(t, v.IsFloat64Slice())
+
+}
+
+func TestEachFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1)}}
+	count := 0
+	replacedVals := make([]float64, 0)
+	assert.Equal(t, v, v.EachFloat64(func(i int, val float64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustFloat64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustFloat64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustFloat64Slice()[2])
+
+}
+
+func TestWhereFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	selected := v.WhereFloat64(func(i int, val float64) bool {
+		return i%2 == 0
+	}).MustFloat64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	grouped := v.GroupFloat64(func(i int, val float64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]float64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	rawArr := v.MustFloat64Slice()
+
+	replaced := v.ReplaceFloat64(func(index int, val float64) float64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustFloat64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	collected := v.CollectFloat64(func(index int, val float64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestComplex64(t *testing.T) {
+
+	val := complex64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex64())
+	assert.Equal(t, val, New(m).Get("value").MustComplex64())
+	assert.Equal(t, complex64(0), New(m).Get("nothing").Complex64())
+	assert.Equal(t, val, New(m).Get("nothing").Complex64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustComplex64()
+	})
+
+}
+
+func TestComplex64Slice(t *testing.T) {
+
+	val := complex64(1)
+	m := map[string]interface{}{"value": []complex64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustComplex64Slice()[0])
+	assert.Equal(t, []complex64(nil), New(m).Get("nothing").Complex64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Complex64Slice([]complex64{complex64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustComplex64Slice()
+	})
+
+}
+
+func TestIsComplex64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: complex64(1)}
+	assert.True(t, v.IsComplex64())
+
+	v = &Value{data: []complex64{complex64(1)}}
+	assert.True(t, v.IsComplex64Slice())
+
+}
+
+func TestEachComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+	count := 0
+	replacedVals := make([]complex64, 0)
+	assert.Equal(t, v, v.EachComplex64(func(i int, val complex64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustComplex64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustComplex64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustComplex64Slice()[2])
+
+}
+
+func TestWhereComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	selected := v.WhereComplex64(func(i int, val complex64) bool {
+		return i%2 == 0
+	}).MustComplex64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	grouped := v.GroupComplex64(func(i int, val complex64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]complex64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	rawArr := v.MustComplex64Slice()
+
+	replaced := v.ReplaceComplex64(func(index int, val complex64) complex64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustComplex64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	collected := v.CollectComplex64(func(index int, val complex64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestComplex128(t *testing.T) {
+
+	val := complex128(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex128())
+	assert.Equal(t, val, New(m).Get("value").MustComplex128())
+	assert.Equal(t, complex128(0), New(m).Get("nothing").Complex128())
+	assert.Equal(t, val, New(m).Get("nothing").Complex128(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustComplex128()
+	})
+
+}
+
+func TestComplex128Slice(t *testing.T) {
+
+	val := complex128(1)
+	m := map[string]interface{}{"value": []complex128{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex128Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustComplex128Slice()[0])
+	assert.Equal(t, []complex128(nil), New(m).Get("nothing").Complex128Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Complex128Slice([]complex128{complex128(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustComplex128Slice()
+	})
+
+}
+
+func TestIsComplex128(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: complex128(1)}
+	assert.True(t, v.IsComplex128())
+
+	v = &Value{data: []complex128{complex128(1)}}
+	assert.True(t, v.IsComplex128Slice())
+
+}
+
+func TestEachComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+	count := 0
+	replacedVals := make([]complex128, 0)
+	assert.Equal(t, v, v.EachComplex128(func(i int, val complex128) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustComplex128Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustComplex128Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustComplex128Slice()[2])
+
+}
+
+func TestWhereComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	selected := v.WhereComplex128(func(i int, val complex128) bool {
+		return i%2 == 0
+	}).MustComplex128Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	grouped := v.GroupComplex128(func(i int, val complex128) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]complex128)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	rawArr := v.MustComplex128Slice()
+
+	replaced := v.ReplaceComplex128(func(index int, val complex128) complex128 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustComplex128Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	collected := v.CollectComplex128(func(index int, val complex128) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}

+ 13 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value.go

@@ -0,0 +1,13 @@
+package objx
+
+// Value provides methods for extracting interface{} data in various
+// types.
+type Value struct {
+	// data contains the raw data being managed by this Value
+	data interface{}
+}
+
+// Data returns the raw data contained by this Value
+func (v *Value) Data() interface{} {
+	return v.data
+}

+ 1 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value_test.go

@@ -0,0 +1 @@
+package objx

+ 853 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go

@@ -0,0 +1,853 @@
+package assert
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"math"
+	"reflect"
+	"regexp"
+	"runtime"
+	"strings"
+	"time"
+)
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Errorf(format string, args ...interface{})
+}
+
+// Comparison a custom function that returns true on success and false on failure
+type Comparison func() (success bool)
+
+/*
+	Helper functions
+*/
+
+// ObjectsAreEqual determines if two objects are considered equal.
+//
+// This function does no assertion of any kind.
+func ObjectsAreEqual(expected, actual interface{}) bool {
+
+	if expected == nil || actual == nil {
+		return expected == actual
+	}
+
+	if reflect.DeepEqual(expected, actual) {
+		return true
+	}
+
+	return false
+
+}
+
+// ObjectsAreEqualValues gets whether two objects are equal, or if their
+// values are equal.
+func ObjectsAreEqualValues(expected, actual interface{}) bool {
+	if ObjectsAreEqual(expected, actual) {
+		return true
+	}
+
+	actualType := reflect.TypeOf(actual)
+	expectedValue := reflect.ValueOf(expected)
+	if expectedValue.Type().ConvertibleTo(actualType) {
+		// Attempt comparison after type conversion
+		if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) {
+			return true
+		}
+	}
+
+	return false
+}
+
+/* CallerInfo is necessary because the assert functions use the testing object
+internally, causing it to print the file:line of the assert method, rather than where
+the problem actually occured in calling code.*/
+
+// CallerInfo returns a string containing the file and line number of the assert call
+// that failed.
+func CallerInfo() string {
+
+	file := ""
+	line := 0
+	ok := false
+
+	for i := 0; ; i++ {
+		_, file, line, ok = runtime.Caller(i)
+		if !ok {
+			return ""
+		}
+		parts := strings.Split(file, "/")
+		dir := parts[len(parts)-2]
+		file = parts[len(parts)-1]
+		if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
+			break
+		}
+	}
+
+	return fmt.Sprintf("%s:%d", file, line)
+}
+
+// getWhitespaceString returns a string that is long enough to overwrite the default
+// output from the go testing framework.
+func getWhitespaceString() string {
+
+	_, file, line, ok := runtime.Caller(1)
+	if !ok {
+		return ""
+	}
+	parts := strings.Split(file, "/")
+	file = parts[len(parts)-1]
+
+	return strings.Repeat(" ", len(fmt.Sprintf("%s:%d:      ", file, line)))
+
+}
+
+func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
+	if len(msgAndArgs) == 0 || msgAndArgs == nil {
+		return ""
+	}
+	if len(msgAndArgs) == 1 {
+		return msgAndArgs[0].(string)
+	}
+	if len(msgAndArgs) > 1 {
+		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
+	}
+	return ""
+}
+
+// Indents all lines of the message by appending a number of tabs to each line, in an output format compatible with Go's
+// test printing (see inner comment for specifics)
+func indentMessageLines(message string, tabs int) string {
+	outBuf := new(bytes.Buffer)
+
+	for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
+		if i != 0 {
+			outBuf.WriteRune('\n')
+		}
+		for ii := 0; ii < tabs; ii++ {
+			outBuf.WriteRune('\t')
+			// Bizarrely, all lines except the first need one fewer tabs prepended, so deliberately advance the counter
+			// by 1 prematurely.
+			if ii == 0 && i > 0 {
+				ii++
+			}
+		}
+		outBuf.WriteString(scanner.Text())
+	}
+
+	return outBuf.String()
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+
+	message := messageFromMsgAndArgs(msgAndArgs...)
+
+	if len(message) > 0 {
+		t.Errorf("\r%s\r\tLocation:\t%s\n"+
+			"\r\tError:%s\n"+
+			"\r\tMessages:\t%s\n\r",
+			getWhitespaceString(),
+			CallerInfo(),
+			indentMessageLines(failureMessage, 2),
+			message)
+	} else {
+		t.Errorf("\r%s\r\tLocation:\t%s\n"+
+			"\r\tError:%s\n\r",
+			getWhitespaceString(),
+			CallerInfo(),
+			indentMessageLines(failureMessage, 2))
+	}
+
+	return false
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+
+	interfaceType := reflect.TypeOf(interfaceObject).Elem()
+
+	if !reflect.TypeOf(object).Implements(interfaceType) {
+		return Fail(t, fmt.Sprintf("Object must implement %v", interfaceType), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+
+	if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
+		return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
+	}
+
+	return true
+}
+
+// Equal asserts that two objects are equal.
+//
+//    assert.Equal(t, 123, 123, "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	if !ObjectsAreEqual(expected, actual) {
+		return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
+			"        != %#v (actual)", expected, actual), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	if !ObjectsAreEqualValues(expected, actual) {
+		return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
+			"        != %#v (actual)", expected, actual), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// Exactly asserts that two objects are equal is value and type.
+//
+//    assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	aType := reflect.TypeOf(expected)
+	bType := reflect.TypeOf(actual)
+
+	if aType != bType {
+		return Fail(t, "Types expected to match exactly", "%v != %v", aType, bType)
+	}
+
+	return Equal(t, expected, actual, msgAndArgs...)
+
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    assert.NotNil(t, err, "err should be something")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+	success := true
+
+	if object == nil {
+		success = false
+	} else {
+		value := reflect.ValueOf(object)
+		kind := value.Kind()
+		if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
+			success = false
+		}
+	}
+
+	if !success {
+		Fail(t, "Expected not to be nil.", msgAndArgs...)
+	}
+
+	return success
+}
+
+// isNil checks if a specified object is nil or not, without Failing.
+func isNil(object interface{}) bool {
+	if object == nil {
+		return true
+	}
+
+	value := reflect.ValueOf(object)
+	kind := value.Kind()
+	if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
+		return true
+	}
+
+	return false
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    assert.Nil(t, err, "err should be nothing")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	if isNil(object) {
+		return true
+	}
+	return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
+}
+
+var zeros = []interface{}{
+	int(0),
+	int8(0),
+	int16(0),
+	int32(0),
+	int64(0),
+	uint(0),
+	uint8(0),
+	uint16(0),
+	uint32(0),
+	uint64(0),
+	float32(0),
+	float64(0),
+}
+
+// isEmpty gets whether the specified object is considered empty or not.
+func isEmpty(object interface{}) bool {
+
+	if object == nil {
+		return true
+	} else if object == "" {
+		return true
+	} else if object == false {
+		return true
+	}
+
+	for _, v := range zeros {
+		if object == v {
+			return true
+		}
+	}
+
+	objValue := reflect.ValueOf(object)
+
+	switch objValue.Kind() {
+	case reflect.Map:
+		fallthrough
+	case reflect.Slice, reflect.Chan:
+		{
+			return (objValue.Len() == 0)
+		}
+	case reflect.Ptr:
+		{
+			switch object.(type) {
+			case *time.Time:
+				return object.(*time.Time).IsZero()
+			default:
+				return false
+			}
+		}
+	}
+	return false
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// assert.Empty(t, obj)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+	pass := isEmpty(object)
+	if !pass {
+		Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
+	}
+
+	return pass
+
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if assert.NotEmpty(t, obj) {
+//   assert.Equal(t, "two", obj[1])
+// }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+	pass := !isEmpty(object)
+	if !pass {
+		Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
+	}
+
+	return pass
+
+}
+
+// getLen try to get length of object.
+// return (false, 0) if impossible.
+func getLen(x interface{}) (ok bool, length int) {
+	v := reflect.ValueOf(x)
+	defer func() {
+		if e := recover(); e != nil {
+			ok = false
+		}
+	}()
+	return true, v.Len()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    assert.Len(t, mySlice, 3, "The size of slice is not 3")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
+	ok, l := getLen(object)
+	if !ok {
+		return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
+	}
+
+	if l != length {
+		return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
+	}
+	return true
+}
+
+// True asserts that the specified value is true.
+//
+//    assert.True(t, myBool, "myBool should be true")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+
+	if value != true {
+		return Fail(t, "Should be true", msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// False asserts that the specified value is true.
+//
+//    assert.False(t, myBool, "myBool should be false")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+
+	if value != false {
+		return Fail(t, "Should be false", msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	if ObjectsAreEqual(expected, actual) {
+		return Fail(t, "Should not be equal", msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// containsElement try loop over the list check if the list includes the element.
+// return (false, false) if impossible.
+// return (true, false) if element was not found.
+// return (true, true) if element was found.
+func includeElement(list interface{}, element interface{}) (ok, found bool) {
+
+	listValue := reflect.ValueOf(list)
+	elementValue := reflect.ValueOf(element)
+	defer func() {
+		if e := recover(); e != nil {
+			ok = false
+			found = false
+		}
+	}()
+
+	if reflect.TypeOf(list).Kind() == reflect.String {
+		return true, strings.Contains(listValue.String(), elementValue.String())
+	}
+
+	for i := 0; i < listValue.Len(); i++ {
+		if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
+			return true, true
+		}
+	}
+	return true, false
+
+}
+
+// Contains asserts that the specified string or list(array, slice...) contains the
+// specified substring or element.
+//
+//    assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
+//    assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+
+	ok, found := includeElement(s, contains)
+	if !ok {
+		return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+	}
+	if !found {
+		return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// NotContains asserts that the specified string or list(array, slice...) does NOT contain the
+// specified substring or element.
+//
+//    assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//    assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+
+	ok, found := includeElement(s, contains)
+	if !ok {
+		return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+	}
+	if found {
+		return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
+	result := comp()
+	if !result {
+		Fail(t, "Condition failed!", msgAndArgs...)
+	}
+	return result
+}
+
+// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
+// methods, and represents a simple func that takes no arguments, and returns nothing.
+type PanicTestFunc func()
+
+// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
+func didPanic(f PanicTestFunc) (bool, interface{}) {
+
+	didPanic := false
+	var message interface{}
+	func() {
+
+		defer func() {
+			if message = recover(); message != nil {
+				didPanic = true
+			}
+		}()
+
+		// call the target function
+		f()
+
+	}()
+
+	return didPanic, message
+
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panics(t, func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+
+	if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanics(t, func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+
+	if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+	}
+
+	return true
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+
+	dt := expected.Sub(actual)
+	if dt < -delta || dt > delta {
+		return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+	}
+
+	return true
+}
+
+func toFloat(x interface{}) (float64, bool) {
+	var xf float64
+	xok := true
+
+	switch xn := x.(type) {
+	case uint8:
+		xf = float64(xn)
+	case uint16:
+		xf = float64(xn)
+	case uint32:
+		xf = float64(xn)
+	case uint64:
+		xf = float64(xn)
+	case int:
+		xf = float64(xn)
+	case int8:
+		xf = float64(xn)
+	case int16:
+		xf = float64(xn)
+	case int32:
+		xf = float64(xn)
+	case int64:
+		xf = float64(xn)
+	case float32:
+		xf = float64(xn)
+	case float64:
+		xf = float64(xn)
+	default:
+		xok = false
+	}
+
+	return xf, xok
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+
+	af, aok := toFloat(expected)
+	bf, bok := toFloat(actual)
+
+	if !aok || !bok {
+		return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
+	}
+
+	if math.IsNaN(af) {
+		return Fail(t, fmt.Sprintf("Actual must not be NaN"), msgAndArgs...)
+	}
+
+	if math.IsNaN(bf) {
+		return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
+	}
+
+	dt := af - bf
+	if dt < -delta || dt > delta {
+		return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+	}
+
+	return true
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if expected == nil || actual == nil ||
+		reflect.TypeOf(actual).Kind() != reflect.Slice ||
+		reflect.TypeOf(expected).Kind() != reflect.Slice {
+		return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+	}
+
+	actualSlice := reflect.ValueOf(actual)
+	expectedSlice := reflect.ValueOf(expected)
+
+	for i := 0; i < actualSlice.Len(); i++ {
+		result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
+		if !result {
+			return result
+		}
+	}
+
+	return true
+}
+
+// min(|expected|, |actual|) * epsilon
+func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 {
+	af, aok := toFloat(expected)
+	bf, bok := toFloat(actual)
+
+	if !aok || !bok {
+		// invalid input
+		return 0
+	}
+
+	if af < 0 {
+		af = -af
+	}
+	if bf < 0 {
+		bf = -bf
+	}
+	var delta float64
+	if af < bf {
+		delta = af * epsilon
+	} else {
+		delta = bf * epsilon
+	}
+	return delta
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+//
+// Returns whether the assertion was successful (true) or not (false).
+func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	delta := calcEpsilonDelta(expected, actual, epsilon)
+
+	return InDelta(t, expected, actual, delta, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
+func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if expected == nil || actual == nil ||
+		reflect.TypeOf(actual).Kind() != reflect.Slice ||
+		reflect.TypeOf(expected).Kind() != reflect.Slice {
+		return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+	}
+
+	actualSlice := reflect.ValueOf(actual)
+	expectedSlice := reflect.ValueOf(expected)
+
+	for i := 0; i < actualSlice.Len(); i++ {
+		result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
+		if !result {
+			return result
+		}
+	}
+
+	return true
+}
+
+/*
+	Errors
+*/
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(t, err) {
+//	   assert.Equal(t, actualObj, expectedObj)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
+	if isNil(err) {
+		return true
+	}
+
+	return Fail(t, fmt.Sprintf("No error is expected but got %v", err), msgAndArgs...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//	   assert.Equal(t, err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
+
+	message := messageFromMsgAndArgs(msgAndArgs...)
+	return NotNil(t, err, "An error is expected but got nil. %s", message)
+
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//	   assert.Equal(t, err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
+
+	message := messageFromMsgAndArgs(msgAndArgs...)
+	if !NotNil(t, theError, "An error is expected but got nil. %s", message) {
+		return false
+	}
+	s := "An error with value \"%s\" is expected but got \"%s\". %s"
+	return Equal(t, theError.Error(), errString,
+		s, errString, theError.Error(), message)
+}
+
+// matchRegexp return true if a specified regexp matches a string.
+func matchRegexp(rx interface{}, str interface{}) bool {
+
+	var r *regexp.Regexp
+	if rr, ok := rx.(*regexp.Regexp); ok {
+		r = rr
+	} else {
+		r = regexp.MustCompile(fmt.Sprint(rx))
+	}
+
+	return (r.FindStringIndex(fmt.Sprint(str)) != nil)
+
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+
+	match := matchRegexp(rx, str)
+
+	if !match {
+		Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
+	}
+
+	return match
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	match := matchRegexp(rx, str)
+
+	if match {
+		Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
+	}
+
+	return !match
+
+}

+ 791 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions_test.go

@@ -0,0 +1,791 @@
+package assert
+
+import (
+	"errors"
+	"math"
+	"regexp"
+	"testing"
+	"time"
+)
+
+// AssertionTesterInterface defines an interface to be used for testing assertion methods
+type AssertionTesterInterface interface {
+	TestMethod()
+}
+
+// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface
+type AssertionTesterConformingObject struct {
+}
+
+func (a *AssertionTesterConformingObject) TestMethod() {
+}
+
+// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface
+type AssertionTesterNonConformingObject struct {
+}
+
+func TestObjectsAreEqual(t *testing.T) {
+
+	if !ObjectsAreEqual("Hello World", "Hello World") {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual(123, 123) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual(123.5, 123.5) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual([]byte("Hello World"), []byte("Hello World")) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual(nil, nil) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if ObjectsAreEqual(map[int]int{5: 10}, map[int]int{10: 20}) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual('x', "x") {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual("x", 'x') {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual(0, 0.1) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual(0.1, 0) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual(uint32(10), int32(10)) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if !ObjectsAreEqualValues(uint32(10), int32(10)) {
+		t.Error("ObjectsAreEqualValues should return true")
+	}
+
+}
+
+func TestImplements(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
+		t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
+	}
+	if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
+		t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
+	}
+
+}
+
+func TestIsType(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+		t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
+	}
+	if IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
+		t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
+	}
+
+}
+
+func TestEqual(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Equal(mockT, "Hello World", "Hello World") {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, 123, 123) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, 123.5, 123.5) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, []byte("Hello World"), []byte("Hello World")) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, nil, nil) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, int32(123), int32(123)) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, uint64(123), uint64(123)) {
+		t.Error("Equal should return true")
+	}
+
+}
+
+func TestNotNil(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !NotNil(mockT, new(AssertionTesterConformingObject)) {
+		t.Error("NotNil should return true: object is not nil")
+	}
+	if NotNil(mockT, nil) {
+		t.Error("NotNil should return false: object is nil")
+	}
+
+}
+
+func TestNil(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Nil(mockT, nil) {
+		t.Error("Nil should return true: object is nil")
+	}
+	if Nil(mockT, new(AssertionTesterConformingObject)) {
+		t.Error("Nil should return false: object is not nil")
+	}
+
+}
+
+func TestTrue(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !True(mockT, true) {
+		t.Error("True should return true")
+	}
+	if True(mockT, false) {
+		t.Error("True should return false")
+	}
+
+}
+
+func TestFalse(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !False(mockT, false) {
+		t.Error("False should return true")
+	}
+	if False(mockT, true) {
+		t.Error("False should return false")
+	}
+
+}
+
+func TestExactly(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	a := float32(1)
+	b := float64(1)
+	c := float32(1)
+	d := float32(2)
+
+	if Exactly(mockT, a, b) {
+		t.Error("Exactly should return false")
+	}
+	if Exactly(mockT, a, d) {
+		t.Error("Exactly should return false")
+	}
+	if !Exactly(mockT, a, c) {
+		t.Error("Exactly should return true")
+	}
+
+	if Exactly(mockT, nil, a) {
+		t.Error("Exactly should return false")
+	}
+	if Exactly(mockT, a, nil) {
+		t.Error("Exactly should return false")
+	}
+
+}
+
+func TestNotEqual(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !NotEqual(mockT, "Hello World", "Hello World!") {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, 123, 1234) {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, 123.5, 123.55) {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, []byte("Hello World"), []byte("Hello World!")) {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, nil, new(AssertionTesterConformingObject)) {
+		t.Error("NotEqual should return true")
+	}
+	funcA := func() int { return 23 }
+	funcB := func() int { return 42 }
+	if !NotEqual(mockT, funcA, funcB) {
+		t.Error("NotEqual should return true")
+	}
+
+	if NotEqual(mockT, "Hello World", "Hello World") {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, 123, 123) {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, 123.5, 123.5) {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, []byte("Hello World"), []byte("Hello World")) {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+		t.Error("NotEqual should return false")
+	}
+}
+
+type A struct {
+	Name, Value string
+}
+
+func TestContains(t *testing.T) {
+
+	mockT := new(testing.T)
+	list := []string{"Foo", "Bar"}
+	complexList := []*A{
+		{"b", "c"},
+		{"d", "e"},
+		{"g", "h"},
+		{"j", "k"},
+	}
+
+	if !Contains(mockT, "Hello World", "Hello") {
+		t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
+	}
+	if Contains(mockT, "Hello World", "Salut") {
+		t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
+	}
+
+	if !Contains(mockT, list, "Bar") {
+		t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Bar\"")
+	}
+	if Contains(mockT, list, "Salut") {
+		t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
+	}
+	if !Contains(mockT, complexList, &A{"g", "h"}) {
+		t.Error("Contains should return true: complexList contains {\"g\", \"h\"}")
+	}
+	if Contains(mockT, complexList, &A{"g", "e"}) {
+		t.Error("Contains should return false: complexList contains {\"g\", \"e\"}")
+	}
+}
+
+func TestNotContains(t *testing.T) {
+
+	mockT := new(testing.T)
+	list := []string{"Foo", "Bar"}
+
+	if !NotContains(mockT, "Hello World", "Hello!") {
+		t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
+	}
+	if NotContains(mockT, "Hello World", "Hello") {
+		t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
+	}
+
+	if !NotContains(mockT, list, "Foo!") {
+		t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
+	}
+	if NotContains(mockT, list, "Foo") {
+		t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+	}
+
+}
+
+func Test_includeElement(t *testing.T) {
+
+	list1 := []string{"Foo", "Bar"}
+	list2 := []int{1, 2}
+
+	ok, found := includeElement("Hello World", "World")
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list1, "Foo")
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list1, "Bar")
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list2, 1)
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list2, 2)
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list1, "Foo!")
+	True(t, ok)
+	False(t, found)
+
+	ok, found = includeElement(list2, 3)
+	True(t, ok)
+	False(t, found)
+
+	ok, found = includeElement(list2, "1")
+	True(t, ok)
+	False(t, found)
+
+	ok, found = includeElement(1433, "1")
+	False(t, ok)
+	False(t, found)
+
+}
+
+func TestCondition(t *testing.T) {
+	mockT := new(testing.T)
+
+	if !Condition(mockT, func() bool { return true }, "Truth") {
+		t.Error("Condition should return true")
+	}
+
+	if Condition(mockT, func() bool { return false }, "Lie") {
+		t.Error("Condition should return false")
+	}
+
+}
+
+func TestDidPanic(t *testing.T) {
+
+	if funcDidPanic, _ := didPanic(func() {
+		panic("Panic!")
+	}); !funcDidPanic {
+		t.Error("didPanic should return true")
+	}
+
+	if funcDidPanic, _ := didPanic(func() {
+	}); funcDidPanic {
+		t.Error("didPanic should return false")
+	}
+
+}
+
+func TestPanics(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Panics(mockT, func() {
+		panic("Panic!")
+	}) {
+		t.Error("Panics should return true")
+	}
+
+	if Panics(mockT, func() {
+	}) {
+		t.Error("Panics should return false")
+	}
+
+}
+
+func TestNotPanics(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !NotPanics(mockT, func() {
+	}) {
+		t.Error("NotPanics should return true")
+	}
+
+	if NotPanics(mockT, func() {
+		panic("Panic!")
+	}) {
+		t.Error("NotPanics should return false")
+	}
+
+}
+
+func TestNoError(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	// start with a nil error
+	var err error
+
+	True(t, NoError(mockT, err), "NoError should return True for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+
+	False(t, NoError(mockT, err), "NoError with error should return False")
+
+}
+
+func TestError(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	// start with a nil error
+	var err error
+
+	False(t, Error(mockT, err), "Error should return False for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+
+	True(t, Error(mockT, err), "Error with error should return True")
+
+}
+
+func TestEqualError(t *testing.T) {
+	mockT := new(testing.T)
+
+	// start with a nil error
+	var err error
+	False(t, EqualError(mockT, err, ""),
+		"EqualError should return false for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+	False(t, EqualError(mockT, err, "Not some error"),
+		"EqualError should return false for different error string")
+	True(t, EqualError(mockT, err, "some error"),
+		"EqualError should return true")
+}
+
+func Test_isEmpty(t *testing.T) {
+
+	chWithValue := make(chan struct{}, 1)
+	chWithValue <- struct{}{}
+
+	True(t, isEmpty(""))
+	True(t, isEmpty(nil))
+	True(t, isEmpty([]string{}))
+	True(t, isEmpty(0))
+	True(t, isEmpty(int32(0)))
+	True(t, isEmpty(int64(0)))
+	True(t, isEmpty(false))
+	True(t, isEmpty(map[string]string{}))
+	True(t, isEmpty(new(time.Time)))
+	True(t, isEmpty(make(chan struct{})))
+	False(t, isEmpty("something"))
+	False(t, isEmpty(errors.New("something")))
+	False(t, isEmpty([]string{"something"}))
+	False(t, isEmpty(1))
+	False(t, isEmpty(true))
+	False(t, isEmpty(map[string]string{"Hello": "World"}))
+	False(t, isEmpty(chWithValue))
+
+}
+
+func TestEmpty(t *testing.T) {
+
+	mockT := new(testing.T)
+	chWithValue := make(chan struct{}, 1)
+	chWithValue <- struct{}{}
+
+	True(t, Empty(mockT, ""), "Empty string is empty")
+	True(t, Empty(mockT, nil), "Nil is empty")
+	True(t, Empty(mockT, []string{}), "Empty string array is empty")
+	True(t, Empty(mockT, 0), "Zero int value is empty")
+	True(t, Empty(mockT, false), "False value is empty")
+	True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty")
+
+	False(t, Empty(mockT, "something"), "Non Empty string is not empty")
+	False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
+	False(t, Empty(mockT, []string{"something"}), "Non empty string array is not empty")
+	False(t, Empty(mockT, 1), "Non-zero int value is not empty")
+	False(t, Empty(mockT, true), "True value is not empty")
+	False(t, Empty(mockT, chWithValue), "Channel with values is not empty")
+}
+
+func TestNotEmpty(t *testing.T) {
+
+	mockT := new(testing.T)
+	chWithValue := make(chan struct{}, 1)
+	chWithValue <- struct{}{}
+
+	False(t, NotEmpty(mockT, ""), "Empty string is empty")
+	False(t, NotEmpty(mockT, nil), "Nil is empty")
+	False(t, NotEmpty(mockT, []string{}), "Empty string array is empty")
+	False(t, NotEmpty(mockT, 0), "Zero int value is empty")
+	False(t, NotEmpty(mockT, false), "False value is empty")
+	False(t, NotEmpty(mockT, make(chan struct{})), "Channel without values is empty")
+
+	True(t, NotEmpty(mockT, "something"), "Non Empty string is not empty")
+	True(t, NotEmpty(mockT, errors.New("something")), "Non nil object is not empty")
+	True(t, NotEmpty(mockT, []string{"something"}), "Non empty string array is not empty")
+	True(t, NotEmpty(mockT, 1), "Non-zero int value is not empty")
+	True(t, NotEmpty(mockT, true), "True value is not empty")
+	True(t, NotEmpty(mockT, chWithValue), "Channel with values is not empty")
+}
+
+func Test_getLen(t *testing.T) {
+	falseCases := []interface{}{
+		nil,
+		0,
+		true,
+		false,
+		'A',
+		struct{}{},
+	}
+	for _, v := range falseCases {
+		ok, l := getLen(v)
+		False(t, ok, "Expected getLen fail to get length of %#v", v)
+		Equal(t, 0, l, "getLen should return 0 for %#v", v)
+	}
+
+	ch := make(chan int, 5)
+	ch <- 1
+	ch <- 2
+	ch <- 3
+	trueCases := []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 3},
+		{[...]int{1, 2, 3}, 3},
+		{"ABC", 3},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 3},
+		{ch, 3},
+
+		{[]int{}, 0},
+		{map[int]int{}, 0},
+		{make(chan int), 0},
+
+		{[]int(nil), 0},
+		{map[int]int(nil), 0},
+		{(chan int)(nil), 0},
+	}
+
+	for _, c := range trueCases {
+		ok, l := getLen(c.v)
+		True(t, ok, "Expected getLen success to get length of %#v", c.v)
+		Equal(t, c.l, l)
+	}
+}
+
+func TestLen(t *testing.T) {
+	mockT := new(testing.T)
+
+	False(t, Len(mockT, nil, 0), "nil does not have length")
+	False(t, Len(mockT, 0, 0), "int does not have length")
+	False(t, Len(mockT, true, 0), "true does not have length")
+	False(t, Len(mockT, false, 0), "false does not have length")
+	False(t, Len(mockT, 'A', 0), "Rune does not have length")
+	False(t, Len(mockT, struct{}{}, 0), "Struct does not have length")
+
+	ch := make(chan int, 5)
+	ch <- 1
+	ch <- 2
+	ch <- 3
+
+	cases := []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 3},
+		{[...]int{1, 2, 3}, 3},
+		{"ABC", 3},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 3},
+		{ch, 3},
+
+		{[]int{}, 0},
+		{map[int]int{}, 0},
+		{make(chan int), 0},
+
+		{[]int(nil), 0},
+		{map[int]int(nil), 0},
+		{(chan int)(nil), 0},
+	}
+
+	for _, c := range cases {
+		True(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
+	}
+
+	cases = []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 4},
+		{[...]int{1, 2, 3}, 2},
+		{"ABC", 2},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 4},
+		{ch, 2},
+
+		{[]int{}, 1},
+		{map[int]int{}, 1},
+		{make(chan int), 1},
+
+		{[]int(nil), 1},
+		{map[int]int(nil), 1},
+		{(chan int)(nil), 1},
+	}
+
+	for _, c := range cases {
+		False(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
+	}
+}
+
+func TestWithinDuration(t *testing.T) {
+
+	mockT := new(testing.T)
+	a := time.Now()
+	b := a.Add(10 * time.Second)
+
+	True(t, WithinDuration(mockT, a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
+	True(t, WithinDuration(mockT, b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
+
+	False(t, WithinDuration(mockT, a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
+	False(t, WithinDuration(mockT, b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	False(t, WithinDuration(mockT, a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
+	False(t, WithinDuration(mockT, b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	False(t, WithinDuration(mockT, a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
+	False(t, WithinDuration(mockT, b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
+}
+
+func TestInDelta(t *testing.T) {
+	mockT := new(testing.T)
+
+	True(t, InDelta(mockT, 1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
+	True(t, InDelta(mockT, 1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
+	True(t, InDelta(mockT, 1, 2, 1), "|1 - 2| <= 1")
+	False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
+	False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
+	False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail")
+	False(t, InDelta(mockT, 42, math.NaN(), 0.01), "Expected NaN for actual to fail")
+	False(t, InDelta(mockT, math.NaN(), 42, 0.01), "Expected NaN for expected to fail")
+
+	cases := []struct {
+		a, b  interface{}
+		delta float64
+	}{
+		{uint8(2), uint8(1), 1},
+		{uint16(2), uint16(1), 1},
+		{uint32(2), uint32(1), 1},
+		{uint64(2), uint64(1), 1},
+
+		{int(2), int(1), 1},
+		{int8(2), int8(1), 1},
+		{int16(2), int16(1), 1},
+		{int32(2), int32(1), 1},
+		{int64(2), int64(1), 1},
+
+		{float32(2), float32(1), 1},
+		{float64(2), float64(1), 1},
+	}
+
+	for _, tc := range cases {
+		True(t, InDelta(mockT, tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
+	}
+}
+
+func TestInDeltaSlice(t *testing.T) {
+	mockT := new(testing.T)
+
+	True(t, InDeltaSlice(mockT,
+		[]float64{1.001, 0.999},
+		[]float64{1, 1},
+		0.1), "{1.001, 0.009} is element-wise close to {1, 1} in delta=0.1")
+
+	True(t, InDeltaSlice(mockT,
+		[]float64{1, 2},
+		[]float64{0, 3},
+		1), "{1, 2} is element-wise close to {0, 3} in delta=1")
+
+	False(t, InDeltaSlice(mockT,
+		[]float64{1, 2},
+		[]float64{0, 3},
+		0.1), "{1, 2} is not element-wise close to {0, 3} in delta=0.1")
+
+	False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
+}
+
+func TestInEpsilon(t *testing.T) {
+	mockT := new(testing.T)
+
+	cases := []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), uint16(2), .001},
+		{2.1, 2.2, 0.1},
+		{2.2, 2.1, 0.1},
+		{-2.1, -2.2, 0.1},
+		{-2.2, -2.1, 0.1},
+		{uint64(100), uint8(101), 0.01},
+		{0.1, -0.1, 2},
+	}
+
+	for _, tc := range cases {
+		True(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+
+	cases = []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), int16(-2), .001},
+		{uint64(100), uint8(102), 0.01},
+		{2.1, 2.2, 0.001},
+		{2.2, 2.1, 0.001},
+		{2.1, -2.2, 1},
+		{2.1, "bla-bla", 0},
+		{0.1, -0.1, 1.99},
+	}
+
+	for _, tc := range cases {
+		False(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+
+}
+
+func TestInEpsilonSlice(t *testing.T) {
+	mockT := new(testing.T)
+
+	True(t, InEpsilonSlice(mockT,
+		[]float64{2.2, 2.0},
+		[]float64{2.1, 2.1},
+		0.06), "{2.2, 2.0} is element-wise close to {2.1, 2.1} in espilon=0.06")
+
+	False(t, InEpsilonSlice(mockT,
+		[]float64{2.2, 2.0},
+		[]float64{2.1, 2.1},
+		0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in espilon=0.04")
+
+	False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
+}
+
+func TestRegexp(t *testing.T) {
+	mockT := new(testing.T)
+
+	cases := []struct {
+		rx, str string
+	}{
+		{"^start", "start of the line"},
+		{"end$", "in the end"},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
+	}
+
+	for _, tc := range cases {
+		True(t, Regexp(mockT, tc.rx, tc.str))
+		True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+		False(t, NotRegexp(mockT, tc.rx, tc.str))
+		False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+	}
+
+	cases = []struct {
+		rx, str string
+	}{
+		{"^asdfastart", "Not the start of the line"},
+		{"end$", "in the end."},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
+	}
+
+	for _, tc := range cases {
+		False(t, Regexp(mockT, tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
+		False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+		True(t, NotRegexp(mockT, tc.rx, tc.str))
+		True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+	}
+}

+ 154 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/doc.go

@@ -0,0 +1,154 @@
+// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
+//
+// Example Usage
+//
+// The following is a complete example using assert in a standard test function:
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/assert"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      assert.Equal(t, a, b, "The two words should be the same.")
+//
+//    }
+//
+// if you assert many times, use the below:
+//
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/assert"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//      assert := assert.New(t)
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      assert.Equal(a, b, "The two words should be the same.")
+//    }
+//
+// Assertions
+//
+// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
+// All assertion functions take, as the first argument, the `*testing.T` object provided by the
+// testing framework. This allows the assertion funcs to write the failings and other details to
+// the correct place.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+//
+// Here is an overview of the assert functions:
+//
+//    assert.Equal(t, expected, actual [, message [, format-args]])
+//
+//    assert.EqualValues(t, expected, actual [, message [, format-args]])
+//
+//    assert.NotEqual(t, notExpected, actual [, message [, format-args]])
+//
+//    assert.True(t, actualBool [, message [, format-args]])
+//
+//    assert.False(t, actualBool [, message [, format-args]])
+//
+//    assert.Nil(t, actualObject [, message [, format-args]])
+//
+//    assert.NotNil(t, actualObject [, message [, format-args]])
+//
+//    assert.Empty(t, actualObject [, message [, format-args]])
+//
+//    assert.NotEmpty(t, actualObject [, message [, format-args]])
+//
+//    assert.Len(t, actualObject, expectedLength, [, message [, format-args]])
+//
+//    assert.Error(t, errorObject [, message [, format-args]])
+//
+//    assert.NoError(t, errorObject [, message [, format-args]])
+//
+//    assert.EqualError(t, theError, errString [, message [, format-args]])
+//
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
+//
+//    assert.IsType(t, expectedObject, actualObject [, message [, format-args]])
+//
+//    assert.Contains(t, stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.NotContains(t, stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.Panics(t, func(){
+//
+//	    // call code that should panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.NotPanics(t, func(){
+//
+//	    // call code that should not panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
+//
+//    assert.InDelta(t, numA, numB, delta, [, message [, format-args]])
+//
+//    assert.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
+//
+// assert package contains Assertions object. it has assertion methods.
+//
+// Here is an overview of the assert functions:
+//    assert.Equal(expected, actual [, message [, format-args]])
+//
+//    assert.EqualValues(expected, actual [, message [, format-args]])
+//
+//    assert.NotEqual(notExpected, actual [, message [, format-args]])
+//
+//    assert.True(actualBool [, message [, format-args]])
+//
+//    assert.False(actualBool [, message [, format-args]])
+//
+//    assert.Nil(actualObject [, message [, format-args]])
+//
+//    assert.NotNil(actualObject [, message [, format-args]])
+//
+//    assert.Empty(actualObject [, message [, format-args]])
+//
+//    assert.NotEmpty(actualObject [, message [, format-args]])
+//
+//    assert.Len(actualObject, expectedLength, [, message [, format-args]])
+//
+//    assert.Error(errorObject [, message [, format-args]])
+//
+//    assert.NoError(errorObject [, message [, format-args]])
+//
+//    assert.EqualError(theError, errString [, message [, format-args]])
+//
+//    assert.Implements((*MyInterface)(nil), new(MyObject) [,message [, format-args]])
+//
+//    assert.IsType(expectedObject, actualObject [, message [, format-args]])
+//
+//    assert.Contains(stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.NotContains(stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.Panics(func(){
+//
+//	    // call code that should panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.NotPanics(func(){
+//
+//	    // call code that should not panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.WithinDuration(timeA, timeB, deltaTime, [, message [, format-args]])
+//
+//    assert.InDelta(numA, numB, delta, [, message [, format-args]])
+//
+//    assert.InEpsilon(numA, numB, epsilon, [, message [, format-args]])
+package assert

+ 10 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/errors.go

@@ -0,0 +1,10 @@
+package assert
+
+import (
+	"errors"
+)
+
+// AnError is an error instance useful for testing.  If the code does not care
+// about error specifics, and only needs to return the error for example, this
+// error should be used to make the test code more readable.
+var AnError = errors.New("assert.AnError general error for testing")

+ 265 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go

@@ -0,0 +1,265 @@
+package assert
+
+import "time"
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+	t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+	return &Assertions{
+		t: t,
+	}
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
+	return Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    assert.Implements((*MyInterface)(nil), new(MyObject), "MyObject")
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	return Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	return IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// Equal asserts that two objects are equal.
+//
+//    assert.Equal(123, 123, "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Equal(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValues(uint32(123), int32(123), "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualValues(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactly asserts that two objects are equal is value and type.
+//
+//    assert.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Exactly(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    assert.NotNil(err, "err should be something")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
+	return NotNil(a.t, object, msgAndArgs...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    assert.Nil(err, "err should be nothing")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
+	return Nil(a.t, object, msgAndArgs...)
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or a
+// slice with len == 0.
+//
+// assert.Empty(obj)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
+	return Empty(a.t, object, msgAndArgs...)
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or a
+// slice with len == 0.
+//
+// if assert.NotEmpty(obj) {
+//   assert.Equal("two", obj[1])
+// }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
+	return NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    assert.Len(mySlice, 3, "The size of slice is not 3")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
+	return Len(a.t, object, length, msgAndArgs...)
+}
+
+// True asserts that the specified value is true.
+//
+//    assert.True(myBool, "myBool should be true")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
+	return True(a.t, value, msgAndArgs...)
+}
+
+// False asserts that the specified value is true.
+//
+//    assert.False(myBool, "myBool should be false")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
+	return False(a.t, value, msgAndArgs...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    assert.NotEqual(obj1, obj2, "two objects shouldn't be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// Contains asserts that the specified string contains the specified substring.
+//
+//    assert.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Contains(s, contains interface{}, msgAndArgs ...interface{}) bool {
+	return Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContains asserts that the specified string does NOT contain the specified substring.
+//
+//    assert.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interface{}) bool {
+	return NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
+	return Condition(a.t, comp, msgAndArgs...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panics(func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	return Panics(a.t, f, msgAndArgs...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanics(func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	return NotPanics(a.t, f, msgAndArgs...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+	return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	return InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(err) {
+//	   assert.Equal(actualObj, expectedObj)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NoError(theError error, msgAndArgs ...interface{}) bool {
+	return NoError(a.t, theError, msgAndArgs...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(err, "An error was expected") {
+//	   assert.Equal(err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Error(theError error, msgAndArgs ...interface{}) bool {
+	return Error(a.t, theError, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(err, "An error was expected") {
+//	   assert.Equal(err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
+	return EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	return Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	return NotRegexp(a.t, rx, str, msgAndArgs...)
+}

+ 511 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions_test.go

@@ -0,0 +1,511 @@
+package assert
+
+import (
+	"errors"
+	"regexp"
+	"testing"
+	"time"
+)
+
+func TestImplementsWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
+		t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
+	}
+	if assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
+		t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
+	}
+}
+
+func TestIsTypeWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+		t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
+	}
+	if assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
+		t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
+	}
+
+}
+
+func TestEqualWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.Equal("Hello World", "Hello World") {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal(123, 123) {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal(123.5, 123.5) {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal([]byte("Hello World"), []byte("Hello World")) {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal(nil, nil) {
+		t.Error("Equal should return true")
+	}
+}
+
+func TestEqualValuesWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.EqualValues(uint32(10), int32(10)) {
+		t.Error("EqualValues should return true")
+	}
+}
+
+func TestNotNilWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.NotNil(new(AssertionTesterConformingObject)) {
+		t.Error("NotNil should return true: object is not nil")
+	}
+	if assert.NotNil(nil) {
+		t.Error("NotNil should return false: object is nil")
+	}
+
+}
+
+func TestNilWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.Nil(nil) {
+		t.Error("Nil should return true: object is nil")
+	}
+	if assert.Nil(new(AssertionTesterConformingObject)) {
+		t.Error("Nil should return false: object is not nil")
+	}
+
+}
+
+func TestTrueWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.True(true) {
+		t.Error("True should return true")
+	}
+	if assert.True(false) {
+		t.Error("True should return false")
+	}
+
+}
+
+func TestFalseWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.False(false) {
+		t.Error("False should return true")
+	}
+	if assert.False(true) {
+		t.Error("False should return false")
+	}
+
+}
+
+func TestExactlyWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	a := float32(1)
+	b := float64(1)
+	c := float32(1)
+	d := float32(2)
+
+	if assert.Exactly(a, b) {
+		t.Error("Exactly should return false")
+	}
+	if assert.Exactly(a, d) {
+		t.Error("Exactly should return false")
+	}
+	if !assert.Exactly(a, c) {
+		t.Error("Exactly should return true")
+	}
+
+	if assert.Exactly(nil, a) {
+		t.Error("Exactly should return false")
+	}
+	if assert.Exactly(a, nil) {
+		t.Error("Exactly should return false")
+	}
+
+}
+
+func TestNotEqualWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.NotEqual("Hello World", "Hello World!") {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual(123, 1234) {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual(123.5, 123.55) {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual([]byte("Hello World"), []byte("Hello World!")) {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual(nil, new(AssertionTesterConformingObject)) {
+		t.Error("NotEqual should return true")
+	}
+}
+
+func TestContainsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+	list := []string{"Foo", "Bar"}
+
+	if !assert.Contains("Hello World", "Hello") {
+		t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
+	}
+	if assert.Contains("Hello World", "Salut") {
+		t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
+	}
+
+	if !assert.Contains(list, "Foo") {
+		t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+	}
+	if assert.Contains(list, "Salut") {
+		t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
+	}
+
+}
+
+func TestNotContainsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+	list := []string{"Foo", "Bar"}
+
+	if !assert.NotContains("Hello World", "Hello!") {
+		t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
+	}
+	if assert.NotContains("Hello World", "Hello") {
+		t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
+	}
+
+	if !assert.NotContains(list, "Foo!") {
+		t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
+	}
+	if assert.NotContains(list, "Foo") {
+		t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+	}
+
+}
+
+func TestConditionWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.Condition(func() bool { return true }, "Truth") {
+		t.Error("Condition should return true")
+	}
+
+	if assert.Condition(func() bool { return false }, "Lie") {
+		t.Error("Condition should return false")
+	}
+
+}
+
+func TestDidPanicWrapper(t *testing.T) {
+
+	if funcDidPanic, _ := didPanic(func() {
+		panic("Panic!")
+	}); !funcDidPanic {
+		t.Error("didPanic should return true")
+	}
+
+	if funcDidPanic, _ := didPanic(func() {
+	}); funcDidPanic {
+		t.Error("didPanic should return false")
+	}
+
+}
+
+func TestPanicsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.Panics(func() {
+		panic("Panic!")
+	}) {
+		t.Error("Panics should return true")
+	}
+
+	if assert.Panics(func() {
+	}) {
+		t.Error("Panics should return false")
+	}
+
+}
+
+func TestNotPanicsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.NotPanics(func() {
+	}) {
+		t.Error("NotPanics should return true")
+	}
+
+	if assert.NotPanics(func() {
+		panic("Panic!")
+	}) {
+		t.Error("NotPanics should return false")
+	}
+
+}
+
+func TestNoErrorWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	// start with a nil error
+	var err error
+
+	assert.True(mockAssert.NoError(err), "NoError should return True for nil arg")
+
+	// now set an error
+	err = errors.New("Some error")
+
+	assert.False(mockAssert.NoError(err), "NoError with error should return False")
+
+}
+
+func TestErrorWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	// start with a nil error
+	var err error
+
+	assert.False(mockAssert.Error(err), "Error should return False for nil arg")
+
+	// now set an error
+	err = errors.New("Some error")
+
+	assert.True(mockAssert.Error(err), "Error with error should return True")
+
+}
+
+func TestEqualErrorWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	// start with a nil error
+	var err error
+	assert.False(mockAssert.EqualError(err, ""),
+		"EqualError should return false for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+	assert.False(mockAssert.EqualError(err, "Not some error"),
+		"EqualError should return false for different error string")
+	assert.True(mockAssert.EqualError(err, "some error"),
+		"EqualError should return true")
+}
+
+func TestEmptyWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.True(mockAssert.Empty(""), "Empty string is empty")
+	assert.True(mockAssert.Empty(nil), "Nil is empty")
+	assert.True(mockAssert.Empty([]string{}), "Empty string array is empty")
+	assert.True(mockAssert.Empty(0), "Zero int value is empty")
+	assert.True(mockAssert.Empty(false), "False value is empty")
+
+	assert.False(mockAssert.Empty("something"), "Non Empty string is not empty")
+	assert.False(mockAssert.Empty(errors.New("something")), "Non nil object is not empty")
+	assert.False(mockAssert.Empty([]string{"something"}), "Non empty string array is not empty")
+	assert.False(mockAssert.Empty(1), "Non-zero int value is not empty")
+	assert.False(mockAssert.Empty(true), "True value is not empty")
+
+}
+
+func TestNotEmptyWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.False(mockAssert.NotEmpty(""), "Empty string is empty")
+	assert.False(mockAssert.NotEmpty(nil), "Nil is empty")
+	assert.False(mockAssert.NotEmpty([]string{}), "Empty string array is empty")
+	assert.False(mockAssert.NotEmpty(0), "Zero int value is empty")
+	assert.False(mockAssert.NotEmpty(false), "False value is empty")
+
+	assert.True(mockAssert.NotEmpty("something"), "Non Empty string is not empty")
+	assert.True(mockAssert.NotEmpty(errors.New("something")), "Non nil object is not empty")
+	assert.True(mockAssert.NotEmpty([]string{"something"}), "Non empty string array is not empty")
+	assert.True(mockAssert.NotEmpty(1), "Non-zero int value is not empty")
+	assert.True(mockAssert.NotEmpty(true), "True value is not empty")
+
+}
+
+func TestLenWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.False(mockAssert.Len(nil, 0), "nil does not have length")
+	assert.False(mockAssert.Len(0, 0), "int does not have length")
+	assert.False(mockAssert.Len(true, 0), "true does not have length")
+	assert.False(mockAssert.Len(false, 0), "false does not have length")
+	assert.False(mockAssert.Len('A', 0), "Rune does not have length")
+	assert.False(mockAssert.Len(struct{}{}, 0), "Struct does not have length")
+
+	ch := make(chan int, 5)
+	ch <- 1
+	ch <- 2
+	ch <- 3
+
+	cases := []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 3},
+		{[...]int{1, 2, 3}, 3},
+		{"ABC", 3},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 3},
+		{ch, 3},
+
+		{[]int{}, 0},
+		{map[int]int{}, 0},
+		{make(chan int), 0},
+
+		{[]int(nil), 0},
+		{map[int]int(nil), 0},
+		{(chan int)(nil), 0},
+	}
+
+	for _, c := range cases {
+		assert.True(mockAssert.Len(c.v, c.l), "%#v have %d items", c.v, c.l)
+	}
+}
+
+func TestWithinDurationWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+	a := time.Now()
+	b := a.Add(10 * time.Second)
+
+	assert.True(mockAssert.WithinDuration(a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
+	assert.True(mockAssert.WithinDuration(b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
+
+	assert.False(mockAssert.WithinDuration(a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
+	assert.False(mockAssert.WithinDuration(b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	assert.False(mockAssert.WithinDuration(a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
+	assert.False(mockAssert.WithinDuration(b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	assert.False(mockAssert.WithinDuration(a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
+	assert.False(mockAssert.WithinDuration(b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
+}
+
+func TestInDeltaWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	True(t, assert.InDelta(1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
+	True(t, assert.InDelta(1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
+	True(t, assert.InDelta(1, 2, 1), "|1 - 2| <= 1")
+	False(t, assert.InDelta(1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
+	False(t, assert.InDelta(2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
+	False(t, assert.InDelta("", nil, 1), "Expected non numerals to fail")
+
+	cases := []struct {
+		a, b  interface{}
+		delta float64
+	}{
+		{uint8(2), uint8(1), 1},
+		{uint16(2), uint16(1), 1},
+		{uint32(2), uint32(1), 1},
+		{uint64(2), uint64(1), 1},
+
+		{int(2), int(1), 1},
+		{int8(2), int8(1), 1},
+		{int16(2), int16(1), 1},
+		{int32(2), int32(1), 1},
+		{int64(2), int64(1), 1},
+
+		{float32(2), float32(1), 1},
+		{float64(2), float64(1), 1},
+	}
+
+	for _, tc := range cases {
+		True(t, assert.InDelta(tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
+	}
+}
+
+func TestInEpsilonWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	cases := []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), uint16(2), .001},
+		{2.1, 2.2, 0.1},
+		{2.2, 2.1, 0.1},
+		{-2.1, -2.2, 0.1},
+		{-2.2, -2.1, 0.1},
+		{uint64(100), uint8(101), 0.01},
+		{0.1, -0.1, 2},
+	}
+
+	for _, tc := range cases {
+		True(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+
+	cases = []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), int16(-2), .001},
+		{uint64(100), uint8(102), 0.01},
+		{2.1, 2.2, 0.001},
+		{2.2, 2.1, 0.001},
+		{2.1, -2.2, 1},
+		{2.1, "bla-bla", 0},
+		{0.1, -0.1, 1.99},
+	}
+
+	for _, tc := range cases {
+		False(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+}
+
+func TestRegexpWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	cases := []struct {
+		rx, str string
+	}{
+		{"^start", "start of the line"},
+		{"end$", "in the end"},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
+	}
+
+	for _, tc := range cases {
+		True(t, assert.Regexp(tc.rx, tc.str))
+		True(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
+		False(t, assert.NotRegexp(tc.rx, tc.str))
+		False(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
+	}
+
+	cases = []struct {
+		rx, str string
+	}{
+		{"^asdfastart", "Not the start of the line"},
+		{"end$", "in the end."},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
+	}
+
+	for _, tc := range cases {
+		False(t, assert.Regexp(tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
+		False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
+		True(t, assert.NotRegexp(tc.rx, tc.str))
+		True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
+	}
+}

+ 157 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go

@@ -0,0 +1,157 @@
+package assert
+
+import (
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"strings"
+)
+
+// httpCode is a helper that returns HTTP code of the response. It returns -1
+// if building a new request fails.
+func httpCode(handler http.HandlerFunc, mode, url string, values url.Values) int {
+	w := httptest.NewRecorder()
+	req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
+	if err != nil {
+		return -1
+	}
+	handler(w, req)
+	return w.Code
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	code := httpCode(handler, mode, url, values)
+	if code == -1 {
+		return false
+	}
+	return code >= http.StatusOK && code <= http.StatusPartialContent
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	code := httpCode(handler, mode, url, values)
+	if code == -1 {
+		return false
+	}
+	return code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	code := httpCode(handler, mode, url, values)
+	if code == -1 {
+		return false
+	}
+	return code >= http.StatusBadRequest
+}
+
+// HTTPBody is a helper that returns HTTP body of the response. It returns
+// empty string if building a new request fails.
+func HTTPBody(handler http.HandlerFunc, mode, url string, values url.Values) string {
+	w := httptest.NewRecorder()
+	req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
+	if err != nil {
+		return ""
+	}
+	handler(w, req)
+	return w.Body.String()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	body := HTTPBody(handler, mode, url, values)
+
+	contains := strings.Contains(body, fmt.Sprint(str))
+	if !contains {
+		Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
+	}
+
+	return contains
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	body := HTTPBody(handler, mode, url, values)
+
+	contains := strings.Contains(body, fmt.Sprint(str))
+	if contains {
+		Fail(t, "Expected response body for %s to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)
+	}
+
+	return !contains
+}
+
+//
+// Assertions Wrappers
+//
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	return HTTPSuccess(a.t, handler, mode, url, values)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	return HTTPRedirect(a.t, handler, mode, url, values)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	return HTTPError(a.t, handler, mode, url, values)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	return HTTPBodyContains(a.t, handler, mode, url, values, str)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	return HTTPBodyNotContains(a.t, handler, mode, url, values, str)
+}

+ 86 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions_test.go

@@ -0,0 +1,86 @@
+package assert
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"testing"
+)
+
+func httpOK(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusOK)
+}
+
+func httpRedirect(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusTemporaryRedirect)
+}
+
+func httpError(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusInternalServerError)
+}
+
+func TestHTTPStatuses(t *testing.T) {
+	assert := New(t)
+	mockT := new(testing.T)
+
+	assert.Equal(HTTPSuccess(mockT, httpOK, "GET", "/", nil), true)
+	assert.Equal(HTTPSuccess(mockT, httpRedirect, "GET", "/", nil), false)
+	assert.Equal(HTTPSuccess(mockT, httpError, "GET", "/", nil), false)
+
+	assert.Equal(HTTPRedirect(mockT, httpOK, "GET", "/", nil), false)
+	assert.Equal(HTTPRedirect(mockT, httpRedirect, "GET", "/", nil), true)
+	assert.Equal(HTTPRedirect(mockT, httpError, "GET", "/", nil), false)
+
+	assert.Equal(HTTPError(mockT, httpOK, "GET", "/", nil), false)
+	assert.Equal(HTTPError(mockT, httpRedirect, "GET", "/", nil), false)
+	assert.Equal(HTTPError(mockT, httpError, "GET", "/", nil), true)
+}
+
+func TestHTTPStatusesWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.Equal(mockAssert.HTTPSuccess(httpOK, "GET", "/", nil), true)
+	assert.Equal(mockAssert.HTTPSuccess(httpRedirect, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPSuccess(httpError, "GET", "/", nil), false)
+
+	assert.Equal(mockAssert.HTTPRedirect(httpOK, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPRedirect(httpRedirect, "GET", "/", nil), true)
+	assert.Equal(mockAssert.HTTPRedirect(httpError, "GET", "/", nil), false)
+
+	assert.Equal(mockAssert.HTTPError(httpOK, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPError(httpRedirect, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPError(httpError, "GET", "/", nil), true)
+}
+
+func httpHelloName(w http.ResponseWriter, r *http.Request) {
+	name := r.FormValue("name")
+	w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
+}
+
+func TestHttpBody(t *testing.T) {
+	assert := New(t)
+	mockT := new(testing.T)
+
+	assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+	assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+}
+
+func TestHttpBodyWrappers(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.False(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+	assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+}

+ 43 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go

@@ -0,0 +1,43 @@
+// Provides a system by which it is possible to mock your objects and verify calls are happening as expected.
+//
+// Example Usage
+//
+// The mock package provides an object, Mock, that tracks activity on another object.  It is usually
+// embedded into a test object as shown below:
+//
+//   type MyTestObject struct {
+//     // add a Mock object instance
+//     mock.Mock
+//
+//     // other fields go here as normal
+//   }
+//
+// When implementing the methods of an interface, you wire your functions up
+// to call the Mock.Called(args...) method, and return the appropriate values.
+//
+// For example, to mock a method that saves the name and age of a person and returns
+// the year of their birth or an error, you might write this:
+//
+//     func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
+//       args := o.Called(firstname, lastname, age)
+//       return args.Int(0), args.Error(1)
+//     }
+//
+// The Int, Error and Bool methods are examples of strongly typed getters that take the argument
+// index position. Given this argument list:
+//
+//     (12, true, "Something")
+//
+// You could read them out strongly typed like this:
+//
+//     args.Int(0)
+//     args.Bool(1)
+//     args.String(2)
+//
+// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
+//
+//     return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
+//
+// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
+// cases you should check for nil first.
+package mock

+ 566 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go

@@ -0,0 +1,566 @@
+package mock
+
+import (
+	"fmt"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/objx"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"reflect"
+	"runtime"
+	"strings"
+	"sync"
+	"time"
+)
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Logf(format string, args ...interface{})
+	Errorf(format string, args ...interface{})
+}
+
+/*
+	Call
+*/
+
+// Call represents a method call and is used for setting expectations,
+// as well as recording activity.
+type Call struct {
+
+	// The name of the method that was or will be called.
+	Method string
+
+	// Holds the arguments of the method.
+	Arguments Arguments
+
+	// Holds the arguments that should be returned when
+	// this method is called.
+	ReturnArguments Arguments
+
+	// The number of times to return the return arguments when setting
+	// expectations. 0 means to always return the value.
+	Repeatability int
+
+	// Holds a channel that will be used to block the Return until it either
+	// recieves a message or is closed. nil means it returns immediately.
+	WaitFor <-chan time.Time
+
+	// Holds a handler used to manipulate arguments content that are passed by
+	// reference. It's useful when mocking methods such as unmarshalers or
+	// decoders.
+	Run func(Arguments)
+}
+
+// Mock is the workhorse used to track activity on another object.
+// For an example of its usage, refer to the "Example Usage" section at the top of this document.
+type Mock struct {
+
+	// The method name that is currently
+	// being referred to by the On method.
+	onMethodName string
+
+	// An array of the arguments that are
+	// currently being referred to by the On method.
+	onMethodArguments Arguments
+
+	// Represents the calls that are expected of
+	// an object.
+	ExpectedCalls []Call
+
+	// Holds the calls that were made to this mocked object.
+	Calls []Call
+
+	// TestData holds any data that might be useful for testing.  Testify ignores
+	// this data completely allowing you to do whatever you like with it.
+	testData objx.Map
+
+	mutex sync.Mutex
+}
+
+// TestData holds any data that might be useful for testing.  Testify ignores
+// this data completely allowing you to do whatever you like with it.
+func (m *Mock) TestData() objx.Map {
+
+	if m.testData == nil {
+		m.testData = make(objx.Map)
+	}
+
+	return m.testData
+}
+
+/*
+	Setting expectations
+*/
+
+// On starts a description of an expectation of the specified method
+// being called.
+//
+//     Mock.On("MyMethod", arg1, arg2)
+func (m *Mock) On(methodName string, arguments ...interface{}) *Mock {
+	m.onMethodName = methodName
+	m.onMethodArguments = arguments
+
+	for _, arg := range arguments {
+		if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
+			panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg))
+		}
+	}
+
+	return m
+}
+
+// Return finishes a description of an expectation of the method (and arguments)
+// specified in the most recent On method call.
+//
+//     Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2)
+func (m *Mock) Return(returnArguments ...interface{}) *Mock {
+	m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0, nil, nil})
+	return m
+}
+
+// Once indicates that that the mock should only return the value once.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
+func (m *Mock) Once() {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1
+}
+
+// Twice indicates that that the mock should only return the value twice.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
+func (m *Mock) Twice() {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2
+}
+
+// Times indicates that that the mock should only return the indicated number
+// of times.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
+func (m *Mock) Times(i int) {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i
+}
+
+// WaitUntil sets the channel that will block the mock's return until its closed
+// or a message is received.
+//
+//    Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
+func (m *Mock) WaitUntil(w <-chan time.Time) *Mock {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].WaitFor = w
+	return m
+}
+
+// After sets how long to block until the call returns
+//
+//    Mock.On("MyMethod", arg1, arg2).After(time.Second)
+func (m *Mock) After(d time.Duration) *Mock {
+	return m.WaitUntil(time.After(d))
+}
+
+// Run sets a handler to be called before returning. It can be used when
+// mocking a method such as unmarshalers that takes a pointer to a struct and
+// sets properties in such struct
+//
+//    Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(function(args Arguments) {
+//    	arg := args.Get(0).(*map[string]interface{})
+//    	arg["foo"] = "bar"
+//    })
+func (m *Mock) Run(fn func(Arguments)) *Mock {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Run = fn
+	return m
+}
+
+/*
+	Recording and responding to activity
+*/
+
+func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
+	for i, call := range m.ExpectedCalls {
+		if call.Method == method && call.Repeatability > -1 {
+
+			_, diffCount := call.Arguments.Diff(arguments)
+			if diffCount == 0 {
+				return i, &call
+			}
+
+		}
+	}
+	return -1, nil
+}
+
+func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {
+
+	diffCount := 0
+	var closestCall *Call = nil
+
+	for _, call := range m.ExpectedCalls {
+		if call.Method == method {
+
+			_, tempDiffCount := call.Arguments.Diff(arguments)
+			if tempDiffCount < diffCount || diffCount == 0 {
+				diffCount = tempDiffCount
+				closestCall = &call
+			}
+
+		}
+	}
+
+	if closestCall == nil {
+		return false, nil
+	}
+
+	return true, closestCall
+}
+
+func callString(method string, arguments Arguments, includeArgumentValues bool) string {
+
+	var argValsString string = ""
+	if includeArgumentValues {
+		var argVals []string
+		for argIndex, arg := range arguments {
+			argVals = append(argVals, fmt.Sprintf("%d: %v", argIndex, arg))
+		}
+		argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
+	}
+
+	return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString)
+}
+
+// Called tells the mock object that a method has been called, and gets an array
+// of arguments to return.  Panics if the call is unexpected (i.e. not preceeded by
+// appropriate .On .Return() calls)
+// If Call.WaitFor is set, blocks until the channel is closed or receives a message.
+func (m *Mock) Called(arguments ...interface{}) Arguments {
+	defer m.mutex.Unlock()
+	m.mutex.Lock()
+
+	// get the calling function's name
+	pc, _, _, ok := runtime.Caller(1)
+	if !ok {
+		panic("Couldn't get the caller information")
+	}
+	functionPath := runtime.FuncForPC(pc).Name()
+	parts := strings.Split(functionPath, ".")
+	functionName := parts[len(parts)-1]
+
+	found, call := m.findExpectedCall(functionName, arguments...)
+
+	switch {
+	case found < 0:
+		// we have to fail here - because we don't know what to do
+		// as the return arguments.  This is because:
+		//
+		//   a) this is a totally unexpected call to this method,
+		//   b) the arguments are not what was expected, or
+		//   c) the developer has forgotten to add an accompanying On...Return pair.
+
+		closestFound, closestCall := m.findClosestCall(functionName, arguments...)
+
+		if closestFound {
+			panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n", callString(functionName, arguments, true), callString(functionName, closestCall.Arguments, true)))
+		} else {
+			panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo()))
+		}
+	case call.Repeatability == 1:
+		call.Repeatability = -1
+		m.ExpectedCalls[found] = *call
+	case call.Repeatability > 1:
+		call.Repeatability -= 1
+		m.ExpectedCalls[found] = *call
+	}
+
+	// add the call
+	m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0, nil, nil})
+
+	// block if specified
+	if call.WaitFor != nil {
+		<-call.WaitFor
+	}
+
+	if call.Run != nil {
+		call.Run(arguments)
+	}
+
+	return call.ReturnArguments
+
+}
+
+/*
+	Assertions
+*/
+
+// AssertExpectationsForObjects asserts that everything specified with On and Return
+// of the specified objects was in fact called as expected.
+//
+// Calls may have occurred in any order.
+func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
+	var success bool = true
+	for _, obj := range testObjects {
+		mockObj := obj.(Mock)
+		success = success && mockObj.AssertExpectations(t)
+	}
+	return success
+}
+
+// AssertExpectations asserts that everything specified with On and Return was
+// in fact called as expected.  Calls may have occurred in any order.
+func (m *Mock) AssertExpectations(t TestingT) bool {
+
+	var somethingMissing bool = false
+	var failedExpectations int = 0
+
+	// iterate through each expectation
+	for _, expectedCall := range m.ExpectedCalls {
+		switch {
+		case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments):
+			somethingMissing = true
+			failedExpectations++
+			t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
+		case expectedCall.Repeatability > 0:
+			somethingMissing = true
+			failedExpectations++
+		default:
+			t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
+		}
+	}
+
+	if somethingMissing {
+		t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(m.ExpectedCalls)-failedExpectations, len(m.ExpectedCalls), failedExpectations, assert.CallerInfo())
+	}
+
+	return !somethingMissing
+}
+
+// AssertNumberOfCalls asserts that the method was called expectedCalls times.
+func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
+	var actualCalls int = 0
+	for _, call := range m.Calls {
+		if call.Method == methodName {
+			actualCalls++
+		}
+	}
+	return assert.Equal(t, actualCalls, expectedCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls))
+}
+
+// AssertCalled asserts that the method was called.
+func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+	if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) {
+		t.Logf("%v", m.ExpectedCalls)
+		return false
+	}
+	return true
+}
+
+// AssertNotCalled asserts that the method was not called.
+func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+	if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) {
+		t.Logf("%v", m.ExpectedCalls)
+		return false
+	}
+	return true
+}
+
+func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
+	for _, call := range m.Calls {
+		if call.Method == methodName {
+
+			_, differences := Arguments(expected).Diff(call.Arguments)
+
+			if differences == 0 {
+				// found the expected call
+				return true
+			}
+
+		}
+	}
+	// we didn't find the expected call
+	return false
+}
+
+/*
+	Arguments
+*/
+
+// Arguments holds an array of method arguments or return values.
+type Arguments []interface{}
+
+const (
+	// The "any" argument.  Used in Diff and Assert when
+	// the argument being tested shouldn't be taken into consideration.
+	Anything string = "mock.Anything"
+)
+
+// AnythingOfTypeArgument is a string that contains the type of an argument
+// for use when type checking.  Used in Diff and Assert.
+type AnythingOfTypeArgument string
+
+// AnythingOfType returns an AnythingOfTypeArgument object containing the
+// name of the type to check for.  Used in Diff and Assert.
+//
+// For example:
+//	Assert(t, AnythingOfType("string"), AnythingOfType("int"))
+func AnythingOfType(t string) AnythingOfTypeArgument {
+	return AnythingOfTypeArgument(t)
+}
+
+// Get Returns the argument at the specified index.
+func (args Arguments) Get(index int) interface{} {
+	if index+1 > len(args) {
+		panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args)))
+	}
+	return args[index]
+}
+
+// Is gets whether the objects match the arguments specified.
+func (args Arguments) Is(objects ...interface{}) bool {
+	for i, obj := range args {
+		if obj != objects[i] {
+			return false
+		}
+	}
+	return true
+}
+
+// Diff gets a string describing the differences between the arguments
+// and the specified objects.
+//
+// Returns the diff string and number of differences found.
+func (args Arguments) Diff(objects []interface{}) (string, int) {
+
+	var output string = "\n"
+	var differences int
+
+	var maxArgCount int = len(args)
+	if len(objects) > maxArgCount {
+		maxArgCount = len(objects)
+	}
+
+	for i := 0; i < maxArgCount; i++ {
+		var actual, expected interface{}
+
+		if len(objects) <= i {
+			actual = "(Missing)"
+		} else {
+			actual = objects[i]
+		}
+
+		if len(args) <= i {
+			expected = "(Missing)"
+		} else {
+			expected = args[i]
+		}
+
+		if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
+
+			// type checking
+			if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
+				// not match
+				differences++
+				output = fmt.Sprintf("%s\t%d: \u274C  type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual)
+			}
+
+		} else {
+
+			// normal checking
+
+			if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
+				// match
+				output = fmt.Sprintf("%s\t%d: \u2705  %s == %s\n", output, i, actual, expected)
+			} else {
+				// not match
+				differences++
+				output = fmt.Sprintf("%s\t%d: \u274C  %s != %s\n", output, i, actual, expected)
+			}
+		}
+
+	}
+
+	if differences == 0 {
+		return "No differences.", differences
+	}
+
+	return output, differences
+
+}
+
+// Assert compares the arguments with the specified objects and fails if
+// they do not exactly match.
+func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
+
+	// get the differences
+	diff, diffCount := args.Diff(objects)
+
+	if diffCount == 0 {
+		return true
+	}
+
+	// there are differences... report them...
+	t.Logf(diff)
+	t.Errorf("%sArguments do not match.", assert.CallerInfo())
+
+	return false
+
+}
+
+// String gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+//
+// If no index is provided, String() returns a complete string representation
+// of the arguments.
+func (args Arguments) String(indexOrNil ...int) string {
+
+	if len(indexOrNil) == 0 {
+		// normal String() method - return a string representation of the args
+		var argsStr []string
+		for _, arg := range args {
+			argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg)))
+		}
+		return strings.Join(argsStr, ",")
+	} else if len(indexOrNil) == 1 {
+		// Index has been specified - get the argument at that index
+		var index int = indexOrNil[0]
+		var s string
+		var ok bool
+		if s, ok = args.Get(index).(string); !ok {
+			panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index)))
+		}
+		return s
+	}
+
+	panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String.  Must be 0 or 1, not %d", len(indexOrNil)))
+
+}
+
+// Int gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Int(index int) int {
+	var s int
+	var ok bool
+	if s, ok = args.Get(index).(int); !ok {
+		panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+	}
+	return s
+}
+
+// Error gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Error(index int) error {
+	obj := args.Get(index)
+	var s error
+	var ok bool
+	if obj == nil {
+		return nil
+	}
+	if s, ok = obj.(error); !ok {
+		panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+	}
+	return s
+}
+
+// Bool gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Bool(index int) bool {
+	var s bool
+	var ok bool
+	if s, ok = args.Get(index).(bool); !ok {
+		panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+	}
+	return s
+}

+ 843 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock_test.go

@@ -0,0 +1,843 @@
+package mock
+
+import (
+	"errors"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+	"time"
+)
+
+/*
+	Test objects
+*/
+
+// ExampleInterface represents an example interface.
+type ExampleInterface interface {
+	TheExampleMethod(a, b, c int) (int, error)
+}
+
+// TestExampleImplementation is a test implementation of ExampleInterface
+type TestExampleImplementation struct {
+	Mock
+}
+
+func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
+	args := i.Called(a, b, c)
+	return args.Int(0), errors.New("Whoops")
+}
+
+func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
+	i.Called(yesorno)
+}
+
+type ExampleType struct {
+	ran bool
+}
+
+func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error {
+	args := i.Called(et)
+	return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error {
+	args := i.Called(fn)
+	return args.Error(0)
+}
+
+type ExampleFuncType func(string) error
+
+func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error {
+	args := i.Called(fn)
+	return args.Error(0)
+}
+
+/*
+	Mock
+*/
+
+func Test_Mock_TestData(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	if assert.NotNil(t, mockedService.TestData()) {
+
+		mockedService.TestData().Set("something", 123)
+		assert.Equal(t, 123, mockedService.TestData().Get("something").Data())
+
+	}
+
+}
+
+func Test_Mock_On(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod"), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
+
+}
+
+func Test_Mock_On_WithArgs(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod", 1, 2, 3), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
+	assert.Equal(t, 1, mockedService.onMethodArguments[0])
+	assert.Equal(t, 2, mockedService.onMethodArguments[1])
+	assert.Equal(t, 3, mockedService.onMethodArguments[2])
+
+}
+
+func Test_Mock_On_WithFuncArg(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethodFunc", AnythingOfType("func(string) error")).Return(nil), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethodFunc", mockedService.onMethodName)
+	assert.Equal(t, AnythingOfType("func(string) error"), mockedService.onMethodArguments[0])
+
+	fn := func(string) error { return nil }
+	mockedService.TheExampleMethodFunc(fn)
+
+}
+
+func Test_Mock_On_WithFuncPanics(t *testing.T) {
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Panics(t, func() {
+		mockedService.On("TheExampleMethodFunc", func(string) error { return nil })
+	})
+}
+
+func Test_Mock_On_WithFuncTypeArg(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).Return(nil), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethodFuncType", mockedService.onMethodName)
+	assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), mockedService.onMethodArguments[0])
+
+	fn := func(string) error { return nil }
+	mockedService.TheExampleMethodFuncType(fn)
+
+}
+
+func Test_Mock_Return(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_WaitUntil(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+	ch := time.After(time.Second)
+
+	assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).WaitUntil(ch), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
+		call := mockedService.Mock.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.Equal(t, ch, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_After(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).After(time.Second), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
+		call := mockedService.Mock.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.NotEqual(t, nil, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Run(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.Mock.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Run(func(args Arguments) {
+		arg := args.Get(0).(*ExampleType)
+		arg.ran = true
+	}), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
+		call := mockedService.Mock.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod3", call.Method)
+		assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0])
+		assert.Equal(t, nil, call.ReturnArguments[0])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.NotEqual(t, nil, call.WaitFor)
+		assert.NotNil(t, call.Run)
+
+	}
+
+	et := ExampleType{}
+	assert.Equal(t, false, et.ran)
+	mockedService.TheExampleMethod3(&et)
+	assert.Equal(t, true, et.ran)
+
+}
+
+func Test_Mock_Return_Once(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Once()
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 1, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Twice(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Twice()
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 2, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Times(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Times(5)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 5, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Nothing(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 0, len(call.ReturnArguments))
+
+	}
+
+}
+
+func Test_Mock_findExpectedCall(t *testing.T) {
+
+	m := new(Mock)
+	m.On("One", 1).Return("one")
+	m.On("Two", 2).Return("two")
+	m.On("Two", 3).Return("three")
+
+	f, c := m.findExpectedCall("Two", 3)
+
+	if assert.Equal(t, 2, f) {
+		if assert.NotNil(t, c) {
+			assert.Equal(t, "Two", c.Method)
+			assert.Equal(t, 3, c.Arguments[0])
+			assert.Equal(t, "three", c.ReturnArguments[0])
+		}
+	}
+
+}
+
+func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) {
+
+	m := new(Mock)
+	m.On("One", 1).Return("one")
+	m.On("Two", 2).Return("two")
+	m.On("Two", 3).Return("three")
+
+	f, _ := m.findExpectedCall("Two")
+
+	assert.Equal(t, -1, f)
+
+}
+
+func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) {
+
+	m := new(Mock)
+	m.On("One", 1).Return("one")
+	m.On("Two", 2).Return("two").Once()
+	m.On("Two", 3).Return("three").Twice()
+	m.On("Two", 3).Return("three").Times(8)
+
+	f, c := m.findExpectedCall("Two", 3)
+
+	if assert.Equal(t, 2, f) {
+		if assert.NotNil(t, c) {
+			assert.Equal(t, "Two", c.Method)
+			assert.Equal(t, 3, c.Arguments[0])
+			assert.Equal(t, "three", c.ReturnArguments[0])
+		}
+	}
+
+}
+
+func Test_callString(t *testing.T) {
+
+	assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false))
+
+}
+
+func Test_Mock_Called(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_Called", 1, 2, 3).Return(5, "6", true)
+
+	returnArguments := mockedService.Called(1, 2, 3)
+
+	if assert.Equal(t, 1, len(mockedService.Calls)) {
+		assert.Equal(t, "Test_Mock_Called", mockedService.Calls[0].Method)
+		assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
+		assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
+		assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments)) {
+		assert.Equal(t, 5, returnArguments[0])
+		assert.Equal(t, "6", returnArguments[1])
+		assert.Equal(t, true, returnArguments[2])
+	}
+
+}
+
+func asyncCall(m *Mock, ch chan Arguments) {
+	ch <- m.Called(1, 2, 3)
+}
+
+func Test_Mock_Called_blocks(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(2 * time.Millisecond)
+
+	ch := make(chan Arguments)
+
+	go asyncCall(&mockedService.Mock, ch)
+
+	select {
+	case <-ch:
+		t.Fatal("should have waited")
+	case <-time.After(1 * time.Millisecond):
+	}
+
+	returnArguments := <-ch
+
+	if assert.Equal(t, 1, len(mockedService.Mock.Calls)) {
+		assert.Equal(t, "asyncCall", mockedService.Mock.Calls[0].Method)
+		assert.Equal(t, 1, mockedService.Mock.Calls[0].Arguments[0])
+		assert.Equal(t, 2, mockedService.Mock.Calls[0].Arguments[1])
+		assert.Equal(t, 3, mockedService.Mock.Calls[0].Arguments[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments)) {
+		assert.Equal(t, 5, returnArguments[0])
+		assert.Equal(t, "6", returnArguments[1])
+		assert.Equal(t, true, returnArguments[2])
+	}
+
+}
+
+func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(5, "6", true).Once()
+	mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(-1, "hi", false)
+
+	returnArguments1 := mockedService.Called(1, 2, 3)
+	returnArguments2 := mockedService.Called(1, 2, 3)
+
+	if assert.Equal(t, 2, len(mockedService.Calls)) {
+		assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[0].Method)
+		assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
+		assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
+		assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
+
+		assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[1].Method)
+		assert.Equal(t, 1, mockedService.Calls[1].Arguments[0])
+		assert.Equal(t, 2, mockedService.Calls[1].Arguments[1])
+		assert.Equal(t, 3, mockedService.Calls[1].Arguments[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments1)) {
+		assert.Equal(t, 5, returnArguments1[0])
+		assert.Equal(t, "6", returnArguments1[1])
+		assert.Equal(t, true, returnArguments1[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments2)) {
+		assert.Equal(t, -1, returnArguments2[0])
+		assert.Equal(t, "hi", returnArguments2[1])
+		assert.Equal(t, false, returnArguments2[2])
+	}
+
+}
+
+func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", 1, 2, 3).Return(5, "6", true).Times(4)
+
+	mockedService.TheExampleMethod(1, 2, 3)
+	mockedService.TheExampleMethod(1, 2, 3)
+	mockedService.TheExampleMethod(1, 2, 3)
+	mockedService.TheExampleMethod(1, 2, 3)
+	assert.Panics(t, func() {
+		mockedService.TheExampleMethod(1, 2, 3)
+	})
+
+}
+
+func Test_Mock_Called_Unexpected(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	// make sure it panics if no expectation was made
+	assert.Panics(t, func() {
+		mockedService.Called(1, 2, 3)
+	}, "Calling unexpected method should panic")
+
+}
+
+func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
+
+	var mockedService1 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService2 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService3 *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService1.On("Test_AssertExpectationsForObjects_Helper", 1).Return()
+	mockedService2.On("Test_AssertExpectationsForObjects_Helper", 2).Return()
+	mockedService3.On("Test_AssertExpectationsForObjects_Helper", 3).Return()
+
+	mockedService1.Called(1)
+	mockedService2.Called(2)
+	mockedService3.Called(3)
+
+	assert.True(t, AssertExpectationsForObjects(t, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+
+}
+
+func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
+
+	var mockedService1 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService2 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService3 *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService1.On("Test_AssertExpectationsForObjects_Helper_Failed", 1).Return()
+	mockedService2.On("Test_AssertExpectationsForObjects_Helper_Failed", 2).Return()
+	mockedService3.On("Test_AssertExpectationsForObjects_Helper_Failed", 3).Return()
+
+	mockedService1.Called(1)
+	mockedService3.Called(3)
+
+	tt := new(testing.T)
+	assert.False(t, AssertExpectationsForObjects(tt, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+
+}
+
+func Test_Mock_AssertExpectations(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertExpectations", 1, 2, 3).Return(5, 6, 7)
+
+	tt := new(testing.T)
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	// make the call now
+	mockedService.Called(1, 2, 3)
+
+	// now assert expectations
+	assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Once()
+
+	tt := new(testing.T)
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	// make the call now
+	mockedService.TheExampleMethod3(&ExampleType{})
+
+	// now assert expectations
+	assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertExpectations_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Twice()
+
+	tt := new(testing.T)
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	// make the call now
+	mockedService.Called(1, 2, 3)
+
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	mockedService.Called(1, 2, 3)
+
+	// now assert expectations
+	assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 1, 2, 3).Return(5, 6, 7)
+	mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 4, 5, 6).Return(5, 6, 7)
+
+	args1 := mockedService.Called(1, 2, 3)
+	assert.Equal(t, 5, args1.Int(0))
+	assert.Equal(t, 6, args1.Int(1))
+	assert.Equal(t, 7, args1.Int(2))
+
+	args2 := mockedService.Called(4, 5, 6)
+	assert.Equal(t, 5, args2.Int(0))
+	assert.Equal(t, 6, args2.Int(1))
+	assert.Equal(t, 7, args2.Int(2))
+
+}
+
+func Test_Mock_AssertNumberOfCalls(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertNumberOfCalls", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+	assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 1))
+
+	mockedService.Called(1, 2, 3)
+	assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 2))
+
+}
+
+func Test_Mock_AssertCalled(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+
+	assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled", 1, 2, 3))
+
+}
+
+func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything).Return()
+
+	mockedService.Called(1, "two", []uint8("three"))
+
+	assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled_WithAnythingOfTypeArgument", AnythingOfType("int"), AnythingOfType("string"), AnythingOfType("[]uint8")))
+
+}
+
+func Test_Mock_AssertCalled_WithArguments(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled_WithArguments", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+
+	tt := new(testing.T)
+	assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 1, 2, 3))
+	assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 2, 3, 4))
+
+}
+
+func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Once()
+	mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4).Return(5, 6, 7).Once()
+
+	mockedService.Called(1, 2, 3)
+	mockedService.Called(2, 3, 4)
+
+	tt := new(testing.T)
+	assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3))
+	assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4))
+	assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 3, 4, 5))
+
+}
+
+func Test_Mock_AssertNotCalled(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertNotCalled", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+
+	assert.True(t, mockedService.AssertNotCalled(t, "Test_Mock_NotCalled"))
+
+}
+
+/*
+	Arguments helper methods
+*/
+func Test_Arguments_Get(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+
+	assert.Equal(t, "string", args.Get(0).(string))
+	assert.Equal(t, 123, args.Get(1).(int))
+	assert.Equal(t, true, args.Get(2).(bool))
+
+}
+
+func Test_Arguments_Is(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+
+	assert.True(t, args.Is("string", 123, true))
+	assert.False(t, args.Is("wrong", 456, false))
+
+}
+
+func Test_Arguments_Diff(t *testing.T) {
+
+	var args Arguments = []interface{}{"Hello World", 123, true}
+	var diff string
+	var count int
+	diff, count = args.Diff([]interface{}{"Hello World", 456, "false"})
+
+	assert.Equal(t, 2, count)
+	assert.Contains(t, diff, `%!s(int=456) != %!s(int=123)`)
+	assert.Contains(t, diff, `false != %!s(bool=true)`)
+
+}
+
+func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	var diff string
+	var count int
+	diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"})
+
+	assert.Equal(t, 3, count)
+	assert.Contains(t, diff, `extra != (Missing)`)
+
+}
+
+func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	var count int
+	_, count = args.Diff([]interface{}{"string", Anything, true})
+
+	assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", Anything, true}
+	var count int
+	_, count = args.Diff([]interface{}{"string", 123, true})
+
+	assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", AnythingOfType("int"), true}
+	var count int
+	_, count = args.Diff([]interface{}{"string", 123, true})
+
+	assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", AnythingOfType("string"), true}
+	var count int
+	var diff string
+	diff, count = args.Diff([]interface{}{"string", 123, true})
+
+	assert.Equal(t, 1, count)
+	assert.Contains(t, diff, `string != type int - %!s(int=123)`)
+
+}
+
+func Test_Arguments_Assert(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+
+	assert.True(t, args.Assert(t, "string", 123, true))
+
+}
+
+func Test_Arguments_String_Representation(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, `string,int,bool`, args.String())
+
+}
+
+func Test_Arguments_String(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, "string", args.String(0))
+
+}
+
+func Test_Arguments_Error(t *testing.T) {
+
+	var err error = errors.New("An Error")
+	var args Arguments = []interface{}{"string", 123, true, err}
+	assert.Equal(t, err, args.Error(3))
+
+}
+
+func Test_Arguments_Error_Nil(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true, nil}
+	assert.Equal(t, nil, args.Error(3))
+
+}
+
+func Test_Arguments_Int(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, 123, args.Int(1))
+
+}
+
+func Test_Arguments_Bool(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, true, args.Bool(2))
+
+}

+ 5 - 0
libnetwork/cmd/dnet/dnet.go

@@ -12,6 +12,7 @@ import (
 
 
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/reexec"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/pkg/term"
@@ -31,6 +32,10 @@ var (
 )
 )
 
 
 func main() {
 func main() {
+	if reexec.Init() {
+		return
+	}
+
 	_, stdout, stderr := term.StdStreams()
 	_, stdout, stderr := term.StdStreams()
 	logrus.SetOutput(stderr)
 	logrus.SetOutput(stderr)
 
 

+ 2 - 2
libnetwork/cmd/test/libnetwork.toml

@@ -3,8 +3,8 @@ title = "LibNetwork Configuration file"
 [daemon]
 [daemon]
   debug = false
   debug = false
 [cluster]
 [cluster]
-  discovery = "token://ce5b9756aeab50fe8fda02624f093d1c"
-  Address = "1.1.1.1:90"
+  discovery = "token://22aa23948f4f6b31230687689636959e"
+  Address = "1.1.1.1"
 [datastore]
 [datastore]
   embedded = false
   embedded = false
 [datastore.client]
 [datastore.client]

+ 21 - 5
libnetwork/cmd/test/main.go

@@ -2,16 +2,18 @@ package main
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"log"
 	"net"
 	"net"
 	"os"
 	"os"
 	"time"
 	"time"
 
 
+	log "github.com/Sirupsen/logrus"
+
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
 )
 )
 
 
 func main() {
 func main() {
+	log.SetLevel(log.DebugLevel)
 	os.Setenv("LIBNETWORK_CFG", "libnetwork.toml")
 	os.Setenv("LIBNETWORK_CFG", "libnetwork.toml")
 	controller, err := libnetwork.New("libnetwork.toml")
 	controller, err := libnetwork.New("libnetwork.toml")
 	if err != nil {
 	if err != nil {
@@ -24,12 +26,26 @@ func main() {
 	options := options.Generic{"AddressIPv4": net}
 	options := options.Generic{"AddressIPv4": net}
 
 
 	err = controller.ConfigureNetworkDriver(netType, options)
 	err = controller.ConfigureNetworkDriver(netType, options)
-	for i := 0; i < 100; i++ {
+	for i := 0; i < 10; i++ {
 		netw, err := controller.NewNetwork(netType, fmt.Sprintf("Gordon-%d", i))
 		netw, err := controller.NewNetwork(netType, fmt.Sprintf("Gordon-%d", i))
 		if err != nil {
 		if err != nil {
-			log.Fatal(err)
+			if _, ok := err.(libnetwork.NetworkNameError); !ok {
+				log.Fatal(err)
+			}
+		} else {
+			fmt.Println("Network Created Successfully :", netw)
+		}
+		netw, _ = controller.NetworkByName(fmt.Sprintf("Gordon-%d", i))
+		_, err = netw.CreateEndpoint(fmt.Sprintf("Gordon-Ep-%d", i), nil)
+		if err != nil {
+			log.Fatalf("Error creating endpoint 1 %v", err)
 		}
 		}
-		fmt.Println("Network Created Successfully :", netw)
-		time.Sleep(10 * time.Second)
+
+		_, err = netw.CreateEndpoint(fmt.Sprintf("Gordon-Ep2-%d", i), nil)
+		if err != nil {
+			log.Fatalf("Error creating endpoint 2 %v", err)
+		}
+
+		time.Sleep(2 * time.Second)
 	}
 	}
 }
 }

+ 59 - 100
libnetwork/controller.go

@@ -45,7 +45,6 @@ create network namespaces and allocate interfaces for containers to use.
 package libnetwork
 package libnetwork
 
 
 import (
 import (
-	"encoding/json"
 	"fmt"
 	"fmt"
 	"net"
 	"net"
 	"os"
 	"os"
@@ -61,7 +60,6 @@ import (
 	"github.com/docker/libnetwork/hostdiscovery"
 	"github.com/docker/libnetwork/hostdiscovery"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
-	"github.com/docker/swarm/pkg/store"
 )
 )
 
 
 // NetworkController provides the interface for controller instance which manages
 // NetworkController provides the interface for controller instance which manages
@@ -94,6 +92,12 @@ type NetworkController interface {
 // When the function returns true, the walk will stop.
 // When the function returns true, the walk will stop.
 type NetworkWalker func(nw Network) bool
 type NetworkWalker func(nw Network) bool
 
 
+type driverData struct {
+	driver     driverapi.Driver
+	capability driverapi.Capability
+}
+
+type driverTable map[string]*driverData
 type networkTable map[types.UUID]*network
 type networkTable map[types.UUID]*network
 type endpointTable map[types.UUID]*endpoint
 type endpointTable map[types.UUID]*endpoint
 type sandboxTable map[string]*sandboxData
 type sandboxTable map[string]*sandboxData
@@ -160,23 +164,6 @@ func (c *controller) initConfig(configFile string) error {
 	return nil
 	return nil
 }
 }
 
 
-func (c *controller) initDataStore() error {
-	if c.cfg == nil {
-		return fmt.Errorf("datastore initialization requires a valid configuration")
-	}
-
-	store, err := datastore.NewDataStore(&c.cfg.Datastore)
-	if err != nil {
-		return err
-	}
-	c.Lock()
-	c.store = store
-	c.Unlock()
-	go c.watchNewNetworks()
-
-	return nil
-}
-
 func (c *controller) initDiscovery() error {
 func (c *controller) initDiscovery() error {
 	if c.cfg == nil {
 	if c.cfg == nil {
 		return fmt.Errorf("discovery initialization requires a valid configuration")
 		return fmt.Errorf("discovery initialization requires a valid configuration")
@@ -194,21 +181,21 @@ func (c *controller) hostLeaveCallback(hosts []net.IP) {
 
 
 func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error {
 func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error {
 	c.Lock()
 	c.Lock()
-	d, ok := c.drivers[networkType]
+	dd, ok := c.drivers[networkType]
 	c.Unlock()
 	c.Unlock()
 	if !ok {
 	if !ok {
 		return NetworkTypeError(networkType)
 		return NetworkTypeError(networkType)
 	}
 	}
-	return d.Config(options)
+	return dd.driver.Config(options)
 }
 }
 
 
-func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver) error {
+func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
 	c.Lock()
 	c.Lock()
 	defer c.Unlock()
 	defer c.Unlock()
 	if _, ok := c.drivers[networkType]; ok {
 	if _, ok := c.drivers[networkType]; ok {
 		return driverapi.ErrActiveRegistration(networkType)
 		return driverapi.ErrActiveRegistration(networkType)
 	}
 	}
-	c.drivers[networkType] = driver
+	c.drivers[networkType] = &driverData{driver, capability}
 	return nil
 	return nil
 }
 }
 
 
@@ -218,18 +205,6 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
 	if name == "" {
 	if name == "" {
 		return nil, ErrInvalidName(name)
 		return nil, ErrInvalidName(name)
 	}
 	}
-	// Check if a driver for the specified network type is available
-	c.Lock()
-	d, ok := c.drivers[networkType]
-	c.Unlock()
-	if !ok {
-		var err error
-		d, err = c.loadDriver(networkType)
-		if err != nil {
-			return nil, err
-		}
-	}
-
 	// Check if a network already exists with the specified network name
 	// Check if a network already exists with the specified network name
 	c.Lock()
 	c.Lock()
 	for _, n := range c.networks {
 	for _, n := range c.networks {
@@ -242,87 +217,58 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
 
 
 	// Construct the network object
 	// Construct the network object
 	network := &network{
 	network := &network{
-		name:      name,
-		id:        types.UUID(stringid.GenerateRandomID()),
-		ctrlr:     c,
-		driver:    d,
-		endpoints: endpointTable{},
+		name:        name,
+		networkType: networkType,
+		id:          types.UUID(stringid.GenerateRandomID()),
+		ctrlr:       c,
+		endpoints:   endpointTable{},
 	}
 	}
 
 
 	network.processOptions(options...)
 	network.processOptions(options...)
-	if err := c.addNetworkToStore(network); err != nil {
+
+	if err := c.addNetwork(network); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	// Create the network
-	if err := d.CreateNetwork(network.id, network.generic); err != nil {
+
+	if err := c.updateNetworkToStore(network); err != nil {
+		if e := network.Delete(); e != nil {
+			log.Warnf("couldnt cleanup network %s: %v", network.name, err)
+		}
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	// Store the network handler in controller
-	c.Lock()
-	c.networks[network.id] = network
-	c.Unlock()
-
 	return network, nil
 	return network, nil
 }
 }
 
 
-func (c *controller) newNetworkFromStore(n *network) {
-	c.Lock()
-	defer c.Unlock()
-
-	if _, ok := c.drivers[n.networkType]; !ok {
-		log.Warnf("Network driver unavailable for type=%s. ignoring network updates for %s", n.Type(), n.Name())
-		return
-	}
-	n.ctrlr = c
-	n.driver = c.drivers[n.networkType]
-	c.networks[n.id] = n
-	// TODO : Populate n.endpoints back from endpoint dbstore
-}
+func (c *controller) addNetwork(n *network) error {
 
 
-func (c *controller) addNetworkToStore(n *network) error {
-	if isReservedNetwork(n.Name()) {
-		return nil
-	}
 	c.Lock()
 	c.Lock()
-	cs := c.store
+	// Check if a driver for the specified network type is available
+	dd, ok := c.drivers[n.networkType]
 	c.Unlock()
 	c.Unlock()
-	if cs == nil {
-		log.Debugf("datastore not initialized. Network %s is not added to the store", n.Name())
-		return nil
+
+	if !ok {
+		var err error
+		dd, err = c.loadDriver(n.networkType)
+		if err != nil {
+			return err
+		}
 	}
 	}
-	return cs.PutObjectAtomic(n)
-}
 
 
-func (c *controller) watchNewNetworks() {
+	n.Lock()
+	n.driver = dd.driver
+	d := n.driver
+	n.Unlock()
+
+	// Create the network
+	if err := d.CreateNetwork(n.id, n.generic); err != nil {
+		return err
+	}
 	c.Lock()
 	c.Lock()
-	cs := c.store
+	c.networks[n.id] = n
 	c.Unlock()
 	c.Unlock()
 
 
-	cs.KVStore().WatchRange(datastore.Key(datastore.NetworkKeyPrefix), "", 0, func(kvi []store.KVEntry) {
-		for _, kve := range kvi {
-			var n network
-			err := json.Unmarshal(kve.Value(), &n)
-			if err != nil {
-				log.Error(err)
-				continue
-			}
-			n.dbIndex = kve.LastIndex()
-			c.Lock()
-			existing, ok := c.networks[n.id]
-			c.Unlock()
-			if ok && existing.dbIndex == n.dbIndex {
-				// Skip any watch notification for a network that has not changed
-				continue
-			} else if ok {
-				// Received an update for an existing network object
-				log.Debugf("Skipping network update for %s (%s)", n.name, n.id)
-				continue
-			}
-
-			c.newNetworkFromStore(&n)
-		}
-	})
+	return nil
 }
 }
 
 
 func (c *controller) Networks() []Network {
 func (c *controller) Networks() []Network {
@@ -380,7 +326,7 @@ func (c *controller) NetworkByID(id string) (Network, error) {
 	return nil, ErrNoSuchNetwork(id)
 	return nil, ErrNoSuchNetwork(id)
 }
 }
 
 
-func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
+func (c *controller) loadDriver(networkType string) (*driverData, error) {
 	// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
 	// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
@@ -392,11 +338,24 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
 	}
 	}
 	c.Lock()
 	c.Lock()
 	defer c.Unlock()
 	defer c.Unlock()
-	d, ok := c.drivers[networkType]
+	dd, ok := c.drivers[networkType]
 	if !ok {
 	if !ok {
 		return nil, ErrInvalidNetworkDriver(networkType)
 		return nil, ErrInvalidNetworkDriver(networkType)
 	}
 	}
-	return d, nil
+	return dd, nil
+}
+
+func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
+	c.Lock()
+	dd, ok := c.drivers[networkType]
+	c.Unlock()
+	if !ok {
+		return false, types.NotFoundErrorf("driver not found for %s", networkType)
+	}
+	if dd.capability.Scope == driverapi.GlobalScope {
+		return true, nil
+	}
+	return false, nil
 }
 }
 
 
 func (c *controller) GC() {
 func (c *controller) GC() {

+ 69 - 19
libnetwork/datastore/datastore.go

@@ -1,19 +1,29 @@
 package datastore
 package datastore
 
 
 import (
 import (
-	"errors"
+	"encoding/json"
+	"reflect"
 	"strings"
 	"strings"
 
 
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/config"
+	"github.com/docker/libnetwork/types"
 	"github.com/docker/swarm/pkg/store"
 	"github.com/docker/swarm/pkg/store"
 )
 )
 
 
 //DataStore exported
 //DataStore exported
 type DataStore interface {
 type DataStore interface {
+	// GetObject gets data from datastore and unmarshals to the specified object
+	GetObject(key string, o interface{}) error
 	// PutObject adds a new Record based on an object into the datastore
 	// PutObject adds a new Record based on an object into the datastore
 	PutObject(kvObject KV) error
 	PutObject(kvObject KV) error
 	// PutObjectAtomic provides an atomic add and update operation for a Record
 	// PutObjectAtomic provides an atomic add and update operation for a Record
 	PutObjectAtomic(kvObject KV) error
 	PutObjectAtomic(kvObject KV) error
+	// DeleteObject deletes a record
+	DeleteObject(kvObject KV) error
+	// DeleteObjectAtomic performs an atomic delete operation
+	DeleteObjectAtomic(kvObject KV) error
+	// DeleteTree deletes a record
+	DeleteTree(kvObject KV) error
 	// KVStore returns access to the KV Store
 	// KVStore returns access to the KV Store
 	KVStore() store.Store
 	KVStore() store.Store
 }
 }
@@ -26,6 +36,8 @@ type datastore struct {
 type KV interface {
 type KV interface {
 	// Key method lets an object to provide the Key to be used in KV Store
 	// Key method lets an object to provide the Key to be used in KV Store
 	Key() []string
 	Key() []string
+	// KeyPrefix method lets an object to return immediate parent key that can be used for tree walk
+	KeyPrefix() []string
 	// Value method lets an object to marshal its content to be stored in the KV store
 	// Value method lets an object to marshal its content to be stored in the KV store
 	Value() []byte
 	Value() []byte
 	// Index method returns the latest DB Index as seen by the object
 	// Index method returns the latest DB Index as seen by the object
@@ -37,23 +49,33 @@ type KV interface {
 const (
 const (
 	// NetworkKeyPrefix is the prefix for network key in the kv store
 	// NetworkKeyPrefix is the prefix for network key in the kv store
 	NetworkKeyPrefix = "network"
 	NetworkKeyPrefix = "network"
+	// EndpointKeyPrefix is the prefix for endpoint key in the kv store
+	EndpointKeyPrefix = "endpoint"
 )
 )
 
 
+var rootChain = []string{"docker", "libnetwork"}
+
 //Key provides convenient method to create a Key
 //Key provides convenient method to create a Key
 func Key(key ...string) string {
 func Key(key ...string) string {
-	keychain := []string{"docker", "libnetwork"}
-	keychain = append(keychain, key...)
+	keychain := append(rootChain, key...)
 	str := strings.Join(keychain, "/")
 	str := strings.Join(keychain, "/")
 	return str + "/"
 	return str + "/"
 }
 }
 
 
-var errNewDatastore = errors.New("Error creating new Datastore")
-var errInvalidConfiguration = errors.New("Invalid Configuration passed to Datastore")
-var errInvalidAtomicRequest = errors.New("Invalid Atomic Request")
+//ParseKey provides convenient method to unpack the key to complement the Key function
+func ParseKey(key string) ([]string, error) {
+	chain := strings.Split(strings.Trim(key, "/"), "/")
+
+	// The key must atleast be equal to the rootChain in order to be considered as valid
+	if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) {
+		return nil, types.BadRequestErrorf("invalid Key : %s", key)
+	}
+	return chain[len(rootChain):], nil
+}
 
 
 // newClient used to connect to KV Store
 // newClient used to connect to KV Store
 func newClient(kv string, addrs string) (DataStore, error) {
 func newClient(kv string, addrs string) (DataStore, error) {
-	store, err := store.CreateStore(kv, []string{addrs}, store.Config{})
+	store, err := store.NewStore(store.Backend(kv), []string{addrs}, &store.Config{})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -64,7 +86,7 @@ func newClient(kv string, addrs string) (DataStore, error) {
 // NewDataStore creates a new instance of LibKV data store
 // NewDataStore creates a new instance of LibKV data store
 func NewDataStore(cfg *config.DatastoreCfg) (DataStore, error) {
 func NewDataStore(cfg *config.DatastoreCfg) (DataStore, error) {
 	if cfg == nil {
 	if cfg == nil {
-		return nil, errInvalidConfiguration
+		return nil, types.BadRequestErrorf("invalid configuration passed to datastore")
 	}
 	}
 	// TODO : cfg.Embedded case
 	// TODO : cfg.Embedded case
 	return newClient(cfg.Client.Provider, cfg.Client.Address)
 	return newClient(cfg.Client.Provider, cfg.Client.Address)
@@ -82,30 +104,28 @@ func (ds *datastore) KVStore() store.Store {
 // PutObjectAtomic adds a new Record based on an object into the datastore
 // PutObjectAtomic adds a new Record based on an object into the datastore
 func (ds *datastore) PutObjectAtomic(kvObject KV) error {
 func (ds *datastore) PutObjectAtomic(kvObject KV) error {
 	if kvObject == nil {
 	if kvObject == nil {
-		return errors.New("kvObject is nil")
+		return types.BadRequestErrorf("invalid KV Object : nil")
 	}
 	}
 	kvObjValue := kvObject.Value()
 	kvObjValue := kvObject.Value()
 
 
 	if kvObjValue == nil {
 	if kvObjValue == nil {
-		return errInvalidAtomicRequest
-	}
-	_, err := ds.store.AtomicPut(Key(kvObject.Key()...), []byte{}, kvObjValue, kvObject.Index())
-	if err != nil {
-		return err
+		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
 	}
 	}
 
 
-	_, index, err := ds.store.Get(Key(kvObject.Key()...))
+	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
+	_, pair, err := ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	kvObject.SetIndex(index)
+
+	kvObject.SetIndex(pair.LastIndex)
 	return nil
 	return nil
 }
 }
 
 
 // PutObject adds a new Record based on an object into the datastore
 // PutObject adds a new Record based on an object into the datastore
 func (ds *datastore) PutObject(kvObject KV) error {
 func (ds *datastore) PutObject(kvObject KV) error {
 	if kvObject == nil {
 	if kvObject == nil {
-		return errors.New("kvObject is nil")
+		return types.BadRequestErrorf("invalid KV Object : nil")
 	}
 	}
 	return ds.putObjectWithKey(kvObject, kvObject.Key()...)
 	return ds.putObjectWithKey(kvObject, kvObject.Key()...)
 }
 }
@@ -114,7 +134,37 @@ func (ds *datastore) putObjectWithKey(kvObject KV, key ...string) error {
 	kvObjValue := kvObject.Value()
 	kvObjValue := kvObject.Value()
 
 
 	if kvObjValue == nil {
 	if kvObjValue == nil {
-		return errors.New("Object must provide marshalled data for key : " + Key(kvObject.Key()...))
+		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
+	}
+	return ds.store.Put(Key(key...), kvObjValue, nil)
+}
+
+// GetObject returns a record matching the key
+func (ds *datastore) GetObject(key string, o interface{}) error {
+	kvPair, err := ds.store.Get(key)
+	if err != nil {
+		return err
 	}
 	}
-	return ds.store.Put(Key(key...), kvObjValue)
+	return json.Unmarshal(kvPair.Value, o)
+}
+
+// DeleteObject unconditionally deletes a record from the store
+func (ds *datastore) DeleteObject(kvObject KV) error {
+	return ds.store.Delete(Key(kvObject.Key()...))
+}
+
+// DeleteObjectAtomic performs atomic delete on a record
+func (ds *datastore) DeleteObjectAtomic(kvObject KV) error {
+	if kvObject == nil {
+		return types.BadRequestErrorf("invalid KV Object : nil")
+	}
+
+	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
+	_, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous)
+	return err
+}
+
+// DeleteTree unconditionally deletes a record from the store
+func (ds *datastore) DeleteTree(kvObject KV) error {
+	return ds.store.DeleteTree(Key(kvObject.KeyPrefix()...))
 }
 }

+ 30 - 5
libnetwork/datastore/datastore_test.go

@@ -2,6 +2,7 @@ package datastore
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
+	"reflect"
 	"testing"
 	"testing"
 
 
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/config"
@@ -16,6 +17,25 @@ func NewTestDataStore() DataStore {
 	return &datastore{store: NewMockStore()}
 	return &datastore{store: NewMockStore()}
 }
 }
 
 
+func TestKey(t *testing.T) {
+	eKey := []string{"hello", "world"}
+	sKey := Key(eKey...)
+	if sKey != "docker/libnetwork/hello/world/" {
+		t.Fatalf("unexpected key : %s", sKey)
+	}
+}
+
+func TestParseKey(t *testing.T) {
+	keySlice, err := ParseKey("/docker/libnetwork/hello/world/")
+	if err != nil {
+		t.Fatal(err)
+	}
+	eKey := []string{"hello", "world"}
+	if len(keySlice) < 2 || !reflect.DeepEqual(eKey, keySlice) {
+		t.Fatalf("unexpected unkey : %s", keySlice)
+	}
+}
+
 func TestInvalidDataStore(t *testing.T) {
 func TestInvalidDataStore(t *testing.T) {
 	config := &config.DatastoreCfg{}
 	config := &config.DatastoreCfg{}
 	config.Embedded = false
 	config.Embedded = false
@@ -35,12 +55,12 @@ func TestKVObjectFlatKey(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	keychain := []string{dummyKey, "1000"}
 	keychain := []string{dummyKey, "1000"}
-	data, _, err := store.KVStore().Get(Key(keychain...))
+	data, err := store.KVStore().Get(Key(keychain...))
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	var n dummyObject
 	var n dummyObject
-	json.Unmarshal(data, &n)
+	json.Unmarshal(data.Value, &n)
 	if n.Name != expected.Name {
 	if n.Name != expected.Name {
 		t.Fatalf("Dummy object doesnt match the expected object")
 		t.Fatalf("Dummy object doesnt match the expected object")
 	}
 	}
@@ -63,14 +83,14 @@ func TestAtomicKVObjectFlatKey(t *testing.T) {
 
 
 	// Get the latest index and try PutObjectAtomic again for the same Key
 	// Get the latest index and try PutObjectAtomic again for the same Key
 	// This must succeed as well
 	// This must succeed as well
-	data, index, err := store.KVStore().Get(Key(expected.Key()...))
+	data, err := store.KVStore().Get(Key(expected.Key()...))
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	n := dummyObject{}
 	n := dummyObject{}
-	json.Unmarshal(data, &n)
+	json.Unmarshal(data.Value, &n)
 	n.ID = "1111"
 	n.ID = "1111"
-	n.DBIndex = index
+	n.DBIndex = data.LastIndex
 	n.ReturnValue = true
 	n.ReturnValue = true
 	err = store.PutObjectAtomic(&n)
 	err = store.PutObjectAtomic(&n)
 	if err != nil {
 	if err != nil {
@@ -94,6 +114,11 @@ type dummyObject struct {
 func (n *dummyObject) Key() []string {
 func (n *dummyObject) Key() []string {
 	return []string{dummyKey, n.ID}
 	return []string{dummyKey, n.ID}
 }
 }
+
+func (n *dummyObject) KeyPrefix() []string {
+	return []string{dummyKey}
+}
+
 func (n *dummyObject) Value() []byte {
 func (n *dummyObject) Value() []byte {
 	if !n.ReturnValue {
 	if !n.ReturnValue {
 		return nil
 		return nil

+ 35 - 47
libnetwork/datastore/mock_store.go

@@ -2,8 +2,8 @@ package datastore
 
 
 import (
 import (
 	"errors"
 	"errors"
-	"time"
 
 
+	"github.com/docker/libnetwork/types"
 	"github.com/docker/swarm/pkg/store"
 	"github.com/docker/swarm/pkg/store"
 )
 )
 
 
@@ -31,17 +31,17 @@ func NewMockStore() *MockStore {
 
 
 // Get the value at "key", returns the last modified index
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
 // to use in conjunction to CAS calls
-func (s *MockStore) Get(key string) (value []byte, lastIndex uint64, err error) {
+func (s *MockStore) Get(key string) (*store.KVPair, error) {
 	mData := s.db[key]
 	mData := s.db[key]
 	if mData == nil {
 	if mData == nil {
-		return nil, 0, nil
+		return nil, nil
 	}
 	}
-	return mData.Data, mData.Index, nil
+	return &store.KVPair{Value: mData.Data, LastIndex: mData.Index}, nil
 
 
 }
 }
 
 
 // Put a value at "key"
 // Put a value at "key"
-func (s *MockStore) Put(key string, value []byte) error {
+func (s *MockStore) Put(key string, value []byte, options *store.WriteOptions) error {
 	mData := s.db[key]
 	mData := s.db[key]
 	if mData == nil {
 	if mData == nil {
 		mData = &MockData{value, 0}
 		mData = &MockData{value, 0}
@@ -63,69 +63,57 @@ func (s *MockStore) Exists(key string) (bool, error) {
 	return ok, nil
 	return ok, nil
 }
 }
 
 
-// GetRange gets a range of values at "directory"
-func (s *MockStore) GetRange(prefix string) (values []store.KVEntry, err error) {
+// List gets a range of values at "directory"
+func (s *MockStore) List(prefix string) ([]*store.KVPair, error) {
 	return nil, ErrNotImplmented
 	return nil, ErrNotImplmented
 }
 }
 
 
-// DeleteRange deletes a range of values at "directory"
-func (s *MockStore) DeleteRange(prefix string) error {
-	return ErrNotImplmented
-}
-
-// Watch a single key for modifications
-func (s *MockStore) Watch(key string, heartbeat time.Duration, callback store.WatchCallback) error {
-	return ErrNotImplmented
-}
-
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *MockStore) CancelWatch(key string) error {
-	return ErrNotImplmented
-}
-
-// Internal function to check if a key has changed
-func (s *MockStore) waitForChange(key string) <-chan uint64 {
+// DeleteTree deletes a range of values at "directory"
+func (s *MockStore) DeleteTree(prefix string) error {
+	delete(s.db, prefix)
 	return nil
 	return nil
 }
 }
 
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *MockStore) WatchRange(prefix string, filter string, heartbeat time.Duration, callback store.WatchCallback) error {
-	return ErrNotImplmented
-}
-
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *MockStore) CancelWatchRange(prefix string) error {
-	return ErrNotImplmented
+// Watch a single key for modifications
+func (s *MockStore) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) {
+	return nil, ErrNotImplmented
 }
 }
 
 
-// Acquire the lock for "key"/"directory"
-func (s *MockStore) Acquire(key string, value []byte) (string, error) {
-	return "", ErrNotImplmented
+// WatchTree triggers a watch on a range of values at "directory"
+func (s *MockStore) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) {
+	return nil, ErrNotImplmented
 }
 }
 
 
-// Release the lock for "key"/"directory"
-func (s *MockStore) Release(id string) error {
-	return ErrNotImplmented
+// NewLock exposed
+func (s *MockStore) NewLock(key string, options *store.LockOptions) (store.Locker, error) {
+	return nil, ErrNotImplmented
 }
 }
 
 
 // AtomicPut put a value at "key" if the key has not been
 // AtomicPut put a value at "key" if the key has not been
 // modified in the meantime, throws an error if this is the case
 // modified in the meantime, throws an error if this is the case
-func (s *MockStore) AtomicPut(key string, _ []byte, newValue []byte, index uint64) (bool, error) {
+func (s *MockStore) AtomicPut(key string, newValue []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
 	mData := s.db[key]
 	mData := s.db[key]
-	if mData != nil && mData.Index != index {
-		return false, errInvalidAtomicRequest
+	if mData != nil && mData.Index != previous.LastIndex {
+		return false, nil, types.BadRequestErrorf("atomic put failed due to mismatched Index")
+	}
+	err := s.Put(key, newValue, nil)
+	if err != nil {
+		return false, nil, err
 	}
 	}
-	return true, s.Put(key, newValue)
+	return true, &store.KVPair{Key: key, Value: newValue, LastIndex: s.db[key].Index}, nil
 }
 }
 
 
 // AtomicDelete deletes a value at "key" if the key has not
 // AtomicDelete deletes a value at "key" if the key has not
 // been modified in the meantime, throws an error if this is the case
 // been modified in the meantime, throws an error if this is the case
-func (s *MockStore) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
+func (s *MockStore) AtomicDelete(key string, previous *store.KVPair) (bool, error) {
 	mData := s.db[key]
 	mData := s.db[key]
-	if mData != nil && mData.Index != index {
-		return false, errInvalidAtomicRequest
+	if mData != nil && mData.Index != previous.LastIndex {
+		return false, types.BadRequestErrorf("atomic delete failed due to mismatched Index")
 	}
 	}
 	return true, s.Delete(key)
 	return true, s.Delete(key)
 }
 }
+
+// Close closes the client connection
+func (s *MockStore) Close() {
+	return
+}

+ 16 - 1
libnetwork/driverapi/driverapi.go

@@ -118,5 +118,20 @@ type JoinInfo interface {
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
 type DriverCallback interface {
 type DriverCallback interface {
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance
-	RegisterDriver(name string, driver Driver) error
+	RegisterDriver(name string, driver Driver, capability Capability) error
+}
+
+// Scope indicates the drivers scope capability
+type Scope int
+
+const (
+	// LocalScope represents the driver capable of providing networking services for containers in a single host
+	LocalScope Scope = iota
+	// GlobalScope represents the driver capable of providing networking services for containers across hosts
+	GlobalScope
+)
+
+// Capability represents the high level capabilities of the drivers which libnetwork can make use of
+type Capability struct {
+	Scope Scope
 }
 }

+ 4 - 2
libnetwork/drivers/bridge/bridge.go

@@ -110,8 +110,10 @@ func Init(dc driverapi.DriverCallback) error {
 	if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil {
 	if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil {
 		logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
 		logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
 	}
 	}
-
-	return dc.RegisterDriver(networkType, newDriver())
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, newDriver(), c)
 }
 }
 
 
 // Validate performs a static validation on the network configuration parameters.
 // Validate performs a static validation on the network configuration parameters.

+ 4 - 1
libnetwork/drivers/host/host.go

@@ -16,7 +16,10 @@ type driver struct {
 
 
 // Init registers a new instance of host driver
 // Init registers a new instance of host driver
 func Init(dc driverapi.DriverCallback) error {
 func Init(dc driverapi.DriverCallback) error {
-	return dc.RegisterDriver(networkType, &driver{})
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 }
 
 
 func (d *driver) Config(option map[string]interface{}) error {
 func (d *driver) Config(option map[string]interface{}) error {

+ 4 - 1
libnetwork/drivers/null/null.go

@@ -16,7 +16,10 @@ type driver struct {
 
 
 // Init registers a new instance of null driver
 // Init registers a new instance of null driver
 func Init(dc driverapi.DriverCallback) error {
 func Init(dc driverapi.DriverCallback) error {
-	return dc.RegisterDriver(networkType, &driver{})
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 }
 
 
 func (d *driver) Config(option map[string]interface{}) error {
 func (d *driver) Config(option map[string]interface{}) error {

+ 4 - 1
libnetwork/drivers/remote/driver.go

@@ -23,7 +23,10 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver {
 // plugin is activated.
 // plugin is activated.
 func Init(dc driverapi.DriverCallback) error {
 func Init(dc driverapi.DriverCallback) error {
 	plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
 	plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
-		if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil {
+		c := driverapi.Capability{
+			Scope: driverapi.GlobalScope,
+		}
+		if err := dc.RegisterDriver(name, newDriver(name, client), c); err != nil {
 			log.Errorf("error registering driver for %s due to %v", name, err)
 			log.Errorf("error registering driver for %s due to %v", name, err)
 		}
 		}
 	})
 	})

+ 4 - 1
libnetwork/drivers/windows/windows.go

@@ -13,7 +13,10 @@ type driver struct{}
 
 
 // Init registers a new instance of null driver
 // Init registers a new instance of null driver
 func Init(dc driverapi.DriverCallback) error {
 func Init(dc driverapi.DriverCallback) error {
-	return dc.RegisterDriver(networkType, &driver{})
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 }
 
 
 func (d *driver) Config(option map[string]interface{}) error {
 func (d *driver) Config(option map[string]interface{}) error {

+ 0 - 2
libnetwork/drivers_freebsd.go

@@ -6,8 +6,6 @@ import (
 	"github.com/docker/libnetwork/drivers/remote"
 	"github.com/docker/libnetwork/drivers/remote"
 )
 )
 
 
-type driverTable map[string]driverapi.Driver
-
 func initDrivers(dc driverapi.DriverCallback) error {
 func initDrivers(dc driverapi.DriverCallback) error {
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 		null.Init,
 		null.Init,

+ 0 - 2
libnetwork/drivers_linux.go

@@ -8,8 +8,6 @@ import (
 	"github.com/docker/libnetwork/drivers/remote"
 	"github.com/docker/libnetwork/drivers/remote"
 )
 )
 
 
-type driverTable map[string]driverapi.Driver
-
 func initDrivers(dc driverapi.DriverCallback) error {
 func initDrivers(dc driverapi.DriverCallback) error {
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 		bridge.Init,
 		bridge.Init,

+ 0 - 2
libnetwork/drivers_windows.go

@@ -5,8 +5,6 @@ import (
 	"github.com/docker/libnetwork/drivers/windows"
 	"github.com/docker/libnetwork/drivers/windows"
 )
 )
 
 
-type driverTable map[string]driverapi.Driver
-
 func initDrivers(dc driverapi.DriverCallback) error {
 func initDrivers(dc driverapi.DriverCallback) error {
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 		windows.Init,
 		windows.Init,

+ 190 - 5
libnetwork/endpoint.go

@@ -2,6 +2,8 @@ package libnetwork
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	"encoding/json"
+	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"path"
 	"path"
@@ -10,6 +12,7 @@ import (
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/resolvconf"
@@ -96,6 +99,7 @@ type containerInfo struct {
 	id     string
 	id     string
 	config containerConfig
 	config containerConfig
 	data   ContainerData
 	data   ContainerData
+	sync.Mutex
 }
 }
 
 
 type endpoint struct {
 type endpoint struct {
@@ -108,9 +112,84 @@ type endpoint struct {
 	exposedPorts  []types.TransportPort
 	exposedPorts  []types.TransportPort
 	generic       map[string]interface{}
 	generic       map[string]interface{}
 	joinLeaveDone chan struct{}
 	joinLeaveDone chan struct{}
+	dbIndex       uint64
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
+func (ci *containerInfo) MarshalJSON() ([]byte, error) {
+	ci.Lock()
+	defer ci.Unlock()
+
+	// We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
+	return json.Marshal(ci.id)
+}
+
+func (ci *containerInfo) UnmarshalJSON(b []byte) (err error) {
+	ci.Lock()
+	defer ci.Unlock()
+
+	var id string
+	if err := json.Unmarshal(b, &id); err != nil {
+		return err
+	}
+	ci.id = id
+	return nil
+}
+
+func (ep *endpoint) MarshalJSON() ([]byte, error) {
+	ep.Lock()
+	defer ep.Unlock()
+
+	epMap := make(map[string]interface{})
+	epMap["name"] = ep.name
+	epMap["id"] = string(ep.id)
+	epMap["ep_iface"] = ep.iFaces
+	epMap["exposed_ports"] = ep.exposedPorts
+	epMap["generic"] = ep.generic
+	if ep.container != nil {
+		epMap["container"] = ep.container
+	}
+	return json.Marshal(epMap)
+}
+
+func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
+	ep.Lock()
+	defer ep.Unlock()
+
+	var epMap map[string]interface{}
+	if err := json.Unmarshal(b, &epMap); err != nil {
+		return err
+	}
+	ep.name = epMap["name"].(string)
+	ep.id = types.UUID(epMap["id"].(string))
+
+	ib, _ := json.Marshal(epMap["ep_iface"])
+	var ifaces []endpointInterface
+	json.Unmarshal(ib, &ifaces)
+	ep.iFaces = make([]*endpointInterface, 0)
+	for _, iface := range ifaces {
+		ep.iFaces = append(ep.iFaces, &iface)
+	}
+
+	tb, _ := json.Marshal(epMap["exposed_ports"])
+	var tPorts []types.TransportPort
+	json.Unmarshal(tb, &tPorts)
+	ep.exposedPorts = tPorts
+
+	epc, ok := epMap["container"]
+	if ok {
+		cb, _ := json.Marshal(epc)
+		var cInfo containerInfo
+		json.Unmarshal(cb, &cInfo)
+		ep.container = &cInfo
+	}
+
+	if epMap["generic"] != nil {
+		ep.generic = epMap["generic"].(map[string]interface{})
+	}
+	return nil
+}
+
 const defaultPrefix = "/var/lib/docker/network/files"
 const defaultPrefix = "/var/lib/docker/network/files"
 
 
 func (ep *endpoint) ID() string {
 func (ep *endpoint) ID() string {
@@ -134,6 +213,52 @@ func (ep *endpoint) Network() string {
 	return ep.network.name
 	return ep.network.name
 }
 }
 
 
+// endpoint Key structure : endpoint/network-id/endpoint-id
+func (ep *endpoint) Key() []string {
+	ep.Lock()
+	n := ep.network
+	defer ep.Unlock()
+	return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)}
+}
+
+func (ep *endpoint) KeyPrefix() []string {
+	ep.Lock()
+	n := ep.network
+	defer ep.Unlock()
+	return []string{datastore.EndpointKeyPrefix, string(n.id)}
+}
+
+func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
+	// endpoint Key structure : endpoint/network-id/endpoint-id
+	// its an invalid key if the key doesnt have all the 3 key elements above
+	if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix {
+		return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
+	}
+
+	// network-id is placed at index=1. pls refer to endpoint.Key() method
+	return types.UUID(key[1]), nil
+}
+
+func (ep *endpoint) Value() []byte {
+	b, err := json.Marshal(ep)
+	if err != nil {
+		return nil
+	}
+	return b
+}
+
+func (ep *endpoint) Index() uint64 {
+	ep.Lock()
+	defer ep.Unlock()
+	return ep.dbIndex
+}
+
+func (ep *endpoint) SetIndex(index uint64) {
+	ep.Lock()
+	defer ep.Unlock()
+	ep.dbIndex = index
+}
+
 func (ep *endpoint) processOptions(options ...EndpointOption) {
 func (ep *endpoint) processOptions(options ...EndpointOption) {
 	ep.Lock()
 	ep.Lock()
 	defer ep.Unlock()
 	defer ep.Unlock()
@@ -211,7 +336,14 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 	}
 	}
 
 
 	ep.joinLeaveStart()
 	ep.joinLeaveStart()
-	defer ep.joinLeaveEnd()
+	defer func() {
+		ep.joinLeaveEnd()
+		if err != nil {
+			if e := ep.Leave(containerID, options...); e != nil {
+				log.Warnf("couldnt leave endpoint : %v", ep.name, err)
+			}
+		}
+	}()
 
 
 	ep.Lock()
 	ep.Lock()
 	if ep.container != nil {
 	if ep.container != nil {
@@ -236,11 +368,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 
 
 	ep.Unlock()
 	ep.Unlock()
 	defer func() {
 	defer func() {
-		ep.Lock()
 		if err != nil {
 		if err != nil {
+			ep.Lock()
 			ep.container = nil
 			ep.container = nil
+			ep.Unlock()
 		}
 		}
-		ep.Unlock()
 	}()
 	}()
 
 
 	network.Lock()
 	network.Lock()
@@ -286,8 +418,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 		}
 		}
 	}()
 	}()
 
 
-	container.data.SandboxKey = sb.Key()
+	if err := network.ctrlr.updateEndpointToStore(ep); err != nil {
+		return err
+	}
 
 
+	container.data.SandboxKey = sb.Key()
 	return nil
 	return nil
 }
 }
 
 
@@ -316,7 +451,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 	container := ep.container
 	container := ep.container
 	n := ep.network
 	n := ep.network
 
 
-	if container == nil || container.id == "" ||
+	if container == nil || container.id == "" || container.data.SandboxKey == "" ||
 		containerID == "" || container.id != containerID {
 		containerID == "" || container.id != containerID {
 		if container == nil {
 		if container == nil {
 			err = ErrNoContainer{}
 			err = ErrNoContainer{}
@@ -335,6 +470,13 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 	ctrlr := n.ctrlr
 	ctrlr := n.ctrlr
 	n.Unlock()
 	n.Unlock()
 
 
+	if err := ctrlr.updateEndpointToStore(ep); err != nil {
+		ep.Lock()
+		ep.container = container
+		ep.Unlock()
+		return err
+	}
+
 	err = driver.Leave(n.id, ep.id)
 	err = driver.Leave(n.id, ep.id)
 
 
 	ctrlr.sandboxRm(container.data.SandboxKey, ep)
 	ctrlr.sandboxRm(container.data.SandboxKey, ep)
@@ -343,15 +485,58 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 }
 }
 
 
 func (ep *endpoint) Delete() error {
 func (ep *endpoint) Delete() error {
+	var err error
 	ep.Lock()
 	ep.Lock()
 	epid := ep.id
 	epid := ep.id
 	name := ep.name
 	name := ep.name
+	n := ep.network
 	if ep.container != nil {
 	if ep.container != nil {
 		ep.Unlock()
 		ep.Unlock()
 		return &ActiveContainerError{name: name, id: string(epid)}
 		return &ActiveContainerError{name: name, id: string(epid)}
 	}
 	}
+	n.Lock()
+	ctrlr := n.ctrlr
+	n.Unlock()
+	ep.Unlock()
+
+	if err = ctrlr.deleteEndpointFromStore(ep); err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			ep.SetIndex(0)
+			if e := ctrlr.updateEndpointToStore(ep); e != nil {
+				log.Warnf("failed to recreate endpoint in store %s : %v", name, err)
+			}
+		}
+	}()
+
+	// Update the endpoint count in network and update it in the datastore
+	n.DecEndpointCnt()
+	if err = ctrlr.updateNetworkToStore(n); err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			n.IncEndpointCnt()
+			if e := ctrlr.updateNetworkToStore(n); e != nil {
+				log.Warnf("failed to update network %s : %v", n.name, e)
+			}
+		}
+	}()
+
+	if err = ep.deleteEndpoint(); err != nil {
+		return err
+	}
 
 
+	return nil
+}
+
+func (ep *endpoint) deleteEndpoint() error {
+	ep.Lock()
 	n := ep.network
 	n := ep.network
+	name := ep.name
+	epid := ep.id
 	ep.Unlock()
 	ep.Unlock()
 
 
 	n.Lock()
 	n.Lock()

+ 65 - 11
libnetwork/endpoint_info.go

@@ -1,6 +1,7 @@
 package libnetwork
 package libnetwork
 
 
 import (
 import (
+	"encoding/json"
 	"net"
 	"net"
 
 
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/driverapi"
@@ -49,6 +50,59 @@ type endpointInterface struct {
 	routes    []*net.IPNet
 	routes    []*net.IPNet
 }
 }
 
 
+func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
+	epMap := make(map[string]interface{})
+	epMap["id"] = epi.id
+	epMap["mac"] = epi.mac.String()
+	epMap["addr"] = epi.addr.String()
+	epMap["addrv6"] = epi.addrv6.String()
+	epMap["srcName"] = epi.srcName
+	epMap["dstPrefix"] = epi.dstPrefix
+	var routes []string
+	for _, route := range epi.routes {
+		routes = append(routes, route.String())
+	}
+	epMap["routes"] = routes
+	return json.Marshal(epMap)
+}
+
+func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
+	var epMap map[string]interface{}
+	if err := json.Unmarshal(b, &epMap); err != nil {
+		return err
+	}
+	epi.id = int(epMap["id"].(float64))
+
+	mac, _ := net.ParseMAC(epMap["mac"].(string))
+	epi.mac = mac
+
+	_, ipnet, _ := net.ParseCIDR(epMap["addr"].(string))
+	if ipnet != nil {
+		epi.addr = *ipnet
+	}
+
+	_, ipnet, _ = net.ParseCIDR(epMap["addrv6"].(string))
+	if ipnet != nil {
+		epi.addrv6 = *ipnet
+	}
+
+	epi.srcName = epMap["srcName"].(string)
+	epi.dstPrefix = epMap["dstPrefix"].(string)
+
+	rb, _ := json.Marshal(epMap["routes"])
+	var routes []string
+	json.Unmarshal(rb, &routes)
+	epi.routes = make([]*net.IPNet, 0)
+	for _, route := range routes {
+		_, ipr, err := net.ParseCIDR(route)
+		if err == nil {
+			epi.routes = append(epi.routes, ipr)
+		}
+	}
+
+	return nil
+}
+
 type endpointJoinInfo struct {
 type endpointJoinInfo struct {
 	gw             net.IP
 	gw             net.IP
 	gw6            net.IP
 	gw6            net.IP
@@ -116,25 +170,25 @@ func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, i
 	return nil
 	return nil
 }
 }
 
 
-func (i *endpointInterface) ID() int {
-	return i.id
+func (epi *endpointInterface) ID() int {
+	return epi.id
 }
 }
 
 
-func (i *endpointInterface) MacAddress() net.HardwareAddr {
-	return types.GetMacCopy(i.mac)
+func (epi *endpointInterface) MacAddress() net.HardwareAddr {
+	return types.GetMacCopy(epi.mac)
 }
 }
 
 
-func (i *endpointInterface) Address() net.IPNet {
-	return (*types.GetIPNetCopy(&i.addr))
+func (epi *endpointInterface) Address() net.IPNet {
+	return (*types.GetIPNetCopy(&epi.addr))
 }
 }
 
 
-func (i *endpointInterface) AddressIPv6() net.IPNet {
-	return (*types.GetIPNetCopy(&i.addrv6))
+func (epi *endpointInterface) AddressIPv6() net.IPNet {
+	return (*types.GetIPNetCopy(&epi.addrv6))
 }
 }
 
 
-func (i *endpointInterface) SetNames(srcName string, dstPrefix string) error {
-	i.srcName = srcName
-	i.dstPrefix = dstPrefix
+func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
+	epi.srcName = srcName
+	epi.dstPrefix = dstPrefix
 	return nil
 	return nil
 }
 }
 
 

+ 29 - 25
libnetwork/hostdiscovery/hostdiscovery.go

@@ -24,7 +24,8 @@ import (
 	_ "github.com/docker/swarm/discovery/token"
 	_ "github.com/docker/swarm/discovery/token"
 )
 )
 
 
-const defaultHeartbeat = 10
+const defaultHeartbeat = time.Duration(10) * time.Second
+const TTLFactor = 3
 
 
 type hostDiscovery struct {
 type hostDiscovery struct {
 	discovery discovery.Discovery
 	discovery discovery.Discovery
@@ -43,17 +44,17 @@ func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback Join
 		return fmt.Errorf("discovery requires a valid configuration")
 		return fmt.Errorf("discovery requires a valid configuration")
 	}
 	}
 
 
-	hb := cfg.Heartbeat
+	hb := time.Duration(cfg.Heartbeat) * time.Second
 	if hb == 0 {
 	if hb == 0 {
 		hb = defaultHeartbeat
 		hb = defaultHeartbeat
 	}
 	}
-	d, err := discovery.New(cfg.Discovery, hb)
+	d, err := discovery.New(cfg.Discovery, hb, TTLFactor*hb)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	if ip := net.ParseIP(cfg.Address); ip == nil {
 	if ip := net.ParseIP(cfg.Address); ip == nil {
-		return errors.New("Address config should be either ipv4 or ipv6 address")
+		return errors.New("address config should be either ipv4 or ipv6 address")
 	}
 	}
 
 
 	if err := d.Register(cfg.Address + ":0"); err != nil {
 	if err := d.Register(cfg.Address + ":0"); err != nil {
@@ -64,14 +65,25 @@ func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback Join
 	h.discovery = d
 	h.discovery = d
 	h.Unlock()
 	h.Unlock()
 
 
-	go d.Watch(func(entries []*discovery.Entry) {
-		h.processCallback(entries, joinCallback, leaveCallback)
-	})
-
-	go sustainHeartbeat(d, hb, cfg, h.stopChan)
+	discoveryCh, errCh := d.Watch(h.stopChan)
+	go h.monitorDiscovery(discoveryCh, errCh, joinCallback, leaveCallback)
+	go h.sustainHeartbeat(d, hb, cfg)
 	return nil
 	return nil
 }
 }
 
 
+func (h *hostDiscovery) monitorDiscovery(ch <-chan discovery.Entries, errCh <-chan error, joinCallback JoinCallback, leaveCallback LeaveCallback) {
+	for {
+		select {
+		case entries := <-ch:
+			h.processCallback(entries, joinCallback, leaveCallback)
+		case err := <-errCh:
+			log.Errorf("discovery error: %v", err)
+		case <-h.stopChan:
+			return
+		}
+	}
+}
+
 func (h *hostDiscovery) StopDiscovery() error {
 func (h *hostDiscovery) StopDiscovery() error {
 	h.Lock()
 	h.Lock()
 	stopChan := h.stopChan
 	stopChan := h.stopChan
@@ -82,12 +94,12 @@ func (h *hostDiscovery) StopDiscovery() error {
 	return nil
 	return nil
 }
 }
 
 
-func sustainHeartbeat(d discovery.Discovery, hb uint64, config *config.ClusterCfg, stopChan chan struct{}) {
+func (h *hostDiscovery) sustainHeartbeat(d discovery.Discovery, hb time.Duration, config *config.ClusterCfg) {
 	for {
 	for {
 		select {
 		select {
-		case <-stopChan:
+		case <-h.stopChan:
 			return
 			return
-		case <-time.After(time.Duration(hb) * time.Second):
+		case <-time.After(hb):
 			if err := d.Register(config.Address + ":0"); err != nil {
 			if err := d.Register(config.Address + ":0"); err != nil {
 				log.Warn(err)
 				log.Warn(err)
 			}
 			}
@@ -95,7 +107,7 @@ func sustainHeartbeat(d discovery.Discovery, hb uint64, config *config.ClusterCf
 	}
 	}
 }
 }
 
 
-func (h *hostDiscovery) processCallback(entries []*discovery.Entry, joinCallback JoinCallback, leaveCallback LeaveCallback) {
+func (h *hostDiscovery) processCallback(entries discovery.Entries, joinCallback JoinCallback, leaveCallback LeaveCallback) {
 	updated := hosts(entries)
 	updated := hosts(entries)
 	h.Lock()
 	h.Lock()
 	existing := h.nodes
 	existing := h.nodes
@@ -125,23 +137,15 @@ func diff(existing mapset.Set, updated mapset.Set) (added []net.IP, removed []ne
 
 
 func (h *hostDiscovery) Fetch() ([]net.IP, error) {
 func (h *hostDiscovery) Fetch() ([]net.IP, error) {
 	h.Lock()
 	h.Lock()
-	hd := h.discovery
-	h.Unlock()
-	if hd == nil {
-		return nil, errors.New("No Active Discovery")
-	}
-	entries, err := hd.Fetch()
-	if err != nil {
-		return nil, err
-	}
+	defer h.Unlock()
 	ips := []net.IP{}
 	ips := []net.IP{}
-	for _, entry := range entries {
-		ips = append(ips, net.ParseIP(entry.Host))
+	for _, ipstr := range h.nodes.ToSlice() {
+		ips = append(ips, net.ParseIP(ipstr.(string)))
 	}
 	}
 	return ips, nil
 	return ips, nil
 }
 }
 
 
-func hosts(entries []*discovery.Entry) mapset.Set {
+func hosts(entries discovery.Entries) mapset.Set {
 	hosts := mapset.NewSet()
 	hosts := mapset.NewSet()
 	for _, entry := range entries {
 	for _, entry := range entries {
 		hosts.Add(entry.Host)
 		hosts.Add(entry.Host)

+ 2 - 2
libnetwork/hostdiscovery/hostdiscovery_test.go

@@ -15,7 +15,7 @@ import (
 )
 )
 
 
 func TestDiscovery(t *testing.T) {
 func TestDiscovery(t *testing.T) {
-	_, err := net.Dial("tcp", "discovery-stage.hub.docker.com:80")
+	_, err := net.DialTimeout("tcp", "discovery-stage.hub.docker.com:80", 10*time.Second)
 	if err != nil {
 	if err != nil {
 		t.Skip("Skipping Discovery test which need connectivity to discovery-stage.hub.docker.com")
 		t.Skip("Skipping Discovery test which need connectivity to discovery-stage.hub.docker.com")
 	}
 	}
@@ -52,7 +52,7 @@ func TestDiscovery(t *testing.T) {
 }
 }
 
 
 func TestBadDiscovery(t *testing.T) {
 func TestBadDiscovery(t *testing.T) {
-	_, err := net.Dial("tcp", "discovery-stage.hub.docker.com:80")
+	_, err := net.DialTimeout("tcp", "discovery-stage.hub.docker.com:80", 10*time.Second)
 	if err != nil {
 	if err != nil {
 		t.Skip("Skipping Discovery test which need connectivity to discovery-stage.hub.docker.com")
 		t.Skip("Skipping Discovery test which need connectivity to discovery-stage.hub.docker.com")
 	}
 	}

+ 2 - 2
libnetwork/libnetwork_internal_test.go

@@ -13,14 +13,14 @@ func TestDriverRegistration(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	err = c.(*controller).RegisterDriver(bridgeNetType, nil)
+	err = c.(*controller).RegisterDriver(bridgeNetType, nil, driverapi.Capability{})
 	if err == nil {
 	if err == nil {
 		t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType)
 		t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType)
 	}
 	}
 	if _, ok := err.(driverapi.ErrActiveRegistration); !ok {
 	if _, ok := err.(driverapi.ErrActiveRegistration); !ok {
 		t.Fatalf("Failed for unexpected reason: %v", err)
 		t.Fatalf("Failed for unexpected reason: %v", err)
 	}
 	}
-	err = c.(*controller).RegisterDriver("test-dummy", nil)
+	err = c.(*controller).RegisterDriver("test-dummy", nil, driverapi.Capability{})
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Test failed with an error %v", err)
 		t.Fatalf("Test failed with an error %v", err)
 	}
 	}

+ 127 - 25
libnetwork/network.go

@@ -2,7 +2,6 @@ package libnetwork
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
-	"strings"
 	"sync"
 	"sync"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
@@ -12,6 +11,7 @@ import (
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
+	"github.com/docker/swarm/pkg/store"
 )
 )
 
 
 // A Network represents a logical connectivity zone that containers may
 // A Network represents a logical connectivity zone that containers may
@@ -58,6 +58,7 @@ type network struct {
 	id          types.UUID
 	id          types.UUID
 	driver      driverapi.Driver
 	driver      driverapi.Driver
 	enableIPv6  bool
 	enableIPv6  bool
+	endpointCnt uint64
 	endpoints   endpointTable
 	endpoints   endpointTable
 	generic     options.Generic
 	generic     options.Generic
 	dbIndex     uint64
 	dbIndex     uint64
@@ -90,10 +91,18 @@ func (n *network) Type() string {
 }
 }
 
 
 func (n *network) Key() []string {
 func (n *network) Key() []string {
+	n.Lock()
+	defer n.Unlock()
 	return []string{datastore.NetworkKeyPrefix, string(n.id)}
 	return []string{datastore.NetworkKeyPrefix, string(n.id)}
 }
 }
 
 
+func (n *network) KeyPrefix() []string {
+	return []string{datastore.NetworkKeyPrefix}
+}
+
 func (n *network) Value() []byte {
 func (n *network) Value() []byte {
+	n.Lock()
+	defer n.Unlock()
 	b, err := json.Marshal(n)
 	b, err := json.Marshal(n)
 	if err != nil {
 	if err != nil {
 		return nil
 		return nil
@@ -102,11 +111,33 @@ func (n *network) Value() []byte {
 }
 }
 
 
 func (n *network) Index() uint64 {
 func (n *network) Index() uint64 {
+	n.Lock()
+	defer n.Unlock()
 	return n.dbIndex
 	return n.dbIndex
 }
 }
 
 
 func (n *network) SetIndex(index uint64) {
 func (n *network) SetIndex(index uint64) {
+	n.Lock()
 	n.dbIndex = index
 	n.dbIndex = index
+	n.Unlock()
+}
+
+func (n *network) EndpointCnt() uint64 {
+	n.Lock()
+	defer n.Unlock()
+	return n.endpointCnt
+}
+
+func (n *network) IncEndpointCnt() {
+	n.Lock()
+	n.endpointCnt++
+	n.Unlock()
+}
+
+func (n *network) DecEndpointCnt() {
+	n.Lock()
+	n.endpointCnt--
+	n.Unlock()
 }
 }
 
 
 // TODO : Can be made much more generic with the help of reflection (but has some golang limitations)
 // TODO : Can be made much more generic with the help of reflection (but has some golang limitations)
@@ -115,6 +146,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
 	netMap["name"] = n.name
 	netMap["name"] = n.name
 	netMap["id"] = string(n.id)
 	netMap["id"] = string(n.id)
 	netMap["networkType"] = n.networkType
 	netMap["networkType"] = n.networkType
+	netMap["endpointCnt"] = n.endpointCnt
 	netMap["enableIPv6"] = n.enableIPv6
 	netMap["enableIPv6"] = n.enableIPv6
 	netMap["generic"] = n.generic
 	netMap["generic"] = n.generic
 	return json.Marshal(netMap)
 	return json.Marshal(netMap)
@@ -129,6 +161,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
 	n.name = netMap["name"].(string)
 	n.name = netMap["name"].(string)
 	n.id = types.UUID(netMap["id"].(string))
 	n.id = types.UUID(netMap["id"].(string))
 	n.networkType = netMap["networkType"].(string)
 	n.networkType = netMap["networkType"].(string)
+	n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
 	n.enableIPv6 = netMap["enableIPv6"].(bool)
 	n.enableIPv6 = netMap["enableIPv6"].(bool)
 	if netMap["generic"] != nil {
 	if netMap["generic"] != nil {
 		n.generic = netMap["generic"].(map[string]interface{})
 		n.generic = netMap["generic"].(map[string]interface{})
@@ -161,24 +194,51 @@ func (n *network) processOptions(options ...NetworkOption) {
 }
 }
 
 
 func (n *network) Delete() error {
 func (n *network) Delete() error {
-	n.ctrlr.Lock()
-	_, ok := n.ctrlr.networks[n.id]
+	var err error
+
+	n.Lock()
+	ctrlr := n.ctrlr
+	n.Unlock()
+
+	ctrlr.Lock()
+	_, ok := ctrlr.networks[n.id]
+	ctrlr.Unlock()
+
 	if !ok {
 	if !ok {
-		n.ctrlr.Unlock()
 		return &UnknownNetworkError{name: n.name, id: string(n.id)}
 		return &UnknownNetworkError{name: n.name, id: string(n.id)}
 	}
 	}
 
 
-	n.Lock()
-	numEps := len(n.endpoints)
-	n.Unlock()
+	numEps := n.EndpointCnt()
 	if numEps != 0 {
 	if numEps != 0 {
-		n.ctrlr.Unlock()
 		return &ActiveEndpointsError{name: n.name, id: string(n.id)}
 		return &ActiveEndpointsError{name: n.name, id: string(n.id)}
 	}
 	}
 
 
-	delete(n.ctrlr.networks, n.id)
+	// deleteNetworkFromStore performs an atomic delete operation and the network.endpointCnt field will help
+	// prevent any possible race between endpoint join and network delete
+	if err = ctrlr.deleteNetworkFromStore(n); err != nil {
+		if err == store.ErrKeyModified {
+			return types.InternalErrorf("operation in progress. delete failed for network %s. Please try again.")
+		}
+		return err
+	}
+
+	if err = n.deleteNetwork(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (n *network) deleteNetwork() error {
+	n.Lock()
+	id := n.id
+	d := n.driver
+	n.ctrlr.Lock()
+	delete(n.ctrlr.networks, id)
 	n.ctrlr.Unlock()
 	n.ctrlr.Unlock()
-	if err := n.driver.DeleteNetwork(n.id); err != nil {
+	n.Unlock()
+
+	if err := d.DeleteNetwork(n.id); err != nil {
 		// Forbidden Errors should be honored
 		// Forbidden Errors should be honored
 		if _, ok := err.(types.ForbiddenError); ok {
 		if _, ok := err.(types.ForbiddenError); ok {
 			n.ctrlr.Lock()
 			n.ctrlr.Lock()
@@ -191,12 +251,35 @@ func (n *network) Delete() error {
 	return nil
 	return nil
 }
 }
 
 
+func (n *network) addEndpoint(ep *endpoint) error {
+	var err error
+	n.Lock()
+	n.endpoints[ep.id] = ep
+	d := n.driver
+	n.Unlock()
+
+	defer func() {
+		if err != nil {
+			n.Lock()
+			delete(n.endpoints, ep.id)
+			n.Unlock()
+		}
+	}()
+
+	err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
+	var err error
 	if name == "" {
 	if name == "" {
 		return nil, ErrInvalidName(name)
 		return nil, ErrInvalidName(name)
 	}
 	}
 
 
-	if _, err := n.EndpointByName(name); err == nil {
+	if _, err = n.EndpointByName(name); err == nil {
 		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
 		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
 	}
 	}
 
 
@@ -205,15 +288,37 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
 	ep.network = n
 	ep.network = n
 	ep.processOptions(options...)
 	ep.processOptions(options...)
 
 
-	d := n.driver
-	err := d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
-	if err != nil {
+	n.Lock()
+	ctrlr := n.ctrlr
+	n.Unlock()
+
+	n.IncEndpointCnt()
+	if err = ctrlr.updateNetworkToStore(n); err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			n.DecEndpointCnt()
+			if err = ctrlr.updateNetworkToStore(n); err != nil {
+				log.Warnf("endpoint count cleanup failed when updating network for %s : %v", name, err)
+			}
+		}
+	}()
+	if err = n.addEndpoint(ep); err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			if e := ep.Delete(); ep != nil {
+				log.Warnf("cleaning up endpoint failed %s : %v", name, e)
+			}
+		}
+	}()
+
+	if err = ctrlr.updateEndpointToStore(ep); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	n.Lock()
-	n.endpoints[ep.id] = ep
-	n.Unlock()
 	return ep, nil
 	return ep, nil
 }
 }
 
 
@@ -271,12 +376,9 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
 	return nil, ErrNoSuchEndpoint(id)
 	return nil, ErrNoSuchEndpoint(id)
 }
 }
 
 
-func isReservedNetwork(name string) bool {
-	reserved := []string{"bridge", "none", "host"}
-	for _, r := range reserved {
-		if strings.EqualFold(r, name) {
-			return true
-		}
-	}
-	return false
+func (n *network) isGlobalScoped() (bool, error) {
+	n.Lock()
+	c := n.ctrlr
+	n.Unlock()
+	return c.isDriverGlobalScoped(n.networkType)
 }
 }

+ 292 - 0
libnetwork/store.go

@@ -0,0 +1,292 @@
+package libnetwork
+
+import (
+	"encoding/json"
+	"fmt"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/types"
+)
+
+func (c *controller) initDataStore() error {
+	c.Lock()
+	cfg := c.cfg
+	c.Unlock()
+	if cfg == nil {
+		return fmt.Errorf("datastore initialization requires a valid configuration")
+	}
+
+	store, err := datastore.NewDataStore(&cfg.Datastore)
+	if err != nil {
+		return err
+	}
+	c.Lock()
+	c.store = store
+	c.Unlock()
+	return c.watchStore()
+}
+
+func (c *controller) newNetworkFromStore(n *network) error {
+	n.Lock()
+	n.ctrlr = c
+	n.endpoints = endpointTable{}
+	n.Unlock()
+
+	return c.addNetwork(n)
+}
+
+func (c *controller) updateNetworkToStore(n *network) error {
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. Network %s is not added to the store", n.Name())
+		return nil
+	}
+
+	return cs.PutObjectAtomic(n)
+}
+
+func (c *controller) deleteNetworkFromStore(n *network) error {
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. Network %s is not deleted from datastore", n.Name())
+		return nil
+	}
+
+	if err := cs.DeleteObjectAtomic(n); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *controller) getNetworkFromStore(nid types.UUID) (*network, error) {
+	n := network{id: nid}
+	if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil {
+		return nil, err
+	}
+	return &n, nil
+}
+
+func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
+	ep.Lock()
+	n := ep.network
+	id := ep.id
+	ep.Unlock()
+	if n == nil {
+		// Possibly the watch event for the network has not shown up yet
+		// Try to get network from the store
+		nid, err := networkIDFromEndpointKey(key, ep)
+		if err != nil {
+			return err
+		}
+		n, err = c.getNetworkFromStore(nid)
+		if err != nil {
+			return err
+		}
+		if err := c.newNetworkFromStore(n); err != nil {
+			return err
+		}
+		n = c.networks[nid]
+	}
+
+	_, err := n.EndpointByID(string(id))
+	if err != nil {
+		if _, ok := err.(ErrNoSuchEndpoint); ok {
+			return n.addEndpoint(ep)
+		}
+	}
+	return err
+}
+
+func (c *controller) updateEndpointToStore(ep *endpoint) error {
+	ep.Lock()
+	n := ep.network
+	name := ep.name
+	ep.Unlock()
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. endpoint %s is not added to the store", name)
+		return nil
+	}
+
+	return cs.PutObjectAtomic(ep)
+}
+
+func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) {
+	ep := endpoint{id: eid}
+	if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil {
+		return nil, err
+	}
+	return &ep, nil
+}
+
+func (c *controller) deleteEndpointFromStore(ep *endpoint) error {
+	ep.Lock()
+	n := ep.network
+	ep.Unlock()
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. endpoint %s is not deleted from datastore", ep.Name())
+		return nil
+	}
+
+	if err := cs.DeleteObjectAtomic(ep); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *controller) watchStore() error {
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+
+	nwPairs, err := cs.KVStore().WatchTree(datastore.Key(datastore.NetworkKeyPrefix), nil)
+	if err != nil {
+		return err
+	}
+	epPairs, err := cs.KVStore().WatchTree(datastore.Key(datastore.EndpointKeyPrefix), nil)
+	if err != nil {
+		return err
+	}
+	go func() {
+		for {
+			select {
+			case nws := <-nwPairs:
+				for _, kve := range nws {
+					var n network
+					err := json.Unmarshal(kve.Value, &n)
+					if err != nil {
+						log.Error(err)
+						continue
+					}
+					n.dbIndex = kve.LastIndex
+					c.Lock()
+					existing, ok := c.networks[n.id]
+					c.Unlock()
+					if ok {
+						existing.Lock()
+						// Skip existing network update
+						if existing.dbIndex != n.dbIndex {
+							existing.dbIndex = n.dbIndex
+							existing.endpointCnt = n.endpointCnt
+						}
+						existing.Unlock()
+						continue
+					}
+
+					if err = c.newNetworkFromStore(&n); err != nil {
+						log.Error(err)
+					}
+				}
+			case eps := <-epPairs:
+				for _, epe := range eps {
+					var ep endpoint
+					err := json.Unmarshal(epe.Value, &ep)
+					if err != nil {
+						log.Error(err)
+						continue
+					}
+					ep.dbIndex = epe.LastIndex
+					n, err := c.networkFromEndpointKey(epe.Key, &ep)
+					if err != nil {
+						if _, ok := err.(ErrNoSuchNetwork); !ok {
+							log.Error(err)
+							continue
+						}
+					}
+					if n != nil {
+						ep.network = n.(*network)
+					}
+					if c.processEndpointUpdate(&ep) {
+						err = c.newEndpointFromStore(epe.Key, &ep)
+						if err != nil {
+							log.Error(err)
+						}
+					}
+				}
+			}
+		}
+	}()
+	return nil
+}
+
+func (c *controller) networkFromEndpointKey(key string, ep *endpoint) (Network, error) {
+	nid, err := networkIDFromEndpointKey(key, ep)
+	if err != nil {
+		return nil, err
+	}
+	return c.NetworkByID(string(nid))
+}
+
+func networkIDFromEndpointKey(key string, ep *endpoint) (types.UUID, error) {
+	eKey, err := datastore.ParseKey(key)
+	if err != nil {
+		return types.UUID(""), err
+	}
+	return ep.networkIDFromKey(eKey)
+}
+
+func (c *controller) processEndpointUpdate(ep *endpoint) bool {
+	nw := ep.network
+	if nw == nil {
+		return true
+	}
+	nw.Lock()
+	id := nw.id
+	nw.Unlock()
+
+	c.Lock()
+	n, ok := c.networks[id]
+	c.Unlock()
+	if !ok {
+		return true
+	}
+	existing, _ := n.EndpointByID(string(ep.id))
+	if existing == nil {
+		return true
+	}
+
+	ee := existing.(*endpoint)
+	ee.Lock()
+	if ee.dbIndex != ep.dbIndex {
+		ee.dbIndex = ep.dbIndex
+		if ee.container != nil && ep.container != nil {
+			// we care only about the container id
+			ee.container.id = ep.container.id
+		} else {
+			// we still care only about the container id, but this is a short-cut to communicate join or leave operation
+			ee.container = ep.container
+		}
+	}
+	ee.Unlock()
+
+	return false
+}